{"content":{"title":"damocles 代码解析 笔记","body":"1. `pkg/objstore`包主要是提供一个统一的接口，而实现则是由`pkg/kvstore`包来完成。\r\n2. `venus-worker`主动向`venus-sector-manager`的接口进行连接。\r\n\r\n\r\n# 问题\r\n1. VSM主要功能是什么？\r\n2. vsm如何与worker进行通信，通信协议是什么？\r\n3. worker会和vsm以外的链服务或者market通信吗？\r\n4. vsm如何和node，market建立连接？\r\n5. vsm和node需要进行哪些类型的通信？时候进行通信，为什么通信？\r\n6. vsm和market需要进行哪些类型的通信？时候进行通信，为什么通信？\r\n\r\n# 答案\r\n\r\n\r\n\r\n#  venus-sector-manager\r\n1. `vsm/core`包定义了对外的接口格式。\r\n2. `vsm/modules/poster`包主要负责定时产生windowPost proof，然后通过venus.messager服务把proof msg发送给node。\r\n3. `venus-worker`服务通过api调用`vsm/modules/sealer`包的`SubmitPreCommit()`方法，进行preCommit消息的提交。而`vsm/modeuls/sealer`包会调用`vsm/modules/impl/commitmgr`包里实现具体如何向node节点进行提交信息。\r\n4. `vsm/miner`包主要负责通过`gateway`和`venus-miner`进行建立长链接。`venus-miner`会通过长链接主动向`vsm/miner`包发送`ComputeProof`命令，让其计算winningPost。`vsm/modules/miner`会通过`vsm/modules/impl/prover`包来实现具体的计算任务。`vsm/moduels/impl/prover`包会直接通过ffi直接调用rust库的函数进行计算。也可以通过`vsm/moduels/impl/prover/ext`包来调用`vsm/pkg/extproc`包来使用外部执行器来进行proof产生。\r\n\r\n\r\n# venus-worker\r\n  1. `src/sealing/worker/task/planner/sealer.rs`文件的`Planner`类方法`exec()`会执行状态机状态转换，大部分`sealer.rs`文件的方法都会调用`common.rs`文件中的方法，`common.rs`文件中的函数会`task`的具体执行的`processor`定义在`vc-processors/src/builtin/processors.rs`文件中，这个文件会直接调用官方定义的`fil-proofs`包来实现具体的过程。\r\n\r\n2. 整个worker主要设计思路是：根据config文件设置的`sealingthread`的数量，开启多少个sealingthread线程，线程里面会根据`sealingthread`的配置参数build出一个task，然后调用`exec`方法执行task，执行中最主要的调用方法是`task.handle()`方法，这个方法会调用`planner.exec()`方法。planner是一个trait，`sealer,snapup,unseal,rebuild`四种类型的planner分别是实现了planner trait的`plan(),exec()`两个方法。调用planner.exec()方法后，方法内部会根据当前的state状态，调用不同的方法进行处理，就是一个状态机。代码：\r\n```rust\r\nmatch state {\r\n            State::Empty => inner.empty(),\r\n\r\n            State::Allocated => inner.add_piece(),\r\n\r\n            State::PieceAdded => inner.build_tree_d(),\r\n\r\n            State::TreeDBuilt => inner.snap_encode(),\r\n            .....\r\n            .....\r\n            }\r\n```\r\n很多方法都会共用`common.rs`文件中的方法。但这个`common.rs`文件，也不是最后的执行者，common.rs的很多方法都会调用processor文件的内容，processor其实就是每次阶段执行的具体方法。当然咯，后面最主要调用的是`fil-proofs`包的内容才能实现。\r\n\r\n`watchdog::start_module()`方法会生成一个线程，在线程内部会调用module的run()方法。SealingThread实现了Module trait，sealingthread module 的run方法会有一个loop循环，从而sealingthread线程会一直存在。完成一个封装任务以后，会开启新一轮的封装任务。\r\n每一轮封装任务的开始状态都是empty状态，`handle_empty()`方法会进行状态切换，这个方法里面会调用damocles-manager的`AllocateSector`rpc接口，获取下一个要封装的sector信息（主要是sectornumber），然后开始新一轮的封装任务。\r\n`damocles-manager`的`AllocateSector`接口是会把sectornumber直接增加，然后返回给worker的，收到sector信息后，如果worker停止封装的话，manager也不会知道，从而worker再次调用`AllocateSector`rpc接口的话，sectornumer还是会直接增加的（manager可以批量一次申请好几sector封装任务的，所以不一定是加1，也可以加N，N自己定义），从而导致sectornumber的浪费，因为上一个sectornumber因为worker的异常，而没有真正的封装。\r\n\r\n```rust\r\n    pub fn start_module(&mut self, m: impl 'static + Module) {\r\n .........\r\n        let hdl = thread::spawn(move || {  //生成一个线程\r\n........\r\n            let _guard = span.enter();\r\n            info!(\"start\");\r\n            let res = m.run(ctx);  // SealingThread module运行run方法\r\n            info!(\"stop\");\r\n            let _ = res_tx.send(res);\r\n        });\r\n\r\n        self.modules.push((id, should_wait, hdl, res_rx));\r\n    }\r\n\r\n```\r\n\r\n```rust\r\n\r\n    fn run(&mut self, ctx: Ctx) -> Result<()> {\r\n       .......\r\n\r\n        'SEAL_LOOP: loop { // 不停的循环\r\n        ......\r\n\r\n            if let Err(failure) = self.seal_one(&ctx, resume_state.take()) { // 开启一个sector的封装\r\n                ......\r\n                .......\r\n            }\r\n            ........\r\n       }\r\n       \r\n       \r\n     fn seal_one(&mut self, ctx: &Ctx, state: Option<State>) -> Result<(), Failure> {\r\n            let task = Task::build(ctx, &self.ctrl_ctx, &mut self.config, &mut self.store)?;\r\n            task.exec(state) //开始执行任务\r\n    }\r\n```\r\n\r\n```rust\r\n// task/mod.rs\r\npub fn exec(mut self, state: Option<State>) -> Result<(), Failure> {\r\n        ......\r\n        loop { // 循环完成一个个状态切换\r\n        ......\r\n        .....\r\n         let handle_res = self.handle(event.take());  // handle方法处理每个状态\r\n        ......\r\n        .....\r\n          if let Err(rerr) = self.report_state( // 每完成一个状态切换，就调用mananger的rpc，汇报一下自己的state给mananger。\r\n                SectorStateChange {\r\n                    prev: prev.as_str().to_owned(),\r\n                    next: self.sector.state.as_str().to_owned(),\r\n                    event: format!(\"{:?}\", event),\r\n                },\r\n                fail,\r\n            ) {\r\n                error!(\"report state failed: {:?}\", rerr);\r\n            };\r\n        }\r\n```\r\n\r\n```\r\n fn handle(&mut self, event: Option<Event>) -> Result<Option<Event>, Failure> {\r\n       ,,,,,,\r\n       let planner = get_planner(self.sector.plan.as_deref()).perm()?; // 共有sealer，snapup，rebuild，unseal四个planner\r\n       ,,,,,,\r\n       ,,,,,,\r\n      planner.exec(self) // planner执行具体的封装流程\r\n }\r\n```\r\n\r\n```\r\n    // task/planner/sealer.rs\r\n    fn exec(&self, task: &mut Task<'_>) -> Result<Option<Event>, Failure> {\r\n        let state = task.sector.state;\r\n        let inner = Sealer { task };\r\n        //根据不同的状态，调用不同的状态处理方法；不同的planner的状态流程是不一样的。\r\n        match state {\r\n            State::Empty => inner.handle_empty(),\r\n\r\n            State::Allocated => inner.handle_allocated(),\r\n\r\n            State::DealsAcquired => inner.handle_deals_acquired(),\r\n\r\n            State::PieceAdded => inner.handle_piece_added(),\r\n\r\n            State::TreeDBuilt => inner.handle_tree_d_built(),\r\n\r\n            State::TicketAssigned => inner.handle_ticket_assigned(),\r\n\r\n            State::PC1Done => inner.handle_pc1_done(),\r\n\r\n            State::PC2Done => inner.handle_pc2_done(),\r\n\r\n            State::PCSubmitted => inner.handle_pc_submitted(),\r\n\r\n            State::PCLanded => inner.handle_pc_landed(),\r\n\r\n            State::Persisted => inner.handle_persisted(),\r\n\r\n            State::PersistanceSubmitted => inner.handle_persistance_submitted(),\r\n\r\n            State::SeedAssigned => inner.handle_seed_assigned(),\r\n\r\n            State::C1Done => inner.handle_c1_done(),\r\n\r\n            State::C2Done => inner.handle_c2_done(),\r\n\r\n            State::ProofSubmitted => inner.handle_proof_submitted(),\r\n\r\n            State::Finished => return Ok(None),\r\n\r\n            State::Aborted => {\r\n                return Err(TaskAborted.into());\r\n            }\r\n\r\n            other => return Err(anyhow!(\"unexpected state {:?} in sealer planner\", other).abort()),\r\n        }\r\n        .map(From::from)\r\n    }\r\n```\r\n\r\n从以上我们可以总结得出几个概念：\r\n1. module\r\n2. task\r\n3. planner"},"author":{"user":"https://learnblockchain.cn/people/808","address":null},"history":"QmQ384Vo38ABmNsUtbLRc5RoaP3c64tRPBSbKMwBmQ7ZTX","timestamp":1689935990,"version":1}