├── AC ├── AC.md └── admission-control.svg ├── Execution ├── Execution.md ├── Executor │ ├── block_tree.md │ └── blocks.md └── execution_service&client.md ├── LICENSE ├── Language ├── Language.md ├── VM │ ├── VM.md │ └── VM_runtime │ │ ├── VM_runtime.md │ │ ├── process_txn │ │ └── process_txn.md │ │ └── txn_executor │ │ └── txn_executors.md └── libra-move-a-language-with-programmable-resources.pdf ├── Network └── Network.md ├── README.md ├── VM_validator └── VM_validator.md ├── client ├── client.md ├── client_proxy.md └── grpc_client.md ├── consensus ├── SMR │ ├── EventProcessor.md │ ├── Pacemaker.md │ ├── SMR.md │ ├── block_store.md │ ├── safety_rules.md │ └── sync_manager.md ├── State_Computer.md ├── Txn_manager.md ├── consensus.md └── libra-consensus-state-machine-replication-in-the-libra-blockchain.pdf ├── mempool ├── mempool.md ├── mempool_core_mempool.md ├── mempool_service.md ├── runtime.md └── shared_mempool.md └── storage ├── Event_store.md ├── Libradb.md ├── accumulator.md ├── storage.md └── storage_service&client.md /AC/AC.md: -------------------------------------------------------------------------------- 1 | # Admission Control 2 | 3 | ## 目录 4 | 5 | ``` 6 | ├── README.md 7 | ├── admission_control_proto 8 | │   └── src 9 | │   └── proto # Protobuf definition files 10 | └── admission_control_service 11 | └── src # gRPC service source files 12 | ├── admission_control_node.rs # Wrapper to run AC in a separate thread 13 | ├── admission_control_service.rs # gRPC service and main logic 14 | ├── main.rs # Main entry to run AC as a binary 15 | └── unit_tests # Testsv 16 | ``` 17 | 18 | ## 功能: 19 | 20 | * AC是validator与外界交互的唯一接口 21 | * 在收到client发来的查询状态、同步到最新ledger等请求时,AC会将请求直接转发给validator的storage模块,而不是直接处理这些请求。 22 | * 在收到submit transaction请求时,先验证这一请求的合法性(包括数字签名,账户余额等),如果不合法,返回错误(这些验证一部分是在AC进行,另一部分则通过VM进行);如果合法,则将transaction提交到validator的mempool模块内存储到池中等待组合成区块 23 | 24 | ## 与其他模块的交互: 25 | 26 | **Mempool ,Storage,VM_validator** 27 | 28 | 前两者是通过调用gRPC服务的形式,VM_validator 是通过直接生成一个validator实例来实现的 29 | 30 | 31 | 32 | ## 代码实现: 33 | 34 | ### admission_control_service.rs: 35 | 36 | #### 定义: 37 | 38 | ```rust 39 | //从这个定义可以看到ACservice实际上是通过与其他模块的交互实现的,其包括两个grpc client和一个VM_validator实例 40 | pub struct AdmissionControlService { 41 | /// gRPC client connecting Mempool. 42 | mempool_client: Arc, 43 | /// gRPC client to send read requests to Storage. 44 | storage_read_client: Arc, 45 | /// VM validator instance to validate transactions sent from wallets. 46 | vm_validator: Arc, 47 | /// Flag indicating whether we need to check mempool before validation, drop txn if check 48 | /// fails. 49 | need_to_check_mempool_before_validation: bool, 50 | } 51 | ``` 52 | 53 | ### 下面是对于这个struct的接口实现: 54 | 55 | #### submit_transaction_inner: 56 | 57 | ```rust 58 | /// Validate transaction signature, then via VM, and add it to Mempool if it passes VM check. 59 | 60 | pub(crate) fn submit_transaction_inner( 61 | &self, 62 | req: SubmitTransactionRequest, 63 | ) -> Result { 64 | // Drop requests first if mempool is full (validator is lagging behind) so not to consume 65 | // unnecessary resources. 66 | if !self.can_send_txn_to_mempool()? { 67 | debug!("Mempool is full"); 68 | OP_COUNTERS.inc_by("submit_txn.rejected.mempool_full", 1); 69 | let mut response = SubmitTransactionResponse::new(); 70 | let mut status = MempoolAddTransactionStatus::new(); 71 | status.set_code(MempoolIsFull); 72 | status.set_message("Mempool is full".to_string()); 73 | response.set_mempool_status(status); 74 | return Ok(response); 75 | } 76 | 77 | let signed_txn_proto = req.get_signed_txn(); 78 | //验证数字签名 79 | let signed_txn = match SignedTransaction::from_proto(signed_txn_proto.clone()) { 80 | Ok(t) => t, 81 | Err(e) => { 82 | security_log(SecurityEvent::InvalidTransactionAC) 83 | .error(&e) 84 | .data(&signed_txn_proto) 85 | .log(); 86 | let mut response = SubmitTransactionResponse::new(); 87 | response.set_ac_status( 88 | AdmissionControlStatus::Rejected("submit txn rejected".to_string()) 89 | .into_proto(), 90 | ); 91 | OP_COUNTERS.inc_by("submit_txn.rejected.invalid_txn", 1); 92 | return Ok(response); 93 | } 94 | }; 95 | 96 | 97 | let gas_cost = signed_txn.max_gas_amount(); 98 | //////用self的VM_validator实例进行进一步验证,这里面的具体逻辑会在VM_validator中仔细说 99 | let validation_status = self 100 | .vm_validator 101 | .validate_transaction(signed_txn.clone()) 102 | .wait() 103 | .map_err(|e| { 104 | security_log(SecurityEvent::InvalidTransactionAC) 105 | .error(&e) 106 | .data(&signed_txn) 107 | .log(); 108 | e 109 | })?; 110 | 111 | if let Some(validation_status) = validation_status { 112 | let mut response = SubmitTransactionResponse::new(); 113 | OP_COUNTERS.inc_by("submit_txn.vm_validation.failure", 1); 114 | debug!( 115 | "txn failed in vm validation, status: {:?}, txn: {:?}", 116 | validation_status, signed_txn 117 | ); 118 | response.set_vm_status(validation_status.into_proto()); 119 | return Ok(response); 120 | } 121 | 122 | //验证成功 123 | let sender = signed_txn.sender(); 124 | let account_state = block_on(get_account_state(self.storage_read_client.clone(), sender));/////通过self的storage grpc client来获取账户状态。 125 | let mut add_transaction_request = AddTransactionWithValidationRequest::new(); 126 | add_transaction_request.signed_txn = req.signed_txn.clone(); 127 | add_transaction_request.set_max_gas_cost(gas_cost); 128 | 129 | if let Ok((sequence_number, balance)) = account_state { 130 | add_transaction_request.set_account_balance(balance); 131 | add_transaction_request.set_latest_sequence_number(sequence_number); 132 | } 133 | 134 | self.add_txn_to_mempool(add_transaction_request)///加入到mempool 135 | } 136 | 137 | 138 | ``` 139 | 140 | #### update_to_latest_ledger_inner 141 | 142 | ```rust 143 | fn update_to_latest_ledger_inner( 144 | &self, 145 | req: UpdateToLatestLedgerRequest, 146 | ) -> Result { 147 | let rust_req = types::get_with_proof::UpdateToLatestLedgerRequest::from_proto(req)?; 148 | //问号运算符是rust的一个特性,类似错误检查的功能,如果这个部分运行错误,则整个函数直接返回ERR,没有错误就把返回值赋给rust_req 149 | ///这一部分AC部分不会有什么操作,只是单纯的当中介,转发请求和回答,具体实现是在storage和client两部分进行处理的 150 | let (response_items, ledger_info_with_sigs, validator_change_events) = self 151 | .storage_read_client 152 | .update_to_latest_ledger(rust_req.client_known_version, rust_req.requested_items)?; 153 | let rust_resp = types::get_with_proof::UpdateToLatestLedgerResponse::new( 154 | response_items, 155 | ledger_info_with_sigs, 156 | validator_change_events, 157 | );//proof 158 | Ok(rust_resp.into_proto()) 159 | } 160 | ``` 161 | 162 | #### impl 一个接口: 163 | 164 | #### submit_transaction & update_to_latest_ledger 165 | 166 | ```rust 167 | //可以看出两个函数的实现都类似包裹了一层,都调用了上面的xxx_inner函数来实现实际的功能,之后再通过grpc转发给客户端。这两个函数负责AC对client请求的接受和结果的回复 168 | 169 | impl AdmissionControl for AdmissionControlService 170 | where 171 | M: MempoolClientTrait, 172 | V: TransactionValidation, 173 | { 174 | /// Submit a transaction to the validator this AC instance connecting to. 175 | /// The specific transaction will be first validated by VM and then passed 176 | /// to Mempool for further processing. 177 | fn submit_transaction( 178 | &mut self, 179 | ctx: ::grpcio::RpcContext<'_>, 180 | req: SubmitTransactionRequest, 181 | sink: ::grpcio::UnarySink, 182 | ) { 183 | debug!("[GRPC] AdmissionControl::submit_transaction"); 184 | let _timer = SVC_COUNTERS.req(&ctx); 185 | let resp = self.submit_transaction_inner(req); 186 | provide_grpc_response(resp, ctx, sink); 187 | } 188 | 189 | /// This API is used to update the client to the latest ledger version and optionally also 190 | /// request 1..n other pieces of data. This allows for batch queries. All queries return 191 | /// proofs that a client should check to validate the data. 192 | /// Note that if a client only wishes to update to the latest LedgerInfo and receive the proof 193 | /// of this latest version, they can simply omit the requested_items (or pass an empty list). 194 | /// AC will not directly process this request but pass it to Storage instead. 195 | fn update_to_latest_ledger( 196 | &mut self, 197 | ctx: grpcio::RpcContext<'_>, 198 | req: types::proto::get_with_proof::UpdateToLatestLedgerRequest, 199 | sink: grpcio::UnarySink, 200 | ) { 201 | debug!("[GRPC] AdmissionControl::update_to_latest_ledger"); 202 | let _timer = SVC_COUNTERS.req(&ctx); 203 | let resp = self.update_to_latest_ledger_inner(req); 204 | provide_grpc_response(resp, ctx, sink); 205 | } 206 | } 207 | 208 | ``` 209 | 210 | ## 总结: 211 | 212 | **看完AC部分的基本代码后,我们已经知道了client submit的transaction是怎样通过验证并加入到validator的mempool中等待组装成块的,也知道了client的query操作是如何与validator的storage建立关系的** 213 | 214 | 215 | 216 | -------------------------------------------------------------------------------- /AC/admission-control.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | admission-control 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Storage 16 | 17 | 18 | 19 | 20 | 21 | Mempool 22 | 23 | 24 | 25 | 26 | 27 | Virtual 28 | Machine 29 | 30 | 31 | 32 | 33 | 34 | Client 35 | 36 | 37 | 38 | 39 | 40 | Admission 41 | Control 42 | 43 | 44 | 45 | AC. 46 | 1 47 | 48 | 49 | AC. 50 | 2 51 | 52 | 53 | AC. 54 | 3 55 | 56 | 57 | AC. 58 | 4 59 | 60 | 61 | Admission Control 62 | 63 | 64 | -------------------------------------------------------------------------------- /Execution/Execution.md: -------------------------------------------------------------------------------- 1 | # Execution 2 | 3 | **Execution是Libra中的一个重要模块,负责接收有一定顺序的交易,调用MoveVM计算每一个交易的结果,并把结果应用到当前的state里面一部分主要提供了两个API,分别是:** 4 | 5 | * execute block 6 | * commit block 7 | 8 | 这两部分的顶层实现我们在**executionclients&service.md**中进行了展示。 9 | 10 | 11 | 12 | ## 目录: 13 | 14 | ``` 15 | execution 16 | └── execution_client # A Rust wrapper on top of GRPC clients. 17 | └── execution_proto # All interfaces provided by the execution component. 18 | └── execution_service # Execution component as a GRPC service. 19 | └── executor # The main implementation of execution component. 20 | ``` 21 | 22 | -------------------------------------------------------------------------------- /Execution/Executor/block_tree.md: -------------------------------------------------------------------------------- 1 | # block_tree 2 | 3 | ##含义: 4 | 5 | ```rust 6 | //! In a leader based consensus algorithm, each participant maintains a block tree that looks like 7 | //! the following: 8 | //! ```text 9 | //! Height 5 6 7 ... 10 | //! 11 | //! Committed -> B5 -> B6 -> B7 12 | //! | 13 | //! └--> B5' -> B6' -> B7' 14 | //! | 15 | //! └----> B7" 16 | //! ``` 17 | //! This module implements `BlockTree` that is an in-memory representation of this tree. 18 | ``` 19 | 20 | ## 功能: 21 | 22 | 这一部分实现了树的各种操作,比如看看某个block的儿子,父亲,插入block等等操作, 23 | 24 | ## 代码: 25 | 26 | ####定义: 27 | 28 | ```rust 29 | //定义block的trait 30 | //值得注意的set_committed之后可能不会马上加入storage,因为execution操作可能会滞后一点点。 31 | 32 | pub trait Block: std::fmt::Debug { 33 | /// The output of executing this block. 34 | type Output; 35 | 36 | /// The signatures on this block. 37 | type Signature; 38 | 39 | /// Whether consensus has decided to commit this block. This kind of blocks are expected to be 40 | /// sent to storage very soon, unless execution is lagging behind. 41 | fn is_committed(&self) -> bool; 42 | 43 | /// Marks this block as committed. 44 | fn set_committed(&mut self); 45 | 46 | /// Whether this block has finished execution. 47 | fn is_executed(&self) -> bool; 48 | 49 | /// Sets the output of this block. 50 | fn set_output(&mut self, output: Self::Output); 51 | 52 | /// Sets the signatures for this block. 53 | fn set_signature(&mut self, signature: Self::Signature); 54 | 55 | /// The id of this block. 56 | fn id(&self) -> HashValue; 57 | 58 | /// The id of the parent block. 59 | fn parent_id(&self) -> HashValue; 60 | 61 | /// Adds a block as its child. 62 | fn add_child(&mut self, child_id: HashValue); 63 | 64 | /// The list of children of this block. 65 | fn children(&self) -> &HashSet; 66 | } 67 | 68 | 69 | 70 | /// The `BlockTree` implementation. 71 | #[derive(Debug)] 72 | pub struct BlockTree { 73 | /// A map that keeps track of all existing blocks by their ids. 74 | id_to_block: HashMap, 75 | 76 | /// The blocks at the lowest height in the map. B5 and B5' in the following example. 77 | /// ```text 78 | /// Committed(B0..4) -> B5 -> B6 -> B7 79 | /// | 80 | /// └--> B5' -> B6' -> B7' 81 | /// | 82 | /// └----> B7" 83 | /// ``` 84 | heads: HashSet, 85 | 86 | /// Id of the last committed block. B4 in the above example. 87 | last_committed_id: HashValue, 88 | }/// The `BlockTree` implementation. 89 | #[derive(Debug)] 90 | pub struct BlockTree { 91 | /// A map that keeps track of all existing blocks by their ids. 92 | id_to_block: HashMap, 93 | /////每一个block的id都是一个hash 94 | 95 | /// The blocks at the lowest height in the map. B5 and B5' in the following example. 96 | /// ```text 97 | /// Committed(B0..4) -> B5 -> B6 -> B7 98 | /// | 99 | /// └--> B5' -> B6' -> B7' 100 | /// | 101 | /// └----> B7" 102 | /// ``` 103 | heads: HashSet, 104 | 105 | /// Id of the last committed block. B4 in the above example. 106 | last_committed_id: HashValue, 107 | } 108 | ``` 109 | 110 | ### 几个比较有意思的函数;除了这几个,剩下的都比较trivial 111 | 112 | ```rust 113 | /// Returns a reference to a specific block, if it exists in the tree. 114 | pub fn get_block(&self, id: HashValue) -> Option<&B> { 115 | self.id_to_block.get(&id) 116 | } 117 | 118 | /// Returns a mutable reference to a specific block, if it exists in the tree. 119 | ///这个函数往往是其他需要修改树的函数的基础,因为要获取可变的引用 120 | pub fn get_block_mut(&mut self, id: HashValue) -> Option<&mut B> { 121 | self.id_to_block.get_mut(&id) 122 | } 123 | 124 | 125 | 126 | //必须要父节点execute完了才能excute自己 127 | /// Returns id of a block that is ready to be sent to VM for execution (its parent has finished 128 | /// execution), if such block exists in the tree. 129 | pub fn get_block_to_execute(&mut self) -> Option { 130 | let mut to_visit: Vec = self.heads.iter().cloned().collect(); 131 | 132 | while let Some(id) = to_visit.pop() { 133 | let block = self 134 | .id_to_block 135 | .get(&id) 136 | .expect("Missing block in id_to_block."); 137 | if !block.is_executed() { 138 | return Some(id); 139 | } 140 | to_visit.extend(block.children().iter().cloned()); 141 | } 142 | 143 | None 144 | } 145 | 146 | 147 | 148 | //如果自己被确认了,那么自己的所有祖先节点也都被确认了,这些区块都将会被送到storage永久的存储,但可能不是马上完成操作 149 | /// Marks given block and all its uncommitted ancestors as committed. This does not cause these 150 | /// blocks to be sent to storage immediately. 151 | pub fn mark_as_committed( 152 | &mut self, 153 | id: HashValue, 154 | signature: B::Signature, 155 | ) -> Result<(), CommitBlockError> { 156 | // First put the signatures in the block. Note that if this causes multiple blocks to be 157 | // marked as committed, only the last one will have the signatures. 158 | 159 | //也就是说,有的被确认的区块会不存在数字签名 160 | match self.id_to_block.get_mut(&id) { 161 | Some(block) => { 162 | if block.is_committed() { 163 | bail_err!(CommitBlockError::BlockAlreadyMarkedAsCommitted { id }); 164 | } else { 165 | block.set_signature(signature); 166 | } 167 | } 168 | None => bail_err!(CommitBlockError::BlockNotFound { id }), 169 | } 170 | 171 | // Mark the current block as committed. Go to parent block and repeat until a committed 172 | // block is found, or no more blocks. 173 | let mut current_id = id; 174 | while let Some(block) = self.id_to_block.get_mut(¤t_id) { 175 | if block.is_committed() { 176 | break; 177 | } 178 | 179 | block.set_committed(); 180 | current_id = block.parent_id(); 181 | } 182 | /////向上递推地commit 183 | Ok(()) 184 | } 185 | 186 | 187 | 188 | /// Removes all blocks in the tree that conflict with committed blocks. Returns a list of 189 | /// blocks that are ready to be sent to storage (all the committed blocks that have been 190 | /// executed). 191 | pub fn prune(&mut self) -> Vec { 192 | let mut blocks_to_store = vec![]; 193 | 194 | // First find if there is a committed block in current heads. Since these blocks are at the 195 | // same height, at most one of them can be committed. If all of them are pending we have 196 | // nothing to do here. Otherwise, one of the branches is committed. Throw away the rest of 197 | // them and advance to the next height. 198 | let mut current_heads = self.heads.clone(); 199 | while let Some(committed_head) = self.get_committed_head(¤t_heads) { 200 | assert!( 201 | current_heads.remove(&committed_head), 202 | "committed_head should exist.", 203 | ); 204 | for id in current_heads { 205 | self.remove_branch(id); 206 | } 207 | 208 | match self.id_to_block.entry(committed_head) { 209 | hash_map::Entry::Occupied(entry) => { 210 | current_heads = entry.get().children().clone(); 211 | let current_id = *entry.key(); 212 | let parent_id = entry.get().parent_id(); 213 | if entry.get().is_executed() { 214 | // If this block has been executed, all its proper ancestors must have 215 | // finished execution and present in `blocks_to_store`. 216 | self.heads = current_heads.clone(); 217 | self.last_committed_id = current_id; 218 | blocks_to_store.push(entry.remove()); 219 | } else { 220 | // The current block has not finished execution. If the parent block does 221 | // not exist in the map, that means parent block (also committed) has been 222 | // executed and removed. Otherwise self.heads does not need to be changed. 223 | if !self.id_to_block.contains_key(&parent_id) { 224 | self.heads = HashSet::new(); 225 | self.heads.insert(current_id); 226 | } 227 | } 228 | } 229 | hash_map::Entry::Vacant(_) => unreachable!("committed_head_id should exist."), 230 | } 231 | } 232 | 233 | blocks_to_store 234 | } 235 | 236 | ``` 237 | 238 | -------------------------------------------------------------------------------- /Execution/execution_service&client.md: -------------------------------------------------------------------------------- 1 | # Execution: 2 | 3 | ## 功能: 4 | 5 | 这一部分主要是实现了execution模块的主要服务,并且实现了调用这些服务的客户端。 6 | 7 | ## 代码实现: 8 | 9 | 这一部分总体逻辑很简单,主要的工作是加壳,主要是处理了接受request,把请求传送给相应的函数,之后的得到结果,返回给客户端。值得注意的是,实际的execute的逻辑并不是在这里实现的,而是在executor中完成的。这还是体现了libra代码的封装的特点。 10 | 11 | ### execution_service 12 | 13 | ```rust 14 | pub struct ExecutionService { 15 | /// `ExecutionService` simply contains an `Executor` and uses it to process requests. We wrap 16 | /// it in `Arc` because `ExecutionService` has to implement `Clone`. 17 | executor: Arc>, 18 | } 19 | 20 | impl ExecutionService { 21 | /// Constructs an `ExecutionService`. 22 | pub fn new( 23 | storage_read_client: Arc, 24 | storage_write_client: Arc, 25 | config: &NodeConfig, 26 | ) -> Self { 27 | let executor = Arc::new(Executor::new( 28 | storage_read_client, 29 | storage_write_client, 30 | config, 31 | )); 32 | ExecutionService { executor } 33 | } 34 | } 35 | ``` 36 | 37 | #### 提供的几种命令的rpc: 38 | 39 | ```rust 40 | fn execute_block( 41 | &mut self, 42 | ctx: grpcio::RpcContext, 43 | request: execution_proto::proto::execution::ExecuteBlockRequest, 44 | sink: grpcio::UnarySink, 45 | ) { 46 | match ExecuteBlockRequest::from_proto(request) { 47 | Ok(req) => { 48 | let fut = process_response( 49 | self.executor.execute_block( 50 | req.transactions, 51 | req.parent_block_id, 52 | req.block_id, 53 | ), 54 | sink, 55 | ) 56 | .boxed() 57 | .unit_error() 58 | .compat(); 59 | ctx.spawn(fut); 60 | } 61 | Err(err) => { 62 | let fut = process_conversion_error(err, sink); 63 | ctx.spawn(fut); 64 | } 65 | } 66 | } 67 | 68 | fn commit_block( 69 | &mut self, 70 | ctx: grpcio::RpcContext, 71 | request: execution_proto::proto::execution::CommitBlockRequest, 72 | sink: grpcio::UnarySink, 73 | ) { 74 | match CommitBlockRequest::from_proto(request) { 75 | Ok(req) => { 76 | let fut = 77 | process_response(self.executor.commit_block(req.ledger_info_with_sigs), sink) 78 | .boxed() 79 | .unit_error() 80 | .compat(); 81 | ctx.spawn(fut); 82 | } 83 | Err(err) => { 84 | let fut = process_conversion_error(err, sink); 85 | ctx.spawn(fut); 86 | } 87 | } 88 | } 89 | 90 | fn execute_chunk( 91 | &mut self, 92 | ctx: grpcio::RpcContext, 93 | request: execution_proto::proto::execution::ExecuteChunkRequest, 94 | sink: grpcio::UnarySink, 95 | ) { 96 | match ExecuteChunkRequest::from_proto(request) { 97 | Ok(req) => { 98 | let fut = process_response( 99 | self.executor 100 | .execute_chunk(req.txn_list_with_proof, req.ledger_info_with_sigs), 101 | sink, 102 | ) 103 | .boxed() 104 | .unit_error() 105 | .compat(); 106 | ctx.spawn(fut); 107 | } 108 | Err(err) => { 109 | let fut = process_conversion_error(err, sink); 110 | ctx.spawn(fut); 111 | } 112 | } 113 | } 114 | } 115 | 116 | ``` 117 | 118 | #### 处理response的RPC: 119 | 120 | ```rust 121 | async fn process_response( 122 | resp: oneshot::Receiver>, 123 | sink: grpcio::UnarySink<::ProtoType>, 124 | ) where 125 | T: IntoProto, 126 | { 127 | match resp.await { 128 | Ok(Ok(response)) => { 129 | sink.success(response.into_proto()); 130 | } 131 | Ok(Err(err)) => { 132 | set_failure_message( 133 | RpcStatusCode::Unknown, 134 | format!("Failed to process request: {}", err), 135 | sink, 136 | ); 137 | } 138 | Err(oneshot::Canceled) => { 139 | set_failure_message( 140 | RpcStatusCode::Internal, 141 | "Executor Internal error: sender is dropped.".to_string(), 142 | sink, 143 | ); 144 | } 145 | } 146 | } 147 | 148 | ``` 149 | 150 | ### client 151 | 152 | ```rust 153 | pub struct ExecutionClient { 154 | client: execution_grpc::ExecutionClient, 155 | } 156 | 157 | impl ExecutionClient { 158 | pub fn new(env: Arc, host: &str, port: u16) -> Self { 159 | let channel = ChannelBuilder::new(env).connect(&format!("{}:{}", host, port)); 160 | let client = execution_grpc::ExecutionClient::new(channel); 161 | ExecutionClient { client } 162 | } 163 | 164 | pub fn execute_block(&self, request: ExecuteBlockRequest) -> Result { 165 | let proto_request = request.into_proto(); 166 | match self.client.execute_block(&proto_request) { 167 | Ok(proto_response) => Ok(ExecuteBlockResponse::from_proto(proto_response)?), 168 | Err(err) => bail!("GRPC error: {}", err), 169 | } 170 | } 171 | 172 | pub fn commit_block(&self, ledger_info_with_sigs: LedgerInfoWithSignatures) -> Result<()> { 173 | let proto_ledger_info = ledger_info_with_sigs.into_proto(); 174 | let mut request = CommitBlockRequest::new(); 175 | request.set_ledger_info_with_sigs(proto_ledger_info); 176 | match self.client.commit_block(&request) { 177 | Ok(_proto_response) => Ok(()), 178 | Err(err) => bail!("GRPC error: {}", err), 179 | } 180 | } 181 | } 182 | 183 | ``` 184 | 185 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2019, Peking University Blockchain Research Center 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /Language/Language.md: -------------------------------------------------------------------------------- 1 | # Language 2 | 3 | ## 目录: 4 | 5 | ``` 6 | ├── README.md # This README 7 | ├── bytecode_verifier # The bytecode verifier 8 | ├── e2e_tests # infrastructure and tests for the end-to-end flow 9 | ├── functional_tests # Testing framework for the Move language 10 | ├── compiler # The IR to Move bytecode compiler 11 | ├── stdlib # Core Move modules and transaction scripts 12 | ├── test.sh # Script for running all the language tests 13 | └── vm 14 | ├── cost_synthesis # Cost synthesis for bytecode instructions 15 | ├── src # Bytecode language definitions, serializer, and deserializer 16 | ├── tests # VM tests 17 | ├── vm_genesis # The genesis state creation, and blockchain genesis writeset 18 | └── vm_runtime # The bytecode interpreter 19 | ``` 20 | 21 | ## 内容: 22 | 23 | **Move语言包括bytecode_verifier,compiler ,VM等各个部分,在这份教程中我们将不会研究Move的编译与用于验证安全性的bytecode_verifier等部分,只是把他们当作包装好的api。** 24 | 25 | **我们关心的是VM如何调度各个部分,最终完成他的功能。因此我们将参照研究execution部分的做法,直接从看VM如何启动并提供服务,并逐渐深入到各个模块。** 26 | 27 | -------------------------------------------------------------------------------- /Language/VM/VM.md: -------------------------------------------------------------------------------- 1 | # VM 2 | 3 | ## 功能: 4 | 5 | **Libra Core components interact with the language component through the VM. Specifically, the admission control component uses a limited, read-only subset of the VM functionality to discard invalid transactions before they are admitted to the mempool and consensus(这一部分我们单独列在了VM_validator文件夹下). The execution component uses the VM to execute a block of transactions.(我们把这一部分称作MoveVM Core)** 6 | 7 | ##MoveVM Core: 8 | 9 | The MoveVM executes transactions expressed in the Move bytecode. There are 10 | two main crates: the core VM and the VM runtime. The VM core contains the low-level 11 | data type for the VM - mostly the file format and abstraction over it. A gas 12 | metering logical abstraction is also defined there. 13 | 14 | ## 目录 15 | 16 | ``` 17 | ├── cost_synthesis # Infrastructure for gas cost synthesis 18 | ├── src # VM core files 19 | ├── tests # Proptests 20 | ├── vm_genesis # Helpers to generate a genesis block, the initial state of the blockchain 21 | └── vm_runtime # Interpreter and runtime data types (see README in that folder) 22 | ``` 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /Language/VM/VM_runtime/VM_runtime.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: vm-runtime 3 | title: MoveVM Runtime 4 | custom_edit_url: https://github.com/libra/libra/edit/master/language/vm/vm_runtime/README.md 5 | --- 6 | 7 | # MoveVM Runtime 8 | 9 | The MoveVM runtime is the verification and execution engine for the Move 10 | bytecode format. The runtime is imported and loaded in 2 modes: 11 | verification mode (by the [admission control](../../../admission_control) 12 | and [mempool](../../../mempool) components) and execution mode (by the 13 | [execution](../../../execution) component). 14 | 15 | ## Overview 16 | 17 | The MoveVM runtime is a stack machine. The VM runtime receives as input a 18 | *block* which is a list of *transaction scripts* and a *data view*. The 19 | data view is a **read only** snapshot of the data and code in the blockchain at 20 | a given version (i.e., block height). At the time of startup, the runtime 21 | does not have any code or data loaded. It is effectively *“empty”*. 22 | 23 | Every transaction executes within the context of a [Libra 24 | account](../../stdlib/modules/libra_account.mvir)---specifically the transaction 25 | submitter's account. The execution of every transaction consists of three 26 | parts: the account prologue, the transaction itself, and the account 27 | epilogue. This is the only transaction flow known to the runtime, and it is 28 | the only flow the runtime executes. The runtime is responsible to load the 29 | individual transaction from the block and execute the transaction flow: 30 | 31 | 1. ***Transaction Prologue*** - in verification mode the runtime runs the 32 | bytecode verifier over the transaction script and executes the 33 | prologue defined in the [Libra account 34 | module](../../stdlib/modules/libra_account.mvir). The prologue is responsible 35 | for checking the structure of the transaction and 36 | rejecting obviously bad transactions. In verification mode, the runtime 37 | returns a status of either `success` or `failure` depending upon the 38 | result of running the prologue. No updates to the blockchain state are 39 | ever performed by the prologue. 40 | 2. ***Transaction Execution*** - in execution mode, and after verification, 41 | the runtime starts executing transaction-specific/client code. A typical 42 | code performs updates to data in the blockchain. Execution of the 43 | transaction by the VM runtime produces a write set that acts as an 44 | atomic state change from the current state of the blockchain---received 45 | via the data view---to a new version that is the result of applying the 46 | write set. Importantly, on-chain data is _never_ changed during the 47 | execution of the transaction. Further, while the write set is produced as the 48 | result of executing the bytecode, the changes are not applied to the global 49 | blockchain state by the VM---this is the responsibility of the 50 | [execution module](../../../execution/). 51 | 3. ***Transaction Epilogue*** - in execution mode the epilogue defined in 52 | the [Libra account module](../../stdlib/modules/libra_account.mvir) is 53 | executed to perform actions based upon the result of the execution of 54 | the user-submitted transaction. One example of such an action is 55 | debiting the gas fee for the transaction from the submitting account's 56 | balance. 57 | 58 | During execution, the runtime resolves references to code by loading the 59 | referenced code via the data view. One can think of this process as similar 60 | to linking. Then, within the context of a block of transactions---a list of 61 | transactions coupled with a data view---the runtime caches code and 62 | linked and imported modules across transactions within the block. 63 | The runtime tracks state changes (data updates) from one transaction 64 | to the next within each block of transactions; the semantics of the 65 | execution of a block specify that transactions are sequentially executed 66 | and, as a consequence, state changes of previous transactions must be 67 | visible to subsequent transactions within each block. 68 | 69 | ## Implementation Details 70 | 71 | * The runtime top level structs are in `runtime` and `libra vm` related 72 | code. 73 | * The transaction flow is implemented in the [`process_txn`](./src/process_txn.rs) 74 | module. 75 | * The interpreter is implemented within the [transaction 76 | executor](./src/txn_executor.rs). 77 | * Code caching logic and policies are defined under the [code 78 | cache](./src/code_cache/) directory. 79 | * Runtime loaded code and the type system view for the runtime is defined 80 | under the [loaded data](./src/loaded_data/) directory. 81 | * The data representation of values, and logic for write set generation can 82 | be found under the [value](./src/value.rs) and [data 83 | cache](./src/data_cache.rs) files. 84 | 85 | ## Folder Structure 86 | 87 | ``` 88 | . 89 | ├── src # VM Runtime files 90 | │   ├── code_cache # VM Runtime code cache 91 | │   ├── loaded_data # VM Runtime loaded data types, runtime caches over code 92 | │   ├── unit_tests # unit tests 93 | ├── vm_cache_map # abstractions for the code cache 94 | ``` 95 | 96 | ## This Module Interacts With 97 | 98 | This crate is mainly used in two parts: AC and mempool use it to determine 99 | if it should accept a transaction or not; the Executor runs the MoveVM 100 | runtime to execute the program field in a SignedTransaction and convert 101 | it into a TransactionOutput, which contains a writeset that the 102 | executor need to patch to the blockchain as a side effect of this 103 | transaction. 104 | 105 | ## 功能: 106 | 107 | **Runtime模块对外提供了两个函数,一个是validate,一个是excute,这构成了VM的主要功能** 108 | 109 | ## 初始化与最顶层代码: 110 | 111 | ```rust 112 | /// An instantiation of the MoveVM. 113 | /// `code_cache` is the top level module cache that holds loaded published modules. 114 | /// `script_cache` is the cache that stores all the scripts that have previously been invoked. 115 | /// `publishing_option` is the publishing option that is set. This can be one of either: 116 | /// * Locked, with a whitelist of scripts that the VM is allowed to execute. For scripts that aren't 117 | /// in the whitelist, the VM will just reject it in `verify_transaction`. 118 | /// * Custom scripts, which will allow arbitrary valid scripts, but no module publishing 119 | /// * Open script and module publishing 120 | pub struct VMRuntime<'alloc> { 121 | code_cache: VMModuleCache<'alloc>, 122 | script_cache: ScriptCache<'alloc>, 123 | publishing_option: VMPublishingOption, 124 | } 125 | 126 | impl<'alloc> VMRuntime<'alloc> { 127 | /// Create a new VM instance with an Arena allocator to store the modules and a `config` that 128 | /// contains the whitelist that this VM is allowed to execute. 129 | pub fn new(allocator: &'alloc Arena, config: &VMConfig) -> Self { 130 | VMRuntime { 131 | code_cache: VMModuleCache::new(allocator), 132 | script_cache: ScriptCache::new(allocator), 133 | publishing_option: config.publishing_options.clone(), 134 | } 135 | } 136 | 137 | /// Determine if a transaction is valid. Will return `None` if the transaction is accepted, 138 | /// `Some(Err)` if the VM rejects it, with `Err` as an error code. We verify the following 139 | /// items: 140 | /// 1. The signature on the `SignedTransaction` matches the public key included in the 141 | /// transaction 142 | /// 2. The script to be executed is in the whitelist. 143 | /// 3. Invokes `LibraAccount.prologue`, which checks properties such as the transaction has the 144 | /// right sequence number and the sender has enough balance to pay for the gas. 4. 145 | /// Transaction arguments matches the main function's type signature. 5. Script and modules 146 | /// in the transaction pass the bytecode static verifier. 147 | /// 148 | /// Note: In the future. we may defer these checks to a later pass, as all the scripts we will 149 | /// execute are pre-verified scripts. And bytecode verification is expensive. Thus whether we 150 | /// want to perform this check here remains unknown. 151 | pub fn verify_transaction( 152 | &self, 153 | txn: SignedTransaction, 154 | data_view: &dyn StateView, 155 | ) -> Option { 156 | debug!("[VM] Verify transaction: {:?}", txn); 157 | // Treat a transaction as a single block. 158 | let module_cache = 159 | BlockModuleCache::new(&self.code_cache, ModuleFetcherImpl::new(data_view)); 160 | let data_cache = BlockDataCache::new(data_view); 161 | 162 | let arena = Arena::new(); 163 | let signature_verified_txn = match txn.check_signature() { 164 | Ok(t) => t, 165 | Err(_) => return Some(VMStatus::Validation(VMValidationStatus::InvalidSignature)), 166 | }; 167 | 168 | let process_txn = 169 | ProcessTransaction::new(signature_verified_txn, module_cache, &data_cache, &arena); 170 | let mode = if data_view.is_genesis() { 171 | ValidationMode::Genesis 172 | } else { 173 | ValidationMode::Validating 174 | }; 175 | 176 | let validated_txn = match process_txn.validate(mode, &self.publishing_option) { 177 | Ok(validated_txn) => validated_txn, 178 | Err(vm_status) => { 179 | let res = Some(vm_status); 180 | report_verification_status(&res); 181 | return res; 182 | } 183 | }; 184 | let res = match validated_txn.verify(&self.script_cache) { 185 | Ok(_) => None, 186 | Err(vm_status) => Some(vm_status), 187 | }; 188 | ////validate和verify在process_txm中实现 189 | report_verification_status(&res); 190 | res 191 | } 192 | 193 | /// Execute a block of transactions. The output vector will have the exact same length as the 194 | /// input vector. The discarded transactions will be marked as `TransactionStatus::Discard` and 195 | /// have an empty writeset. Also the data view is immutable, and also does not have interior 196 | /// mutability. writes to be applied to the data view are encoded in the write set part of a 197 | /// transaction output. 198 | pub fn execute_block_transactions( 199 | &self, 200 | txn_block: Vec, 201 | data_view: &dyn StateView, 202 | ) -> Vec { 203 | execute_block( 204 | txn_block, 205 | &self.code_cache, 206 | &self.script_cache, 207 | data_view, 208 | &self.publishing_option, 209 | ) 210 | } 211 | } 212 | 213 | ``` 214 | 215 | ## MoveVM(move_vm.rs) : a wrapper for thread safe 216 | 217 | ```rust 218 | /// A wrapper to make VMRuntime standalone and thread safe. 219 | #[derive(Clone)] 220 | pub struct MoveVM { 221 | inner: Arc, 222 | } 223 | 224 | impl MoveVM { 225 | pub fn new(config: &VMConfig) -> Self { 226 | let inner = MoveVMImpl::new(Box::new(Arena::new()), |arena| { 227 | VMRuntime::new(&*arena, config) 228 | }); 229 | Self { 230 | inner: Arc::new(inner), 231 | } 232 | } 233 | } 234 | 235 | impl VMVerifier for MoveVM { 236 | fn validate_transaction( 237 | &self, 238 | transaction: SignedTransaction, 239 | state_view: &dyn StateView, 240 | ) -> Option { 241 | // TODO: This should be implemented as an async function. 242 | self.inner 243 | .rent(move |runtime| runtime.verify_transaction(transaction, state_view)) 244 | } 245 | } 246 | 247 | impl VMExecutor for MoveVM { 248 | fn execute_block( 249 | transactions: Vec, 250 | config: &VMConfig, 251 | state_view: &dyn StateView, 252 | ) -> Vec { 253 | let vm = MoveVMImpl::new(Box::new(Arena::new()), |arena| { 254 | // XXX This means that scripts and modules are NOT tested against the whitelist! This 255 | // needs to be fixed. 256 | VMRuntime::new(&*arena, config) 257 | }); 258 | vm.rent(|runtime| runtime.execute_block_transactions(transactions, state_view)) 259 | } 260 | } 261 | 262 | #[test] 263 | fn vm_thread_safe() { 264 | fn assert_send() {} 265 | fn assert_sync() {} 266 | 267 | assert_send::(); 268 | assert_sync::(); 269 | assert_send::(); 270 | assert_sync::(); 271 | } 272 | 273 | ``` 274 | 275 | 276 | 277 | -------------------------------------------------------------------------------- /Language/libra-move-a-language-with-programmable-resources.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jiashuo-Zhang/Libra-code-Analysis/7640948485fcacff61159c51dd160e99230da680/Language/libra-move-a-language-with-programmable-resources.pdf -------------------------------------------------------------------------------- /Network/Network.md: -------------------------------------------------------------------------------- 1 | # Network 2 | 3 | ## 目录: 4 | 5 | ``` 6 | network 7 | ├── benches # network benchmarks 8 | ├── memsocket # In-memory transport for tests 9 | ├── netcore 10 | │ └── src 11 | │ ├── multiplexing # substream multiplexing over a transport 12 | │ ├── negotiate # protocol negotiation 13 | │ └── transport # composable transport API 14 | ├── noise # noise framework for authentication and encryption 15 | └── src 16 | ├── channel # mpsc channel wrapped in IntGauge 17 | ├── connectivity_manager # component to ensure connectivity to peers 18 | ├── interface # generic network API 19 | ├── peer_manager # component to dial/listen for connections 20 | ├── proto # protobuf definitions for network messages 21 | ├── protocols # message protocols 22 | │ ├── direct_send # protocol for fire-and-forget style message delivery 23 | │ ├── discovery # protocol for peer discovery and gossip 24 | │ ├── health_checker # protocol for health probing 25 | │ └── rpc # protocol for remote procedure calls 26 | ├── sink # utilities over message sinks 27 | └── validator_network # network API for consensus and mempool 28 | ``` 29 | 30 | ## 结构: 31 | 32 | ```rust 33 | +---------------------+---------------------+ 34 | | Consensus | Mempool | 35 | +---------------------+---------------------+ 36 | | Validator Network | 37 | +---------------------+---------------------+ 38 | | NetworkProvider | 39 | +------------------------------------------------+-----------------+ | 40 | | Discovery, health, etc | RPC | DirectSend | | 41 | +--------------+---------------------------------------------------------+ 42 | | Peer Manager | 43 | +------------------------------------------------------------------+-----+ 44 | ``` 45 | 46 | ## 功能: 47 | 48 | **netwotk维护了node之间的通信,维护了peer们,还给出了访问validator的mempool,consensus等模块的功能** 49 | 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Libra-code-Analysis 2 | 3 | **这个项目旨在帮助研究者们理解Libra的基础框架和了解Rust语言。我们分别描述了The Libra Blockchain的核心组成部分,并聚焦于他们是如何相互联系,组成一个具有完整功能的系统。我们在现有官方文档和注释的基础上,关注于最为核心的框架,自顶向下地逐步深入,并最终完成代码实现层面的分析。同时,对一些繁琐晦涩的部分,我们只关心他们的作用与实现方法,而不深究其具体实现。我们希望这个项目能为希望了解Libra底层实现的研究者和开发者们提供一部分帮助,同时填补Libra 中文代码分析这一领域的空白。** 4 | 5 | ## 背景知识: 6 | 7 | **我们的分析建立在了解区块链基础概念(如BFT共识、智能合约、联盟链等)与Rust简单语法的基础上,另外,我们强烈推荐阅读一部分Libra官方文档——[Life-of-a-transaction](https://developers.libra.org/docs/life-of-a-transaction),这可以帮助阅读者快速了解Libra的各个部分的大致功能以及互相之间的联系,后续的分析以这一文档为主线,逐步深入。** 8 | 9 | ## 目录: 10 | 11 | * **[AC](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/AC/AC.md)** 12 | * [README](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/AC/AC.md) 13 | * **[VM_validator](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/VM_validator/VM_validator.md)** 14 | * [README](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/VM_validator/VM_validator.md) 15 | * **[Mempool](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/tree/master/mempool)** 16 | * [README](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/mempool/mempool.md) 17 | * [Mempool_core_mempool](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/mempool/mempool_core_mempool.md) 18 | * [Mempool_service](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/mempool/mempool_service.md) 19 | * [Shared_mempool](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/mempool/shared_mempool.md) 20 | * [runtime](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/mempool/runtime.md) 21 | * **[Consensus](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/tree/master/consensus)** 22 | * [LibraBFT-paper](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/consensus/libra-consensus-state-machine-replication-in-the-libra-blockchain.pdf) 23 | * [README](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/consensus/consensus.md) 24 | * [Txn_Manager](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/consensus/Txn_manager.md) 25 | * [State_Computer](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/consensus/State_Computer.md) 26 | * [SMR](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/tree/master/consensus/SMR) 27 | * [block_store](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/consensus/SMR/block_store.md) 28 | * [SMR](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/consensus/SMR/SMR.md) 29 | * [EventProcessor](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/consensus/SMR/EventProcessor.md) 30 | * [Sync_nanager](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/consensus/SMR/sync_manager.md) 31 | * [Safety_rules](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/consensus/SMR/safety_rules.md) 32 | * [Pacemaker](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/consensus/SMR/Pacemaker.md) 33 | * **[Execution](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/tree/master/Execution)** 34 | * [README](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/tree/master/Execution) 35 | * [Execution_service&client](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/Execution/execution_service%26client.md) 36 | * [Executor](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/tree/master/Execution/Executor) 37 | * [block_tree](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/Execution/Executor/block_tree.md) 38 | * [blocks](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/Execution/Executor/blocks.md) 39 | * **[Storage](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/tree/master/storage)** 40 | * [README](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/storage/storage.md) 41 | * [accumulator](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/storage/accumulator.md) 42 | * [Storage_service & client](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/storage/storage_service%26client.md) 43 | * [Event_store](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/storage/Event_store.md) 44 | * [Libradb](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/storage/Libradb.md) 45 | * **[Language](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/tree/master/Language)** 46 | * [Move paper](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/Language/libra-move-a-language-with-programmable-resources.pdf) 47 | * [README](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/Language/Language.md) 48 | * [VM](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/tree/master/Language/VM) 49 | * [README](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/Language/VM/VM.md) 50 | * [VM_runtime](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/tree/master/Language/VM/VM_runtime) 51 | * [Process_txn](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/tree/master/Language/VM/VM_runtime/process_txn) 52 | * [Txn_excutors](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/tree/master/Language/VM/VM_runtime/txn_executor) 53 | * [VM_runtime_README](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/Language/VM/VM_runtime/VM_runtime.md) 54 | * **[Network](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/tree/master/Network)** 55 | - [README](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/Network/Network.md) 56 | * **[Client](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/tree/master/client)** 57 | * [README](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/client/client.md) 58 | * [client_proxy](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/client/client_proxy.md) 59 | * [grpc_client](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/client/grpc_client.md) 60 | 61 | ## 当前进度: 62 | 63 | **目前AC,VM_validator,Mempool,Consensus,Execution,Storage部分内容较为完善,Language,Network,Client内容还有所缺失,由于精力与水平有限,未来我们将优先对Move语言相关部分做进一步分析。** 64 | 65 | ## 说明: 66 | 67 | **整个项目还有很多待完成的工作,我们随时欢迎新的贡献者的加入,共同为Libra的中文代码分析作出贡献。同时,阅读过程中如果发现错误,欢迎联系我们勘误。:)** 68 | 69 | ## 版权与许可声明: 70 | 71 | **本项目使用BSD 2-Clause "Simplified" License,转载需注明许可声明与版权声明。** 72 | 73 | ## 参考资料: 74 | 75 | * Libra 源码: 76 | 77 | * Libra 开发者官网: 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /VM_validator/VM_validator.md: -------------------------------------------------------------------------------- 1 | # VM_validator.rs 2 | 3 | ## 功能: 4 | 5 | **提供一个对交易进行验证的服务,判断其是否合法值得注意的是这一部分并没有实现validate_transactions的逻辑,只是简单的进行了包装,调用MoveVM的一个函数(vm.validate_transaction)实现的,具体实现中,会有输入一个相应的state_view(包含账户信息等)和一个txn,通过这两个参数进行判断。** 6 | 7 | ## 模块: 8 | 9 | * 主要功能在vm_validator.rs 中实现 10 | 11 | ## 与其他模块的交互 12 | 13 | * AC会生成VM_validator的instance 14 | * 会与storage和VM模块进行交互 15 | 16 | ## 代码: 17 | 18 | #### 定义 19 | 20 | ```rust 21 | //定义了一个trait,一个结构体 22 | pub trait TransactionValidation: Send + Sync { 23 | type ValidationInstance: VMVerifier; 24 | /// Validate a txn from client 25 | fn validate_transaction( 26 | &self, 27 | _txn: SignedTransaction, 28 | ) -> Box, Error = failure::Error> + Send>; 29 | } 30 | 31 | #[derive(Clone)] 32 | //结构体中有一个读storage的client,一个用于验证的虚拟机 33 | pub struct VMValidator { 34 | storage_read_client: Arc,////包含一个storage client,来获得相应账户的sequence,balance等信息 35 | vm: MoveVM, 36 | } 37 | 38 | impl VMValidator { 39 | pub fn new(config: &NodeConfig, storage_read_client: Arc) -> Self { 40 | VMValidator { 41 | storage_read_client, 42 | vm: MoveVM::new(&config.vm_config), 43 | } 44 | } 45 | } 46 | 47 | ``` 48 | 49 | #### VMvalidator实现transactionvalidation接口 50 | 51 | ```rust 52 | impl TransactionValidation for VMValidator { 53 | type ValidationInstance = MoveVM; 54 | 55 | fn validate_transaction( 56 | &self, 57 | txn: SignedTransaction, 58 | ) -> Box, Error = failure::Error> + Send> { 59 | // TODO: For transaction validation, there are two options to go: 60 | // 1. Trust storage: there is no need to get root hash from storage here. We will 61 | // create another struct similar to `VerifiedStateView` that implements `StateView` 62 | // but does not do verification. 63 | // 2. Don't trust storage. This requires more work: 64 | // 1) AC must have validator set information 65 | // 2) Get state_root from transaction info which can be verified with signatures of 66 | // validator set. 67 | // 3) Create VerifiedStateView with verified state 68 | // root. 69 | 70 | // Just ask something from storage. It doesn't matter what it is -- we just need the 71 | // transaction info object in account state proof which contains the state root hash. 72 | let address = AccountAddress::new([0xff; ADDRESS_LENGTH]); 73 | let item = RequestItem::GetAccountState { address }; 74 | 75 | match self 76 | .storage_read_client 77 | .update_to_latest_ledger(/* client_known_version = */ 0, vec![item]) 78 | { //这里应该是用了上面函数的默认参数值,功能就是查找vec包含的内容,然后返回状态(详见AC部分) 79 | //获取account_state,并进行一系列检查 80 | Ok((mut items, _, _)) => { 81 | if items.len() != 1 { 82 | return Box::new(err(format_err!( 83 | "Unexpected number of items ({}).", 84 | items.len() 85 | ) 86 | .into())); 87 | } 88 | 89 | match items.remove(0) { 90 | ResponseItem::GetAccountState { 91 | account_state_with_proof, 92 | } => { 93 | let transaction_info = account_state_with_proof.proof.transaction_info(); 94 | let state_root = transaction_info.state_root_hash(); 95 | let smt = SparseMerkleTree::new(state_root); 96 | let state_view = VerifiedStateView::new( 97 | Arc::clone(&self.storage_read_client), 98 | state_root, 99 | &smt, 100 | ); 101 | //包装相关账户的状态 102 | Box::new(ok(self.vm.validate_transaction(txn, &state_view))) 103 | //把相关账户的状态和带验证的交易传入虚拟机,虚拟机运行不报错则表示交易合法 104 | } 105 | _ => panic!("Unexpected item in response."), 106 | } 107 | } 108 | Err(e) => Box::new(err(e.into())),//Box是一个智能指针 109 | } 110 | } 111 | } 112 | ``` 113 | 114 | #### get_account_state :获取账户的sequence number和balance 115 | 116 | ```rust 117 | pub async fn get_account_state( 118 | storage_read_client: Arc, 119 | address: AccountAddress, 120 | ) -> Result<(u64, u64)> { 121 | let req_item = RequestItem::GetAccountState { address }; 122 | let (response_items, _, _) = storage_read_client 123 | .update_to_latest_ledger_async(0 /* client_known_version */, vec![req_item]) 124 | .await?; 125 | // 类似上面函数的注释,返回一个函数的状态和proof 126 | let account_state = match &response_items[0] { 127 | ResponseItem::GetAccountState { 128 | account_state_with_proof, 129 | } => &account_state_with_proof.blob, 130 | _ => bail!("Not account state response."), 131 | }; 132 | let account_resource = get_account_resource_or_default(account_state)?; 133 | let sequence_number = account_resource.sequence_number(); 134 | let balance = account_resource.balance(); 135 | Ok((sequence_number, balance)) 136 | } 137 | ``` 138 | 139 | ## 总结: 140 | 141 | **这一部分体现了封装的基本思想。这一部分起到的作用就是通过底层的查询account状态的函数,组装出相关参数,然后调用VM中实现的函数,最终完成调用功能** 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /client/client.md: -------------------------------------------------------------------------------- 1 | # client 2 | 3 | ##  功能: 4 | 5 | **src实现了一个接入libra的client,他能够用于连接特定的validator**,libra—wallet部分实现了一个钱包,我们暂时不准备看这一部分 6 | 7 | ## 代码: 8 | 9 | #### main.rs:用命令行创建了一个client(可以指定config),并连接到validator,CLI commands 是在client_proxy.rs中实现的,这些命令实现起来都比较短,函数名称能反映其功能。 10 | 11 | #### 剩下的一些xxx.commands基本都是处理了几种command,在处理过程中都是直接调用了client的函数 12 | 13 | ```rust 14 | struct Args { 15 | /// Admission Control port to connect to. 16 | #[structopt(short = "p", long = "port", default_value = "30307")] 17 | pub port: String, 18 | /// Host address/name to connect to. 19 | #[structopt(short = "a", long = "host")] 20 | pub host: String, 21 | /// Path to the generated keypair for the faucet account. The faucet account can be used to 22 | /// mint coins. If not passed, a new keypair will be generated for 23 | /// you and placed in a temporary directory. 24 | /// To manually generate a keypair, use generate_keypair: 25 | /// `cargo run -p generate_keypair -- -o ` 26 | #[structopt(short = "m", long = "faucet_key_file_path")] 27 | pub faucet_account_file: Option, 28 | /// Host that operates a faucet service 29 | /// If not passed, will be derived from host parameter 30 | #[structopt(short = "f", long = "faucet_server")] 31 | pub faucet_server: Option, 32 | /// File location from which to load mnemonic word for user account address/key generation. 33 | /// If not passed, a new mnemonic file will be generated by libra_wallet in the current 34 | /// directory. 35 | #[structopt(short = "n", long = "mnemonic_file")] 36 | pub mnemonic_file: Option, 37 | /// File location from which to load config of trusted validators. It is used to verify 38 | /// validator signatures in validator query response. The file should at least include public 39 | /// key of all validators trusted by the client - which should typically be all validators on 40 | /// the network. To connect to testnet, use 'libra/scripts/cli/trusted_peers.config.toml'. 41 | /// Can be generated by libra-config for local testing: 42 | /// `cargo run --bin libra-config` 43 | /// But the preferred method is to simply use libra-swarm to run local networks 44 | #[structopt(short = "s", long = "validator_set_file")] 45 | pub validator_set_file: String, 46 | /// If set, client will sync with validator during wallet recovery. 47 | #[structopt(short = "r", long = "sync")] 48 | pub sync: bool, 49 | } 50 | 51 | 52 | struct Args { 53 | /// Admission Control port to connect to. 54 | #[structopt(short = "p", long = "port", default_value = "30307")] 55 | pub port: String, 56 | /// Host address/name to connect to. 57 | #[structopt(short = "a", long = "host")] 58 | pub host: String, 59 | /// Path to the generated keypair for the faucet account. The faucet account can be used to 60 | /// mint coins. If not passed, a new keypair will be generated for 61 | /// you and placed in a temporary directory. 62 | /// To manually generate a keypair, use generate_keypair: 63 | /// `cargo run -p generate_keypair -- -o ` 64 | #[structopt(short = "m", long = "faucet_key_file_path")] 65 | pub faucet_account_file: Option, 66 | /// Host that operates a faucet service 67 | /// If not passed, will be derived from host parameter 68 | #[structopt(short = "f", long = "faucet_server")] 69 | pub faucet_server: Option, 70 | /// File location from which to load mnemonic word for user account address/key generation. 71 | /// If not passed, a new mnemonic file will be generated by libra_wallet in the current 72 | /// directory. 73 | #[structopt(short = "n", long = "mnemonic_file")] 74 | pub mnemonic_file: Option, 75 | /// File location from which to load config of trusted validators. It is used to verify 76 | /// validator signatures in validator query response. The file should at least include public 77 | /// key of all validators trusted by the client - which should typically be all validators on 78 | /// the network. To connect to testnet, use 'libra/scripts/cli/trusted_peers.config.toml'. 79 | /// Can be generated by libra-config for local testing: 80 | /// `cargo run --bin libra-config` 81 | /// But the preferred method is to simply use libra-swarm to run local networks 82 | #[structopt(short = "s", long = "validator_set_file")] 83 | pub validator_set_file: String, 84 | /// If set, client will sync with validator during wallet recovery. 85 | #[structopt(short = "r", long = "sync")] 86 | pub sync: bool, 87 | } 88 | 89 | fn main() -> std::io::Result<()> { 90 | let _logger = set_default_global_logger(false /* async */, None); 91 | crash_handler::setup_panic_handler(); 92 | 93 | let (commands, alias_to_cmd) = get_commands(); 94 | 95 | let args = Args::from_args(); 96 | let faucet_account_file = args.faucet_account_file.unwrap_or_else(|| "".to_string()); 97 | 98 | let mut client_proxy = ClientProxy::new( 99 | &args.host, 100 | &args.port, 101 | &args.validator_set_file, 102 | &faucet_account_file, 103 | args.sync, 104 | args.faucet_server, 105 | args.mnemonic_file, 106 | ) 107 | .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, &format!("{}", e)[..]))?; 108 | 109 | // Test connection to validator 110 | let test_ret = client_proxy.test_validator_connection(); 111 | 112 | if let Err(e) = test_ret { 113 | println!( 114 | "Not able to connect to validator at {}:{}, error {:?}", 115 | args.host, args.port, e 116 | ); 117 | return Ok(()); 118 | } 119 | let cli_info = format!("Connected to validator at: {}:{}", args.host, args.port); 120 | print_help(&cli_info, &commands); 121 | println!("Please, input commands: \n"); 122 | 123 | let config = Config::builder() 124 | .history_ignore_space(true) 125 | .completion_type(CompletionType::List) 126 | .auto_add_history(true) 127 | .build(); 128 | let mut rl = Editor::<()>::with_config(config); 129 | loop { 130 | let readline = rl.readline("libra% "); 131 | match readline { 132 | Ok(line) => { 133 | let params = parse_cmd(&line); 134 | match alias_to_cmd.get(params[0]) { 135 | Some(cmd) => cmd.execute(&mut client_proxy, ¶ms),/////根据command的不同会调用不同的函数,这就是在xxxx.command.rs中实现的 136 | None => match params[0] { 137 | "quit" | "q!" => break, 138 | "help" | "h" => print_help(&cli_info, &commands), 139 | "" => continue, 140 | x => println!("Unknown command: {:?}", x), 141 | }, 142 | } 143 | } 144 | Err(ReadlineError::Interrupted) => { 145 | println!("CTRL-C"); 146 | break; 147 | } 148 | Err(ReadlineError::Eof) => { 149 | println!("CTRL-D"); 150 | break; 151 | } 152 | Err(err) => { 153 | println!("Error: {:?}", err); 154 | break; 155 | } 156 | } 157 | } 158 | 159 | Ok(()) 160 | } 161 | 162 | ``` 163 | 164 | -------------------------------------------------------------------------------- /client/grpc_client.md: -------------------------------------------------------------------------------- 1 | # grpc_client 2 | 3 | ## 功能: 4 | 5 | **这一部分主要是建立了一个grpc的client,并通过使用grpc服务来完成各种与validator的交互(比如是submit txns)** 6 | 7 | ## 代码: 8 | 9 | #### 定义: 10 | 11 | ```rust 12 | const MAX_GRPC_RETRY_COUNT: u64 = 1; 13 | 14 | /// Struct holding dependencies of client. 15 | pub struct GRPCClient { 16 | client: AdmissionControlClient,/////可以看到是建立的与ACcontorl的client 17 | validator_verifier: Arc, 18 | } 19 | 20 | impl GRPCClient { 21 | /// Construct a new Client instance. 22 | pub fn new(host: &str, port: &str, validator_verifier: Arc) -> Result { 23 | let conn_addr = format!("{}:{}", host, port); 24 | 25 | // Create a GRPC client 26 | let env = Arc::new(EnvBuilder::new().name_prefix("grpc-client-").build()); 27 | let ch = ChannelBuilder::new(env).connect(&conn_addr); 28 | let client = AdmissionControlClient::new(ch); 29 | 30 | Ok(GRPCClient { 31 | client, 32 | validator_verifier, 33 | }) 34 | } 35 | 36 | ``` 37 | 38 | #### 一些功能:一般对一个功能都同时实现了同步和异步的版本 39 | 40 | ```rust 41 | /// Submits a transaction and bumps the sequence number for the sender, pass in `None` for 42 | /// sender_account if sender's address is not managed by the client. 43 | pub fn submit_transaction( 44 | &self, 45 | sender_account_opt: Option<&mut AccountData>, 46 | req: &SubmitTransactionRequest, 47 | ) -> Result<()> { 48 | let mut resp = self.submit_transaction_opt(req); 49 | 50 | let mut try_cnt = 0_u64; 51 | while Self::need_to_retry(&mut try_cnt, &resp) { 52 | resp = self.submit_transaction_opt(&req); 53 | } 54 | 55 | let completed_resp = SubmitTransactionResponse::from_proto(resp?)?; 56 | 57 | if let Some(ac_status) = completed_resp.ac_status { 58 | if ac_status == AdmissionControlStatus::Accepted { 59 | if let Some(sender_account) = sender_account_opt { 60 | // Bump up sequence_number if transaction is accepted. 61 | sender_account.sequence_number += 1; 62 | } 63 | } else { 64 | bail!("Transaction failed with AC status: {:?}", ac_status,); 65 | } 66 | } else if let Some(vm_error) = completed_resp.vm_error { 67 | if vm_error == VMStatus::Validation(VMValidationStatus::SequenceNumberTooOld) { 68 | if let Some(sender_account) = sender_account_opt { 69 | sender_account.sequence_number = 70 | self.get_sequence_number(sender_account.address)?; 71 | bail!( 72 | "Transaction failed with vm status: {:?}, please retry your transaction.", 73 | vm_error 74 | ); 75 | } 76 | } 77 | bail!("Transaction failed with vm status: {:?}", vm_error); 78 | } else if let Some(mempool_error) = completed_resp.mempool_error { 79 | bail!( 80 | "Transaction failed with mempool status: {:?}", 81 | mempool_error, 82 | ); 83 | } else { 84 | bail!( 85 | "Malformed SubmitTransactionResponse which has no status set, {:?}", 86 | completed_resp, 87 | ); 88 | } 89 | Ok(()) 90 | } 91 | 92 | /// Async version of submit_transaction 93 | pub fn submit_transaction_async( 94 | &self, 95 | req: &SubmitTransactionRequest, 96 | ) -> Result<(impl Future)> { 97 | let resp = self 98 | .client 99 | .submit_transaction_async_opt(&req, Self::get_default_grpc_call_option())? 100 | .then(|proto_resp| { 101 | let ret = SubmitTransactionResponse::from_proto(proto_resp?)?; 102 | Ok(ret) 103 | }); 104 | Ok(resp) 105 | } 106 | 107 | fn submit_transaction_opt( 108 | &self, 109 | resp: &SubmitTransactionRequest, 110 | ) -> Result { 111 | Ok(self 112 | .client 113 | .submit_transaction_opt(resp, Self::get_default_grpc_call_option())?) 114 | } 115 | 116 | fn get_with_proof_async( 117 | &self, 118 | requested_items: Vec, 119 | ) -> Result> { 120 | let req = UpdateToLatestLedgerRequest::new(0, requested_items.clone()); 121 | debug!("get_with_proof with request: {:?}", req); 122 | let proto_req = req.clone().into_proto(); 123 | let validator_verifier = Arc::clone(&self.validator_verifier); 124 | let ret = self 125 | .client 126 | .update_to_latest_ledger_async_opt(&proto_req, Self::get_default_grpc_call_option())? 127 | .then(move |get_with_proof_resp| { 128 | // TODO: Cache/persist client_known_version to work with validator set change when 129 | // the feature is available. 130 | 131 | let resp = UpdateToLatestLedgerResponse::from_proto(get_with_proof_resp?)?; 132 | resp.verify(validator_verifier, &req)?; 133 | Ok(resp) 134 | }); 135 | Ok(ret) 136 | } 137 | 138 | fn need_to_retry(try_cnt: &mut u64, ret: &Result) -> bool { 139 | if *try_cnt <= MAX_GRPC_RETRY_COUNT { 140 | *try_cnt += 1; 141 | if let Err(error) = ret { 142 | if let Some(grpc_error) = error.downcast_ref::() { 143 | if let grpcio::Error::RpcFailure(grpc_rpc_failure) = grpc_error { 144 | // Only retry when the connection is down to make sure we won't 145 | // send one txn twice. 146 | return grpc_rpc_failure.status == grpcio::RpcStatusCode::Unavailable; 147 | } 148 | } 149 | } 150 | } 151 | false 152 | } 153 | /// Sync version of get_with_proof 154 | pub(crate) fn get_with_proof_sync( 155 | &self, 156 | requested_items: Vec, 157 | ) -> Result { 158 | let mut resp: Result = 159 | self.get_with_proof_async(requested_items.clone())?.wait(); 160 | let mut try_cnt = 0_u64; 161 | 162 | while Self::need_to_retry(&mut try_cnt, &resp) { 163 | resp = self.get_with_proof_async(requested_items.clone())?.wait(); 164 | } 165 | 166 | Ok(resp?) 167 | } 168 | 169 | /// Get the latest account sequence number for the account specified. 170 | pub fn get_sequence_number(&self, address: AccountAddress) -> Result { 171 | Ok(get_account_resource_or_default(&self.get_account_blob(address)?.0)?.sequence_number()) 172 | } 173 | 174 | /// Get the latest account state blob from validator. 175 | pub(crate) fn get_account_blob( 176 | &self, 177 | address: AccountAddress, 178 | ) -> Result<(Option, Version)> { 179 | let req_item = RequestItem::GetAccountState { address }; 180 | 181 | let mut response = self.get_with_proof_sync(vec![req_item])?; 182 | let account_state_with_proof = response 183 | .response_items 184 | .remove(0) 185 | .into_get_account_state_response()?; 186 | 187 | Ok(( 188 | account_state_with_proof.blob, 189 | response.ledger_info_with_sigs.ledger_info().version(), 190 | )) 191 | } 192 | 193 | /// Get transaction from validator by account and sequence number. 194 | pub fn get_txn_by_acc_seq( 195 | &self, 196 | account: AccountAddress, 197 | sequence_number: u64, 198 | fetch_events: bool, 199 | ) -> Result>)>> { 200 | let req_item = RequestItem::GetAccountTransactionBySequenceNumber { 201 | account, 202 | sequence_number, 203 | fetch_events, 204 | }; 205 | 206 | let mut response = self.get_with_proof_sync(vec![req_item])?; 207 | let (signed_txn_with_proof, _) = response 208 | .response_items 209 | .remove(0) 210 | .into_get_account_txn_by_seq_num_response()?; 211 | 212 | Ok(signed_txn_with_proof.map(|t| (t.signed_transaction, t.events))) 213 | } 214 | 215 | /// Get transactions in range (start_version..start_version + limit - 1) from validator. 216 | pub fn get_txn_by_range( 217 | &self, 218 | start_version: u64, 219 | limit: u64, 220 | fetch_events: bool, 221 | ) -> Result>)>> { 222 | // Make the request. 223 | let req_item = RequestItem::GetTransactions { 224 | start_version, 225 | limit, 226 | fetch_events, 227 | }; 228 | let mut response = self.get_with_proof_sync(vec![req_item])?; 229 | let txn_list_with_proof = response 230 | .response_items 231 | .remove(0) 232 | .into_get_transactions_response()?; 233 | 234 | // Transform the response. 235 | let num_txns = txn_list_with_proof.transaction_and_infos.len(); 236 | let event_lists = txn_list_with_proof 237 | .events 238 | .map(|event_lists| event_lists.into_iter().map(Some).collect()) 239 | .unwrap_or_else(|| vec![None; num_txns]); 240 | 241 | let res = itertools::zip_eq(txn_list_with_proof.transaction_and_infos, event_lists) 242 | .map(|((signed_txn, _), events)| (signed_txn, events)) 243 | .collect(); 244 | Ok(res) 245 | } 246 | 247 | /// Get event by access path from validator. AccountStateWithProof will be returned if 248 | /// 1. No event is available. 2. Ascending and available event number < limit. 249 | /// 3. Descending and start_seq_num > latest account event sequence number. 250 | pub fn get_events_by_access_path( 251 | &self, 252 | access_path: AccessPath, 253 | start_event_seq_num: u64, 254 | ascending: bool, 255 | limit: u64, 256 | ) -> Result<(Vec, Option)> { 257 | let req_item = RequestItem::GetEventsByEventAccessPath { 258 | access_path, 259 | start_event_seq_num, 260 | ascending, 261 | limit, 262 | }; 263 | 264 | let mut response = self.get_with_proof_sync(vec![req_item])?; 265 | let value_with_proof = response.response_items.remove(0); 266 | match value_with_proof { 267 | ResponseItem::GetEventsByEventAccessPath { 268 | events_with_proof, 269 | proof_of_latest_event, 270 | } => Ok((events_with_proof, proof_of_latest_event)), 271 | _ => bail!( 272 | "Incorrect type of response returned: {:?}", 273 | value_with_proof 274 | ), 275 | } 276 | } 277 | 278 | fn get_default_grpc_call_option() -> CallOption { 279 | CallOption::default() 280 | .wait_for_ready(true) 281 | .timeout(std::time::Duration::from_millis(5000)) 282 | } 283 | } 284 | 285 | ``` 286 | 287 | 288 | 289 | -------------------------------------------------------------------------------- /consensus/SMR/Pacemaker.md: -------------------------------------------------------------------------------- 1 | # Pacemaker: 2 | 3 | ## 功能: 4 | 5 | **顾名思义,负责LibraBFT的liveness。他会检测超时的状况并进入一个新的round ,当他是当前round的leader时,这一部分还负责propose出一个block。** 6 | 7 | ## 代码实现: 8 | 9 | 10 | 11 | ```rust 12 | /// A reason for starting a new round: introduced for monitoring / debug purposes. 13 | #[derive(Eq, Debug, PartialEq)] 14 | pub enum NewRoundReason { 15 | QCReady, 16 | Timeout { cert: PacemakerTimeoutCertificate }, 17 | } 18 | 19 | impl fmt::Display for NewRoundReason { 20 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 21 | match self { 22 | NewRoundReason::QCReady => write!(f, "QCReady"), 23 | NewRoundReason::Timeout { cert } => write!(f, "{}", cert), 24 | } 25 | } 26 | } 27 | 28 | /// NewRoundEvents produced by Pacemaker are guaranteed to be monotonically increasing. 29 | /// NewRoundEvents are consumed by the rest of the system: they can cause sending new proposals 30 | /// or voting for some proposals that wouldn't have been voted otherwise. 31 | /// The duration is populated for debugging and testing 32 | #[derive(Debug, PartialEq, Eq)] 33 | pub struct NewRoundEvent { 34 | pub round: Round, 35 | pub reason: NewRoundReason, 36 | pub timeout: Duration, 37 | } 38 | 39 | impl fmt::Display for NewRoundEvent { 40 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 41 | write!( 42 | f, 43 | "NewRoundEvent: [round: {}, reason: {}, timeout: {:?}]", 44 | self.round, self.reason, self.timeout 45 | ) 46 | } 47 | } 48 | 49 | /// Determines the maximum round duration based on the round difference between the current 50 | /// round and the committed round 51 | pub trait PacemakerTimeInterval: Send + Sync + 'static { 52 | /// Use the index of the round after the highest quorum certificate to commit a block and 53 | /// return the duration for this round 54 | /// 55 | /// Round indices start at 0 (round index = 0 is the first round after the round that led 56 | /// to the highest committed round). Given that round r is the highest round to commit a 57 | /// block, then round index 0 is round r+1. Note that for genesis does not follow the 58 | /// 3-chain rule for commits, so round 1 has round index 0. For example, if one wants 59 | /// to calculate the round duration of round 6 and the highest committed round is 3 (meaning 60 | /// the highest round to commit a block is round 5, then the round index is 0. 61 | fn get_round_duration(&self, round_index_after_committed_qc: usize) -> Duration; 62 | } 63 | 64 | /// Round durations increase exponentially 65 | /// Basically time interval is base * mul^power 66 | /// Where power=max(rounds_since_qc, max_exponent) 67 | #[derive(Clone)] 68 | pub struct ExponentialTimeInterval { 69 | // Initial time interval duration after a successful quorum commit. 70 | base_ms: u64, 71 | // By how much we increase interval every time 72 | exponent_base: f64, 73 | // Maximum time interval won't exceed base * mul^max_pow. 74 | // Theoretically, setting it means 75 | // that we rely on synchrony assumptions when the known max messaging delay is 76 | // max_interval. Alternatively, we can consider using max_interval to meet partial synchrony 77 | // assumptions where while delta is unknown, it is <= max_interval. 78 | max_exponent: usize, 79 | } 80 | 81 | impl ExponentialTimeInterval { 82 | #[cfg(any(test, feature = "fuzzing"))] 83 | pub fn fixed(duration: Duration) -> Self { 84 | Self::new(duration, 1.0, 0) 85 | } 86 | 87 | pub fn new(base: Duration, exponent_base: f64, max_exponent: usize) -> Self { 88 | assert!( 89 | max_exponent < 32, 90 | "max_exponent for PacemakerTimeInterval should be <32" 91 | ); 92 | assert!( 93 | exponent_base.powf(max_exponent as f64).ceil() < f64::from(std::u32::MAX), 94 | "Maximum interval multiplier should be less then u32::Max" 95 | ); 96 | ExponentialTimeInterval { 97 | base_ms: base.as_millis() as u64, // any reasonable ms timeout fits u64 perfectly 98 | exponent_base, 99 | max_exponent, 100 | } 101 | } 102 | } 103 | 104 | impl PacemakerTimeInterval for ExponentialTimeInterval { 105 | fn get_round_duration(&self, round_index_after_committed_qc: usize) -> Duration { 106 | let pow = round_index_after_committed_qc.min(self.max_exponent) as u32; 107 | let base_multiplier = self.exponent_base.powf(f64::from(pow)); 108 | let duration_ms = ((self.base_ms as f64) * base_multiplier).ceil() as u64; 109 | Duration::from_millis(duration_ms) 110 | } 111 | } 112 | 113 | /// `Pacemaker` is a Pacemaker implementation that relies on increasing local timeouts 114 | /// in order to eventually come up with the timeout that is large enough to guarantee overlap of the 115 | /// "current round" of multiple participants. 116 | /// 117 | /// The protocol is as follows: 118 | /// * `Pacemaker` manages the `highest_certified_round` that is keeping the round of the 119 | /// highest certified block known to the validator. 120 | /// * Once a new QC arrives with a round larger than that of `highest_certified_round`, 121 | /// local pacemaker is going to increment a round with a default timeout. 122 | /// * Upon every timeout `Pacemaker` increments a round and doubles the timeout. 123 | /// 124 | /// `Pacemaker` does not require clock synchronization to maintain the property of 125 | /// liveness - although clock synchronization can improve the time necessary to get a large enough 126 | /// timeout overlap. 127 | /// It does rely on an assumption that when an honest replica receives a quorum certificate 128 | /// indicating to move to the next round, all other honest replicas will move to the next round 129 | /// within a bounded time. This can be guaranteed via all honest replicas gossiping their highest 130 | /// QC to f+1 other replicas for instance. 131 | pub struct Pacemaker { 132 | // Determines the time interval for a round interval 133 | time_interval: Box, 134 | // Highest round that a block was committed 135 | highest_committed_round: Round, 136 | // Highest round known certified by QC. 137 | highest_qc_round: Round, 138 | // Current round (current_round - highest_qc_round determines the timeout). 139 | // Current round is basically max(highest_qc_round, highest_received_tc, highest_local_tc) + 1 140 | // update_current_round take care of updating current_round and sending new round event if 141 | // it changes 142 | current_round: Round, 143 | // Approximate deadline when current round ends 144 | current_round_deadline: Instant, 145 | // Service for timer 146 | time_service: Arc, 147 | // To send timeout events to other pacemakers 148 | timeout_sender: channel::Sender, 149 | // Manages the PacemakerTimeout and PacemakerTimeoutCertificate structs 150 | pacemaker_timeout_manager: PacemakerTimeoutManager, 151 | } 152 | 153 | impl Pacemaker { 154 | pub fn new( 155 | persistent_liveness_storage: Box, 156 | time_interval: Box, 157 | time_service: Arc, 158 | timeout_sender: channel::Sender, 159 | highest_timeout_certificate: HighestTimeoutCertificates, 160 | ) -> Self { 161 | // Our counters are initialized via lazy_static, so they're not going to appear in 162 | // Prometheus if some conditions never happen. Invoking get() function enforces creation. 163 | counters::QC_ROUNDS_COUNT.get(); 164 | counters::TIMEOUT_ROUNDS_COUNT.get(); 165 | counters::TIMEOUT_COUNT.get(); 166 | 167 | Self { 168 | time_interval, 169 | highest_committed_round: 0, 170 | highest_qc_round: 0, 171 | current_round: 0, 172 | current_round_deadline: Instant::now(), 173 | time_service, 174 | timeout_sender, 175 | pacemaker_timeout_manager: PacemakerTimeoutManager::new( 176 | highest_timeout_certificate, 177 | persistent_liveness_storage, 178 | ), 179 | } 180 | } 181 | 182 | /// Setup the timeout task and return the duration of the current timeout 183 | fn setup_timeout(&mut self) -> Duration { 184 | let timeout_sender = self.timeout_sender.clone(); 185 | let timeout = self.setup_deadline(); 186 | // Note that the timeout should not be driven sequentially with any other events as it can 187 | // become the head of the line blocker. 188 | trace!( 189 | "Scheduling timeout of {} ms for round {}", 190 | timeout.as_millis(), 191 | self.current_round 192 | ); 193 | self.time_service 194 | .run_after(timeout, SendTask::make(timeout_sender, self.current_round)); 195 | timeout 196 | } 197 | 198 | /// Setup the current round deadline and return the duration of the current round 199 | fn setup_deadline(&mut self) -> Duration { 200 | let round_index_after_committed_round = { 201 | if self.highest_committed_round == 0 { 202 | // Genesis doesn't require the 3-chain rule for commit, hence start the index at 203 | // the round after genesis. 204 | self.current_round - 1 205 | } else if self.current_round < self.highest_committed_round + 3 { 206 | 0 207 | } else { 208 | self.current_round - self.highest_committed_round - 3 209 | } 210 | } as usize; 211 | let timeout = self 212 | .time_interval 213 | .get_round_duration(round_index_after_committed_round); 214 | let now = Instant::now(); 215 | debug!( 216 | "{:?} passed since the previous deadline.", 217 | now.checked_duration_since(self.current_round_deadline) 218 | .map_or("0 ms".to_string(), |v| format!("{:?}", v)) 219 | ); 220 | debug!("Set round deadline to {:?} from now", timeout); 221 | self.current_round_deadline = now + timeout; 222 | timeout 223 | } 224 | 225 | /// Attempts to update highest_qc_certified_round when receiving QC for given round. 226 | /// Returns true if highest_qc_certified_round of this pacemaker has changed 227 | fn update_highest_qc_round(&mut self, round: Round) { 228 | if round > self.highest_qc_round { 229 | debug!( 230 | "{}QuorumCertified at {}{}", 231 | Fg(LightBlack), 232 | round, 233 | Fg(Reset) 234 | ); 235 | self.highest_qc_round = round; 236 | } 237 | } 238 | 239 | /// Combines highest_qc_certified_round, highest_local_tc and highest_received_tc into 240 | /// effective round of this pacemaker. 241 | /// Generates new_round event if effective round changes and ensures it is 242 | /// monotonically increasing 243 | fn update_current_round(&mut self) -> Option { 244 | let (mut best_round, mut best_reason) = (self.highest_qc_round, NewRoundReason::QCReady); 245 | if let Some(highest_timeout_certificate) = 246 | self.pacemaker_timeout_manager.highest_timeout_certificate() 247 | { 248 | if highest_timeout_certificate.round() > best_round { 249 | best_round = highest_timeout_certificate.round(); 250 | best_reason = NewRoundReason::Timeout { 251 | cert: highest_timeout_certificate.clone(), 252 | }; 253 | } 254 | } 255 | 256 | let new_round = best_round + 1; 257 | if self.current_round == new_round { 258 | return None; 259 | } 260 | assert!( 261 | new_round > self.current_round, 262 | "Round illegally decreased from {} to {}", 263 | self.current_round, 264 | new_round 265 | ); 266 | self.current_round = new_round; 267 | let timeout = self.setup_timeout(); 268 | Some(NewRoundEvent { 269 | round: self.current_round, 270 | reason: best_reason, 271 | timeout, 272 | }) 273 | } 274 | 275 | /// Validate timeout certificate and update local state if it's correct 276 | fn check_and_update_highest_received_tc(&mut self, tc: Option<&PacemakerTimeoutCertificate>) { 277 | if let Some(tc) = tc { 278 | self.pacemaker_timeout_manager 279 | .update_highest_received_timeout_certificate(tc); 280 | } 281 | } 282 | 283 | /// Returns deadline for current round 284 | pub fn current_round_deadline(&self) -> Instant { 285 | self.current_round_deadline 286 | } 287 | 288 | /// Synchronous function to return the current round. 289 | pub fn current_round(&self) -> Round { 290 | self.current_round 291 | } 292 | 293 | /// Return a optional reference to the highest timeout certificate (locally generated or 294 | /// remotely received) 295 | pub fn highest_timeout_certificate(&self) -> Option { 296 | self.pacemaker_timeout_manager 297 | .highest_timeout_certificate() 298 | .cloned() 299 | } 300 | 301 | /// Function to update current round based on received certificates. 302 | /// Both round of latest received QC and timeout certificates are taken into account. 303 | /// This function guarantees to update pacemaker state when promise that it returns is fulfilled 304 | pub fn process_certificates( 305 | &mut self, 306 | qc_round: Round, 307 | highest_committed_round: Option, 308 | timeout_certificate: Option<&PacemakerTimeoutCertificate>, 309 | ) -> Option { 310 | self.check_and_update_highest_received_tc(timeout_certificate); 311 | self.update_highest_qc_round(qc_round); 312 | match highest_committed_round { 313 | Some(commit_round) if (commit_round > self.highest_committed_round) => { 314 | self.highest_committed_round = commit_round; 315 | } 316 | _ => (), 317 | } 318 | self.update_current_round() 319 | } 320 | 321 | /// The function is invoked upon receiving a remote timeout message from another validator. 322 | pub fn process_remote_timeout( 323 | &mut self, 324 | pacemaker_timeout: PacemakerTimeout, 325 | validator_verifier: Arc, 326 | ) -> Option { 327 | if self 328 | .pacemaker_timeout_manager 329 | .update_received_timeout(pacemaker_timeout, validator_verifier) 330 | { 331 | self.update_current_round() 332 | } else { 333 | None 334 | } 335 | } 336 | 337 | /// To process the local round timeout triggered by TimeService and return whether it's the 338 | /// current round. 339 | pub fn process_local_timeout(&mut self, round: Round) -> bool { 340 | if round != self.current_round { 341 | return false; 342 | } 343 | warn!( 344 | "Round {} has timed out, broadcasting new round message to all replicas", 345 | round 346 | ); 347 | counters::TIMEOUT_COUNT.inc(); 348 | self.setup_timeout(); 349 | true 350 | } 351 | } 352 | 353 | ``` 354 | 355 | 356 | 357 | 358 | 359 | ## 值得一提的是: 360 | 361 | Libra对proposer如何选取提供了多种方式,并且有一个开放的态度。这一部分非常模块化与可插拔。 362 | 363 | ```rust 364 | pub trait ProposerElection { 365 | /// If a given author is a valid candidate for being a proposer, generate the info, 366 | /// otherwise return None. 367 | /// Note that this function is synchronous. 368 | fn is_valid_proposer(&self, author: Author, round: Round) -> Option; 369 | 370 | /// Return all the possible valid proposers for a given round (this information can be 371 | /// used by e.g., voters for choosing the destinations for sending their votes to). 372 | fn get_valid_proposers(&self, round: Round) -> Vec; 373 | 374 | /// Notify proposer election about a new proposal. The function doesn't return any information: 375 | /// proposer election is going to notify the client about the chosen proposal via a dedicated 376 | /// channel (to be passed in constructor). 377 | fn process_proposal(&mut self, proposal: Block) -> Option>; 378 | 379 | /// Take the highest ranked backup proposal if available for a given round 380 | /// (removes it from the struct), 381 | /// or returns None if no proposals have been received for a given round. 382 | /// A backup proposal is a valid proposal that was not chosen immediately in the 383 | /// `process_proposal()` return value. 384 | /// 385 | /// Note that once the backup proposal is taken and no other proposals are submitted, the 386 | /// following take requests are going to return None. 387 | fn take_backup_proposal(&mut self, round: Round) -> Option>; 388 | } 389 | 390 | ``` 391 | 392 | **这段代码中定义了一个trait,来规范所有的election的机制。只要实现了这4个函数,就可以被用作决定proposer的一种可能机制。Libra还提供了几种可行的机制,比如说rotating_proposer_election和multi_proposer_election。** -------------------------------------------------------------------------------- /consensus/SMR/SMR.md: -------------------------------------------------------------------------------- 1 | # SMR 2 | 3 | ## Start: 4 | 5 | ```rust 6 | //SMRstart的代码,总体来看他完成了一系列功能:开启了network,同步到root,创建了block_store,proposal_generator, safety_rules,pacemaker , event_processor。SMR是用一种 event based fashion的机制工作的,在这里面,eventProcess就负责处理event们, It is exposing the async processing functions for each event type. 7 | 8 | impl StateMachineReplication for ChainedBftSMR { 9 | type Payload = T; 10 | 11 | fn start( 12 | &mut self, 13 | txn_manager: Arc>, 14 | state_computer: Arc>, 15 | ) -> Result<()> { 16 | let executor = self 17 | .runtime 18 | .as_mut() 19 | .expect("Consensus start: No valid runtime found!") 20 | .executor(); 21 | let time_service = Arc::new(ClockTimeService::new(executor.clone())); 22 | 23 | // We first start the network and retrieve the network receivers (this function needs a 24 | // mutable reference). 25 | // Must do it here before giving the clones of network to other components. 26 | let network_receivers = self.network.start(&executor); 27 | let initial_data = self 28 | .initial_data 29 | .take() 30 | .expect("already started, initial data is None"); 31 | let consensus_state = initial_data.state(); 32 | let highest_timeout_certificates = initial_data.highest_timeout_certificates().clone(); 33 | if initial_data.need_sync() { 34 | loop { 35 | // make sure we sync to the root state in case we're not 36 | let status = block_on(state_computer.sync_to(initial_data.root_ledger_info())); 37 | match status { 38 | Ok(SyncStatus::Finished) => break, 39 | Ok(SyncStatus::DownloadFailed) => { 40 | warn!("DownloadFailed, we may not establish connection with peers yet, sleep and retry"); 41 | // we can remove this when we start to handle NewPeer/LostPeer events. 42 | thread::sleep(Duration::from_secs(2)); 43 | } 44 | Ok(e) => panic!( 45 | "state synchronizer failure: {:?}, this validator will be killed as it can not \ 46 | recover from this error. After the validator is restarted, synchronization will \ 47 | be retried.", 48 | e 49 | ), 50 | Err(e) => panic!( 51 | "state synchronizer failure: {:?}, this validator will be killed as it can not \ 52 | recover from this error. After the validator is restarted, synchronization will \ 53 | be retried.", 54 | e 55 | ), 56 | } 57 | } 58 | } 59 | 60 | let block_store = Arc::new(block_on(BlockStore::new( 61 | Arc::clone(&self.storage), 62 | initial_data, 63 | self.signer.clone(), 64 | Arc::clone(&state_computer), 65 | true, 66 | self.config.max_pruned_blocks_in_mem, 67 | ))); 68 | self.block_store = Some(Arc::clone(&block_store)); 69 | 70 | // txn manager is required both by proposal generator (to pull the proposers) 71 | // and by event processor (to update their status). 72 | let proposal_generator = ProposalGenerator::new( 73 | block_store.clone(), 74 | Arc::clone(&txn_manager), 75 | time_service.clone(), 76 | self.config.max_block_size, 77 | true, 78 | ); 79 | 80 | let safety_rules = Arc::new(RwLock::new(SafetyRules::new( 81 | block_store.clone(), 82 | consensus_state, 83 | ))); 84 | 85 | let (external_timeout_sender, external_timeout_receiver) = 86 | channel::new(1_024, &counters::PENDING_PACEMAKER_TIMEOUTS); 87 | let (new_round_events_sender, new_round_events_receiver) = 88 | channel::new(1_024, &counters::PENDING_NEW_ROUND_EVENTS); 89 | let pacemaker = self.create_pacemaker( 90 | executor.clone(), 91 | self.storage.persistent_liveness_storage(), 92 | safety_rules.read().unwrap().last_committed_round(), 93 | block_store.highest_certified_block().round(), 94 | highest_timeout_certificates, 95 | time_service.clone(), 96 | new_round_events_sender, 97 | external_timeout_sender, 98 | ); 99 | 100 | let (winning_proposals_sender, winning_proposals_receiver) = 101 | channel::new(1_024, &counters::PENDING_WINNING_PROPOSALS); 102 | let proposer_election = self.create_proposer_election(winning_proposals_sender); 103 | let event_processor = Arc::new(futures_locks::RwLock::new(EventProcessor::new( 104 | self.author, 105 | Arc::clone(&block_store), 106 | Arc::clone(&pacemaker), 107 | Arc::clone(&proposer_election), 108 | proposal_generator, 109 | safety_rules, 110 | state_computer, 111 | txn_manager, 112 | self.network.clone(), 113 | Arc::clone(&self.storage), 114 | time_service.clone(), 115 | true, 116 | ))); 117 | 118 | self.start_event_processing( 119 | event_processor, 120 | executor.clone(), 121 | new_round_events_receiver, 122 | winning_proposals_receiver, 123 | network_receivers, 124 | external_timeout_receiver, 125 | ); 126 | 127 | debug!("Chained BFT SMR started."); 128 | Ok(()) 129 | } 130 | 131 | ``` 132 | 133 | ## 几个模块:将分别介绍 134 | 135 | - **BlockStore** maintains the tree of proposal blocks, block execution, votes, quorum certificates, and persistent storage. It is responsible for maintaining the consistency of the combination of these data structures and can be concurrently accessed by other subcomponents. 136 | - **EventProcessor** is responsible for processing the individual events (e.g., process_new_round, process_proposal, process_vote). It exposes the async processing functions for each event type and drives the protocol 137 | - **Pacemaker** is responsible for the liveness of the consensus protocol. It changes rounds due to timeout certificates or quorum certificates and proposes blocks when it is the proposer for the current round. 138 | - **SafetyRules** is responsible for the safety of the consensus protocol. It processes quorum certificates and LedgerInfo to learn about new commits and guarantees that the two voting rules are followed — even in the case of restart (since all safety data is persisted to local storage). 139 | 140 | 141 | 142 | -------------------------------------------------------------------------------- /consensus/SMR/block_store.md: -------------------------------------------------------------------------------- 1 | # block_store 2 | 3 | ## 代码: 4 | 5 | ####build_block_tree: 6 | 7 | ```rust 8 | 9 | /// Responsible for maintaining all the blocks of payload and the dependencies of those blocks 10 | /// (parent and previous QC links). It is expected to be accessed concurrently by multiple threads 11 | /// and is thread-safe. 12 | /// 13 | /// Example tree block structure based on parent links. 14 | /// | -> A3 15 | /// Genesis -> B0 -> B1 -> B2 -> B3 16 | /// | -> C1 -> C2 17 | /// | -> D3 18 | /// 19 | /// Example corresponding tree block structure for the QC links (must follow QC constraints). 20 | /// | -> A3 21 | /// Genesis -> B0 -> B1 -> B2 -> B3 22 | /// | -> C1 23 | /// | -------> C2 24 | /// | -------------> D3 25 | pub struct BlockStore { 26 | inner: Arc>>, 27 | validator_signer: ValidatorSigner, 28 | state_computer: Arc>, 29 | enforce_increasing_timestamps: bool, 30 | /// The persistent storage backing up the in-memory data structure, every write should go 31 | /// through this before in-memory tree. 32 | storage: Arc>, 33 | } 34 | 35 | async fn build_block_tree( 36 | root: (Block, QuorumCert, QuorumCert),//选择根 37 | blocks: Vec>,///block们 38 | quorum_certs: Vec,//QCs 39 | state_computer: Arc>, 40 | max_pruned_blocks_in_mem: usize, 41 | ) -> BlockTree { 42 | let mut tree = BlockTree::new(root.0, root.1, root.2, max_pruned_blocks_in_mem); 43 | let quorum_certs = quorum_certs 44 | .into_iter() 45 | .map(|qc| (qc.certified_block_id(), qc)) 46 | .collect::>();//吧QCs转化成一个hashmap便于查找 47 | for block in blocks { 48 | let compute_res = state_computer 49 | .compute(block.parent_id(), block.id(), block.get_payload()) 50 | .await 51 | .expect("fail to rebuild scratchpad"); 52 | let version = tree 53 | .get_state_for_block(block.parent_id()) 54 | .expect("parent state does not exist") 55 | .version 56 | + compute_res.num_successful_txns; 57 | let executed_state = ExecutedState {//根据state_computer的计算结果生成excuted_state 58 | state_id: compute_res.new_state_id, 59 | version, 60 | }; 61 | // if this block is certified, ensure we agree with the certified state. 62 | if let Some(qc) = quorum_certs.get(&block.id()) { 63 | assert_eq!( 64 | qc.certified_state(), 65 | executed_state, 66 | "We have inconsistent executed state with Quorum Cert for block {}", 67 | block.id() 68 | ); 69 | } 70 | tree.insert_block(block, executed_state, compute_res) 71 | .expect("Block insertion failed while build the tree"); 72 | } 73 | quorum_certs.into_iter().for_each(|(_, qc)| { 74 | tree.insert_quorum_cert(qc) 75 | .expect("QuorumCert insertion failed while build the tree") 76 | }); 77 | tree 78 | } 79 | ``` 80 | 81 | ####execute_and_insert_block: 82 | 83 | ```rust 84 | /// Execute and insert a block if it passes all validation tests. 85 | /// Returns the Arc to the block kept in the block store after persisting it to storage 86 | /// 87 | /// This function assumes that the ancestors are present (returns MissingParent otherwise). 88 | /// 89 | /// Duplicate inserts will return the previously inserted block ( 90 | /// note that it is considered a valid non-error case, for example, it can happen if a validator 91 | /// receives a certificate for a block that is currently being added). 92 | pub async fn execute_and_insert_block( 93 | &self, 94 | block: Block, 95 | ) -> Result>, InsertError> { 96 | if let Some(existing_block) = self.inner.read().unwrap().get_block(block.id()) { 97 | return Ok(existing_block); 98 | } 99 | let (parent_id, parent_exec_version) = match self.verify_and_get_parent_info(&block) { 100 | Ok(t) => t, 101 | Err(e) => { 102 | security_log(SecurityEvent::InvalidBlock) 103 | .error(&e) 104 | .data(&block) 105 | .log(); 106 | return Err(e); 107 | } 108 | }; 109 | let compute_res = self 110 | .state_computer 111 | .compute(parent_id, block.id(), block.get_payload()) 112 | .await 113 | .map_err(|e| { 114 | error!("Execution failure for block {}: {:?}", block, e); 115 | InsertError::StateComputerError 116 | })?; 117 | 118 | let version = parent_exec_version + compute_res.num_successful_txns; 119 | 120 | let state = ExecutedState { 121 | state_id: compute_res.new_state_id, 122 | version, 123 | }; 124 | self.storage 125 | .save_tree(vec![block.clone()], vec![]) 126 | .map_err(|_| InsertError::StorageFailure)?;// 加入storage 127 | self.inner 128 | .write() 129 | .unwrap() 130 | .insert_block(block, state, compute_res)//insert 131 | .map_err(|e| e.into()) 132 | } 133 | ``` 134 | 135 | #### 关于QC的一些判断: 136 | 137 | ```rust 138 | /// Check if we're far away from this ledger info and need to sync. 139 | /// Returns false if we have this block in the tree or the root's round is higher than the 140 | /// block. 141 | pub fn need_sync_for_quorum_cert( 142 | &self, 143 | committed_block_id: HashValue, 144 | qc: &QuorumCert, 145 | ) -> bool { 146 | // LedgerInfo doesn't carry the information about the round of the committed block. However, 147 | // the 3-chain safety rules specify that the round of the committed block must be 148 | // certified_block_round() - 2. In case root().round() is greater than that the committed 149 | // block carried by LI is older than my current commit. 150 | !(self.block_exists(committed_block_id) 151 | || self.root().round() + 2 >= qc.certified_block_round())//后一个是说被committed 的block在root之前,前一个是说这个QC已经在树中了,也就是之前已经committed过了 152 | } 153 | 154 | /// Checks if quorum certificate can be inserted in block store without RPC 155 | /// Returns the enum to indicate the detailed status. 156 | pub fn need_fetch_for_quorum_cert(&self, qc: &QuorumCert) -> NeedFetchResult { 157 | if qc.certified_block_round() < self.root().round() { 158 | return NeedFetchResult::QCRoundBeforeRoot; 159 | } 160 | if self 161 | .get_quorum_cert_for_block(qc.certified_block_id()) 162 | .is_some() 163 | { 164 | return NeedFetchResult::QCAlreadyExist; 165 | } 166 | if self.block_exists(qc.certified_block_id()) { 167 | return NeedFetchResult::QCBlockExist; 168 | } 169 | NeedFetchResult::NeedFetch 170 | } 171 | 172 | ``` 173 | 174 | #### 插入QC和插入vote: 175 | 176 | ```rust 177 | /// Validates quorum certificates and inserts it into block tree assuming dependencies exist. 178 | pub async fn insert_single_quorum_cert(&self, qc: QuorumCert) -> Result<(), InsertError> { 179 | // Ensure executed state is consistent with Quorum Cert, otherwise persist the quorum's 180 | // state and hopefully we restart and agree with it. 181 | let executed_state = self 182 | .get_state_for_block(qc.certified_block_id()) 183 | .ok_or_else(|| InsertError::MissingParentBlock(qc.certified_block_id()))?; 184 | assert_eq!( 185 | executed_state, 186 | qc.certified_state(), 187 | "We have inconsistent executed state with the executed state from the quorum \ 188 | certificate for block {}, will kill this validator and rely on state synchronization \ 189 | to try to achieve consistent state with the quorum certificate.", 190 | qc.certified_block_id(), 191 | ); 192 | self.storage 193 | .save_tree(vec![], vec![qc.clone()]) 194 | .map_err(|_| InsertError::StorageFailure)?; 195 | self.inner 196 | .write() 197 | .unwrap() 198 | .insert_quorum_cert(qc) 199 | .map_err(|e| e.into()) 200 | } 201 | 202 | /// Adds a vote for the block. 203 | /// The returned value either contains the vote result (with new / old QC etc.) or a 204 | /// verification error. 205 | /// A block store does not verify that the block, which is voted for, is present locally. 206 | /// It returns QC, if it is formed, but does not insert it into block store, because it might 207 | /// not have required dependencies yet 208 | /// Different execution ids are treated as different blocks (e.g., if some proposal is 209 | /// executed in a non-deterministic fashion due to a bug, then the votes for execution result 210 | /// A and the votes for execution result B are aggregated separately). 211 | pub async fn insert_vote( 212 | &self, 213 | vote_msg: VoteMsg, 214 | min_votes_for_qc: usize, 215 | ) -> VoteReceptionResult { 216 | self.inner 217 | .write() 218 | .unwrap() 219 | .insert_vote(&vote_msg, min_votes_for_qc) 220 | } 221 | ``` 222 | 223 | #### prune the tree:修建tree,给树换根 224 | 225 | ```rust 226 | /// Prune the tree up to next_root_id (keep next_root_id's block). Any branches not part of 227 | /// the next_root_id's tree should be removed as well. 228 | /// 229 | /// For example, root = B_0 230 | /// B_0 -> B_1 -> B_2 231 | /// | -> B_3 -> B4 232 | /// 233 | /// prune_tree(B_3) should be left with 234 | /// B_3 -> B_4, root = B_3 235 | /// 236 | /// Returns the block ids of the blocks removed. 237 | pub async fn prune_tree(&self, next_root_id: HashValue) -> VecDeque { 238 | let id_to_remove = self 239 | .inner 240 | .read() 241 | .unwrap() 242 | .find_blocks_to_prune(next_root_id); 243 | if let Err(e) = self 244 | .storage 245 | .prune_tree(id_to_remove.clone().into_iter().collect()) 246 | { 247 | // it's fine to fail here, as long as the commit succeeds, the next restart will clean 248 | // up dangling blocks, and we need to prune the tree to keep the root consistent with 249 | // executor. 250 | error!("fail to delete block: {:?}", e); 251 | } 252 | self.inner 253 | .write() 254 | .unwrap() 255 | .process_pruned_blocks(next_root_id, id_to_remove.clone()); 256 | id_to_remove 257 | } 258 | ``` 259 | 260 | #### verify_and_get_parent_info,ledger_info_placeholder等如名称所示。返回block parent的信息以及自己的信息 261 | 262 | -------------------------------------------------------------------------------- /consensus/SMR/safety_rules.md: -------------------------------------------------------------------------------- 1 | # safety_rules 2 | 3 | **关于safety_rules ,Libra官方的关于LibraBFT的论文中有详细论述,这一部分对外提供各种接口,用于安全的voting和committng,这一部分比较清楚,里面实现的逻辑就是论文里提到的逻辑,如果理解起来又困难可以看Libra-BFT的论文。** 4 | 5 | ```rust 6 | /// SafetyRules is responsible for two things that are critical for the safety of the consensus: 7 | /// 1) voting rules, 8 | /// 2) commit rules. 9 | /// SafetyRules is NOT THREAD SAFE (should be protected outside via e.g., RwLock). 10 | /// The commit decisions are returned to the caller as result of learning about a new QuorumCert. 11 | pub struct SafetyRules { 12 | // Keeps the state. 13 | state: ConsensusState, 14 | } 15 | 16 | impl SafetyRules { 17 | /// Constructs a new instance of SafetyRules given the BlockTree and ConsensusState. 18 | pub fn new(state: ConsensusState) -> Self { 19 | Self { state } 20 | } 21 | 22 | /// Learn about a new quorum certificate. Several things can happen as a result of that: 23 | /// 1) update the preferred block to a higher value. 24 | /// 2) commit some blocks. 25 | /// In case of commits the last committed block is returned. 26 | /// Requires that all the ancestors of the block are available for at least up to the last committed block, might panic otherwise. 27 | /// The update function is invoked whenever a system learns about a potentially high QC. 28 | ///当收到一个可能更高round的QC的时候,会调用这个 29 | pub fn update(&mut self, qc: &QuorumCert) { 30 | // Preferred block rule: choose the highest 2-chain head. 31 | if qc.parent_block_round() > self.state.preferred_block_round() { 32 | self.state 33 | .set_preferred_block_round(qc.parent_block_round()); 34 | } 35 | } 36 | 37 | /// Check if a one-chain at round r+2 causes a commit at round r and return the committed 38 | /// block id at round r if possible 39 | ///收到了一个QC,要commit之前某个block,这里就规定了commit哪个 40 | fn commit_rule_for_certified_block( 41 | &self, 42 | block_parent_qc: &QuorumCert, 43 | block_round: u64, 44 | ) -> Option { 45 | // We're using a so-called 3-chain commit rule: B0 (as well as its prefix) 46 | // can be committed if there exist certified blocks B1 and B2 that satisfy: 47 | // 1) B0 <- B1 <- B2 <-- 48 | // 2) round(B0) + 1 = round(B1), and 49 | // 3) round(B1) + 1 = round(B2). 50 | 51 | if block_parent_qc.parent_block_round() + 1 == block_parent_qc.certified_block_round() 52 | && block_parent_qc.certified_block_round() + 1 == block_round 53 | { 54 | return Some(block_parent_qc.parent_block_id()); 55 | } 56 | None 57 | } 58 | 59 | /// Clones the up-to-date state of consensus (for monitoring / debugging purposes) 60 | pub fn consensus_state(&self) -> ConsensusState { 61 | self.state.clone() 62 | } 63 | 64 | /// Attempts to vote for a given proposal following the voting rules. 65 | /// The returned value is then going to be used for either sending the vote or doing nothing. 66 | /// In case of a vote a cloned consensus state is returned (to be persisted before the vote is 67 | /// sent). 68 | /// Requires that all the ancestors of the block are available for at least up to the last 69 | /// committed block, might panic otherwise. 70 | ///这里决定是不是要为收到的块vote 71 | pub fn voting_rule( 72 | &mut self, 73 | proposed_block: &Block, 74 | ) -> Result { 75 | if proposed_block.round() <= self.state.last_vote_round() { 76 | return Err(ProposalReject::OldProposal { 77 | proposal_round: proposed_block.round(), 78 | last_vote_round: self.state.last_vote_round(), 79 | }); 80 | } 81 | 82 | let respects_preferred_block = proposed_block.quorum_cert().certified_block_round() 83 | >= self.state.preferred_block_round(); 84 | if respects_preferred_block { 85 | self.state.set_last_vote_round(proposed_block.round()); 86 | 87 | // If the vote for the given proposal is gathered into QC, then this QC might eventually 88 | // commit another block following the rules defined in 89 | // `commit_rule_for_certified_block()` function. 90 | let potential_commit_id = self.commit_rule_for_certified_block( 91 | proposed_block.quorum_cert(), 92 | proposed_block.round(), 93 | ); 94 | 95 | Ok(VoteInfo { 96 | proposal_id: proposed_block.id(), 97 | proposal_round: proposed_block.round(), 98 | consensus_state: self.state.clone(), 99 | potential_commit_id, 100 | parent_block_id: proposed_block.quorum_cert().certified_block_id(), 101 | parent_block_round: proposed_block.quorum_cert().certified_block_round(), 102 | }) 103 | } else { 104 | Err(ProposalReject::ProposalRoundLowerThenPreferredBlock { 105 | preferred_block_round: self.state.preferred_block_round(), 106 | }) 107 | } 108 | } 109 | } 110 | 111 | ``` 112 | 113 | -------------------------------------------------------------------------------- /consensus/SMR/sync_manager.md: -------------------------------------------------------------------------------- 1 | #sync_managers 2 | 3 | ## 代码: 4 | 5 | #### 定义 6 | 7 | ```rust 8 | ////syncManager 就是说在validator运行的过程中可能由于网络问题或者自身问题而没有跟上global的合法状态,这时候我们收到了一些gloable的QC或者ledger info,发现我们与全局的进度差很多,为了跟上这些进度,我们需要与其他节点进行同步。现在来说,我们简单的将发送触发这一同步的消息一方作为peer进行同步,以后会有更高级的策略 9 | 10 | /// SyncManager is responsible for fetching dependencies and 'catching up' for given qc/ledger info 11 | pub struct SyncManager { 12 | block_store: Arc>, 13 | storage: Arc>, 14 | network: ConsensusNetworkImpl, 15 | state_computer: Arc>, 16 | block_mutex_map: MutexMap, 17 | } 18 | 19 | /// This struct describes where do we sync to 20 | pub struct SyncInfo { 21 | /// Highest ledger info to invoke state sync for 22 | /// This is optional for now, because vote does not have it 23 | pub highest_ledger_info: QuorumCert, 24 | /// Quorum certificate to be inserted into block tree 25 | pub highest_quorum_cert: QuorumCert, 26 | /// Author of messages that triggered this sync. 27 | /// For now we sync from this peer. In future we going to use peers from quorum certs, 28 | /// and this field going to be mostly informational 29 | pub peer: Author, 30 | } 31 | ///用syncinfo同步 32 | /// Fetches dependencies for given sync_info.quorum_cert 33 | /// If gap is large, performs state sync using process_highest_ledger_info 34 | /// Inserts sync_info.quorum_cert into block store as the last step 35 | pub async fn sync_to(&mut self, deadline: Instant, sync_info: SyncInfo) -> failure::Result<()> { 36 | let highest_ledger_info = sync_info.highest_ledger_info.clone(); 37 | 38 | self.process_highest_ledger_info(highest_ledger_info, sync_info.peer, deadline) 39 | .await?; 40 | 41 | self.fetch_quorum_cert( 42 | sync_info.highest_quorum_cert.clone(), 43 | sync_info.peer, 44 | deadline, 45 | ) 46 | .await?; 47 | Ok(()) 48 | } 49 | 50 | ``` 51 | 52 | #### 两个很简单的函数: 53 | 54 | ```rust 55 | /// Get a chunk of transactions as a batch 56 | pub async fn get_chunk( 57 | &self, 58 | start_version: u64, 59 | target_version: u64, 60 | batch_size: u64, 61 | ) -> failure::Result { 62 | self.state_computer 63 | .get_chunk(start_version, target_version, batch_size) 64 | .await 65 | } 66 | 67 | pub async fn execute_and_insert_block( 68 | &self, 69 | block: Block, 70 | ) -> Result>, InsertError> { 71 | let _guard = self.block_mutex_map.lock(block.id()); 72 | // execute_and_insert_block has shortcut to return block if it exists 73 | self.block_store.execute_and_insert_block(block).await 74 | } 75 | ``` 76 | 77 | #### sync_to中使用的两个核心函数: 78 | 79 | ```rust 80 | //fetch_quorum_cert的意思很简单,就是给定了一个QC,我们开始获取这个QC之前缺失的块,函数里的loop循环就是不断的获取块,把这些块加到pending中,直到获取到了给定的这个QC。这时候就意味着我们已经完成了同步的依赖条件。剩下要做的就是把pending里面的block全部insert进去,最后再insertQC,成功后就结束了。 81 | 82 | /// Insert the quorum certificate separately from the block, used to split the processing of 83 | /// updating the consensus state(with qc) and deciding whether to vote(with block) 84 | /// The missing ancestors are going to be retrieved from the given peer. If a given peer 85 | /// fails to provide the missing ancestors, the qc is not going to be added. 86 | pub async fn fetch_quorum_cert( 87 | &self, 88 | qc: QuorumCert, 89 | preferred_peer: Author, 90 | deadline: Instant, 91 | ) -> Result<(), InsertError> { 92 | let mut lock_set = self.block_mutex_map.new_lock_set(); 93 | let mut pending = vec![]; 94 | let network = self.network.clone(); 95 | let mut retriever = BlockRetriever { 96 | network, 97 | deadline, 98 | preferred_peer, 99 | }; 100 | let mut retrieve_qc = qc.clone(); 101 | loop { 102 | if lock_set 103 | .lock(retrieve_qc.certified_block_id()) 104 | .await 105 | .is_err() 106 | { 107 | // This should not be possible because that would mean we have circular 108 | // dependency between signed blocks 109 | panic!( 110 | "Can not re-acquire lock for block {} during fetch_quorum_cert", 111 | retrieve_qc.certified_block_id() 112 | ); 113 | } 114 | if self 115 | .block_store 116 | .block_exists(retrieve_qc.certified_block_id()) 117 | { 118 | break; 119 | } 120 | let mut blocks = retriever.retrieve_block_for_qc(&retrieve_qc, 1).await?; 121 | // retrieve_block_for_qc guarantees that blocks has exactly 1 element 122 | let block = blocks.remove(0); 123 | retrieve_qc = block.quorum_cert().clone(); 124 | pending.push(block); 125 | } 126 | // insert the qc <- block pair 127 | while let Some(block) = pending.pop() { 128 | let block_qc = block.quorum_cert().clone(); 129 | self.block_store.insert_single_quorum_cert(block_qc).await?; 130 | self.block_store.execute_and_insert_block(block).await?; 131 | } 132 | self.block_store.insert_single_quorum_cert(qc).await 133 | } 134 | 135 | /// Check the highest ledger info sent by peer to see if we're behind and start a fast 136 | /// forward sync if the committed block doesn't exist in our tree. 137 | /// It works as follows: 138 | /// 1. request the committed 3-chain from the peer, if C2 is the highest_ledger_info 139 | /// we request for B0 <- C0 <- B1 <- C1 <- B2 (<- C2) 140 | /// 2. We persist the 3-chain to storage before start sync to ensure we could restart if we 141 | /// crash in the middle of the sync. 142 | /// 3. We prune the old tree and replace with a new tree built with the 3-chain. 143 | //因为我们commit使用的3-chain原则,prune掉前面的和其他branch的节点是没有影响的 144 | async fn process_highest_ledger_info( 145 | &self, 146 | highest_ledger_info: QuorumCert, 147 | peer: Author, 148 | deadline: Instant, 149 | ) -> failure::Result<()> { 150 | let committed_block_id = highest_ledger_info 151 | .committed_block_id() 152 | .ok_or_else(|| format_err!("highest ledger info has no committed block"))?; 153 | if !self 154 | .block_store 155 | .need_sync_for_quorum_cert(committed_block_id, &highest_ledger_info) 156 | { 157 | return Ok(());//不需要同步的话就直接结束 158 | } 159 | debug!( 160 | "Start state sync with peer: {}, to block: {}, round: {} from {}", 161 | peer.short_str(), 162 | committed_block_id, 163 | highest_ledger_info.certified_block_round() - 2, 164 | self.block_store.root() 165 | ); 166 | let network = self.network.clone(); 167 | let mut retriever = BlockRetriever { 168 | network, 169 | deadline, 170 | preferred_peer: peer, 171 | }; 172 | let mut blocks = retriever 173 | .retrieve_block_for_qc(&highest_ledger_info, 3) 174 | .await?; 175 | assert_eq!( 176 | blocks.last().expect("should have 3-chain").id(), 177 | committed_block_id 178 | ); 179 | /// 1. request the committed 3-chain from the peer, if C2 is the highest_ledger_info 180 | /// we request for B0 <- C0 <- B1 <- C1 <- B2 (<- C2) 181 | let mut quorum_certs = vec![]; 182 | quorum_certs.push(highest_ledger_info.clone()); 183 | quorum_certs.push(blocks[0].quorum_cert().clone()); 184 | quorum_certs.push(blocks[1].quorum_cert().clone()); 185 | // If a node restarts in the middle of state synchronization, it is going to try to catch up 186 | // to the stored quorum certs as the new root. 187 | self.storage 188 | .save_tree(blocks.clone(), quorum_certs.clone())?;//存储 189 | let pre_sync_instance = Instant::now(); 190 | match self 191 | .state_computer 192 | .sync_to(highest_ledger_info.clone()) 193 | .await 194 | { 195 | Ok(SyncStatus::Finished) => (), 196 | Ok(e) => panic!( 197 | "state synchronizer failure: {:?}, this validator will be killed as it can not \ 198 | recover from this error. After the validator is restarted, synchronization will \ 199 | be retried.", 200 | e 201 | ), 202 | Err(e) => panic!( 203 | "state synchronizer failure: {:?}, this validator will be killed as it can not \ 204 | recover from this error. After the validator is restarted, synchronization will \ 205 | be retried.", 206 | e 207 | ), 208 | }; 209 | counters::STATE_SYNC_DURATION_MS.observe(pre_sync_instance.elapsed().as_millis() as f64); 210 | let root = ( 211 | blocks.pop().expect("should have 3-chain"), 212 | quorum_certs.last().expect("should have 3-chain").clone(), 213 | highest_ledger_info.clone(), 214 | ); 215 | debug!("{}Sync to{} {}", Fg(Blue), Fg(Reset), root.0); 216 | // ensure it's [b1, b2] 217 | blocks.reverse(); 218 | self.block_store.rebuild(root, blocks, quorum_certs).await;//rebuild,就是prune 219 | Ok(()) 220 | } 221 | } 222 | 223 | ``` 224 | 225 | #### Blockretriever: 226 | 227 | ```rust 228 | //核心功能就是/// Retrieve chain of n blocks for given QC。n和QC是参数 229 | impl BlockRetriever { 230 | /// Retrieve chain of n blocks for given QC 231 | /// 232 | /// Returns Result with Vec that has a guaranteed size of num_blocks 233 | /// This guarantee is based on BlockRetrievalResponse::verify that ensures that number of 234 | /// blocks in response is equal to number of blocks requested. This method will 235 | /// continue until either the round deadline is reached or the quorum certificate members all 236 | /// fail to return the missing chain. 237 | /// 238 | /// The first attempt of block retrieval will always be sent to preferred_peer to allow the 239 | /// leader to drive quorum certificate creation The other peers from the quorum certificate 240 | /// will be randomly tried next. If all members of the quorum certificate are exhausted, an 241 | /// error is returned 242 | pub async fn retrieve_block_for_qc<'a, T>( 243 | &'a mut self, 244 | qc: &'a QuorumCert, 245 | num_blocks: u64, 246 | ) -> Result>, BlockRetrieverError> 247 | where 248 | T: Payload, 249 | { 250 | let block_id = qc.certified_block_id(); 251 | let mut peers: Vec<&AccountAddress> = qc.ledger_info().signatures().keys().collect(); 252 | let mut attempt = 0_u32; 253 | loop { 254 | if peers.is_empty() { 255 | warn!( 256 | "Failed to fetch block {} in {} attempts: no more peers available", 257 | block_id, attempt 258 | ); 259 | return Err(BlockRetrieverError::AllPeersFailed); 260 | } 261 | let peer = self.pick_peer(attempt, &mut peers); 262 | attempt += 1; 263 | 264 | let timeout = retrieval_timeout(&self.deadline, attempt); 265 | let timeout = if let Some(timeout) = timeout { 266 | timeout 267 | } else { 268 | warn!("Failed to fetch block {} from {}, attempt {}: round deadline was reached, won't make more attempts", block_id, peer, attempt); 269 | return Err(BlockRetrieverError::RoundDeadlineReached); 270 | }; 271 | debug!( 272 | "Fetching {} from {}, attempt {}", 273 | block_id, 274 | peer.short_str(), 275 | attempt 276 | ); 277 | let response = self 278 | .network 279 | .request_block(block_id, num_blocks, peer, timeout) 280 | .await; 281 | let response = match response { 282 | Err(e) => { 283 | warn!( 284 | "Failed to fetch block {} from {}: {:?}, trying another peer", 285 | block_id, 286 | peer.short_str(), 287 | e 288 | ); 289 | continue; 290 | } 291 | Ok(response) => response, 292 | }; 293 | if response.status != BlockRetrievalStatus::SUCCEEDED { 294 | warn!( 295 | "Failed to fetch block {} from {}: {:?}, trying another peer", 296 | block_id, 297 | peer.short_str(), 298 | response.status 299 | ); 300 | continue; 301 | } 302 | return Ok(response.blocks); 303 | } 304 | } 305 | 306 | fn pick_peer(&self, attempt: u32, peers: &mut Vec<&AccountAddress>) -> AccountAddress { 307 | assert!(!peers.is_empty(), "pick_peer on empty peer list"); 308 | 309 | if attempt == 0 { 310 | // remove preferred_peer if its in list of peers 311 | // (strictly speaking it is not required to be there) 312 | for i in 0..peers.len() { 313 | if *peers[i] == self.preferred_peer { 314 | peers.remove(i); 315 | break; 316 | } 317 | } 318 | return self.preferred_peer; 319 | } 320 | let peer_idx = thread_rng().gen_range(0, peers.len()); 321 | *peers.remove(peer_idx) 322 | } 323 | } 324 | 325 | ``` 326 | 327 | 328 | 329 | -------------------------------------------------------------------------------- /consensus/State_Computer.md: -------------------------------------------------------------------------------- 1 | # State_Computer 2 | 3 | ## 功能: 4 | 5 | 是consensus模块与execution模块的接口,主要用于: 6 | 7 | - commit block 8 | - execute block 9 | - synchronize state 10 | 11 | ## 代码实现: 12 | 13 | 实现了3个函数,commit,compute与sysn_to,分别代表上面3个功能 14 | 15 | ```rust 16 | /// Basic communication with the Execution module; 17 | /// implements StateComputer traits. 18 | pub struct ExecutionProxy { 19 | executor: Arc>, 20 | synchronizer: Arc, 21 | } 22 | 23 | impl ExecutionProxy { 24 | pub fn new(executor: Arc>, synchronizer: Arc) -> Self { 25 | Self { 26 | executor, 27 | synchronizer, 28 | } 29 | } 30 | } 31 | 32 | impl StateComputer for ExecutionProxy { 33 | type Payload = Vec; 34 | 35 | fn compute( 36 | &self, 37 | // The id of a parent block, on top of which the given transactions should be executed. 38 | parent_block_id: HashValue, 39 | // The id of a current block. 40 | block_id: HashValue, 41 | // Transactions to execute. 42 | transactions: &Self::Payload, 43 | ) -> Pin> + Send>> { 44 | let pre_execution_instant = Instant::now(); 45 | let execute_future = self.executor.execute_block( 46 | transactions 47 | .iter() 48 | .map(|txn| Transaction::UserTransaction(txn.clone())) 49 | .collect(), 50 | parent_block_id, 51 | block_id, 52 | ); 53 | async move { 54 | match execute_future.await { 55 | Ok(Ok(state_compute_result)) => { 56 | let execution_duration = pre_execution_instant.elapsed(); 57 | let num_txns = state_compute_result.compute_status.len(); 58 | if num_txns == 0 { 59 | // no txns in that block 60 | counters::EMPTY_BLOCK_EXECUTION_DURATION_S 61 | .observe_duration(execution_duration); 62 | } else { 63 | counters::BLOCK_EXECUTION_DURATION_S.observe_duration(execution_duration); 64 | if let Ok(nanos_per_txn) = 65 | u64::try_from(execution_duration.as_nanos() / num_txns as u128) 66 | { 67 | // TODO: use duration_float once it's stable 68 | // Tracking: https://github.com/rust-lang/rust/issues/54361 69 | counters::TXN_EXECUTION_DURATION_S 70 | .observe_duration(Duration::from_nanos(nanos_per_txn)); 71 | } 72 | } 73 | Ok(state_compute_result) 74 | } 75 | Ok(Err(e)) => Err(e), 76 | Err(e) => Err(e.into()), 77 | } 78 | } 79 | .boxed() 80 | } 81 | 82 | /// Send a successful commit. A future is fulfilled when the state is finalized. 83 | fn commit( 84 | &self, 85 | commit: LedgerInfoWithSignatures, 86 | ) -> Pin> + Send>> { 87 | let version = commit.ledger_info().version(); 88 | counters::LAST_COMMITTED_VERSION.set(version as i64); 89 | 90 | let pre_commit_instant = Instant::now(); 91 | let synchronizer = Arc::clone(&self.synchronizer); 92 | let commit_future = self.executor.commit_block(commit); 93 | async move { 94 | match commit_future.await { 95 | Ok(Ok(())) => { 96 | counters::BLOCK_COMMIT_DURATION_S 97 | .observe_duration(pre_commit_instant.elapsed()); 98 | if let Err(e) = synchronizer.commit(version).await { 99 | error!("failed to notify state synchronizer: {:?}", e); 100 | } 101 | Ok(()) 102 | } 103 | Ok(Err(e)) => Err(e), 104 | Err(e) => Err(e.into()), 105 | } 106 | } 107 | .boxed() 108 | } 109 | 110 | /// Synchronize to a commit that not present locally. 111 | fn sync_to(&self, commit: QuorumCert) -> Pin> + Send>> { 112 | counters::STATE_SYNC_COUNT.inc(); 113 | self.synchronizer 114 | .sync_to(commit.ledger_info().clone()) 115 | .boxed() 116 | } 117 | } 118 | 119 | ``` 120 | 121 | -------------------------------------------------------------------------------- /consensus/Txn_manager.md: -------------------------------------------------------------------------------- 1 | # Txn_Manager 2 | 3 | ## 功能: 4 | 5 | 是consensus模块与mempool模块的接口,主要用于 6 | 7 | - 当自己是leader的时候pull出一个块来进行propose 8 | - 有block被commit之后,将这个block中的txns都从mempool中删除 9 | 10 | ## 代码实现: 11 | 12 | **代码逻辑非常简单,实现了上面所说的两个功能。** 13 | 14 | ```rust 15 | /// Proxy interface to mempool 16 | pub struct MempoolProxy { 17 | mempool: Arc, 18 | } 19 | 20 | impl MempoolProxy { 21 | pub fn new(mempool: Arc) -> Self { 22 | Self { 23 | mempool: Arc::clone(&mempool), 24 | } 25 | } 26 | 27 | /// Generate mempool commit transactions request given the set of txns and their status 28 | ////这里值得注意的是txn的状态有rejected和not rejected,mempool会根据标注的这个状态来确定txn的去留 29 | fn gen_commit_transactions_request( 30 | txns: &[SignedTransaction], 31 | compute_result: &StateComputeResult, 32 | timestamp_usecs: u64, 33 | ) -> CommitTransactionsRequest { 34 | let mut all_updates = Vec::new(); 35 | assert_eq!(txns.len(), compute_result.compute_status.len()); 36 | for (txn, status) in txns.iter().zip(compute_result.compute_status.iter()) { 37 | let mut transaction = CommittedTransaction::default(); 38 | transaction.sender = txn.sender().as_ref().to_vec(); 39 | transaction.sequence_number = txn.sequence_number(); 40 | match status { 41 | TransactionStatus::Keep(_) => { 42 | counters::SUCCESS_TXNS_COUNT.inc(); 43 | transaction.is_rejected = false;//标注状态 44 | } 45 | TransactionStatus::Discard(_) => { 46 | counters::FAILED_TXNS_COUNT.inc(); 47 | transaction.is_rejected = true; 48 | } 49 | }; 50 | all_updates.push(transaction); 51 | } 52 | let mut req = CommitTransactionsRequest::default(); 53 | req.transactions = all_updates; 54 | req.block_timestamp_usecs = timestamp_usecs; 55 | req 56 | } 57 | 58 | /// Submit the request and return the future, which is fulfilled when the response is received. 59 | fn submit_commit_transactions_request( 60 | &self, 61 | req: CommitTransactionsRequest, 62 | ) -> Pin> + Send>> { 63 | match self.mempool.commit_transactions_async(&req) { 64 | Ok(receiver) => async move { 65 | match receiver.compat().await { 66 | Ok(_) => Ok(()), 67 | Err(e) => Err(e.into()), 68 | } 69 | } 70 | .boxed(), 71 | Err(e) => future::err(e.into()).boxed(), 72 | } 73 | } 74 | } 75 | 76 | impl TxnManager for MempoolProxy { 77 | type Payload = Vec; 78 | 79 | /// The returned future is fulfilled with the vector of SignedTransactions 80 | fn pull_txns( 81 | &self, 82 | max_size: u64, 83 | exclude_payloads: Vec<&Self::Payload>, 84 | ) -> Pin> + Send>> { 85 | let mut exclude_txns = vec![]; 86 | for payload in exclude_payloads { 87 | for signed_txn in payload { 88 | let mut txn_meta = TransactionExclusion::default(); 89 | txn_meta.sender = signed_txn.sender().into(); 90 | txn_meta.sequence_number = signed_txn.sequence_number(); 91 | exclude_txns.push(txn_meta); 92 | } 93 | } 94 | let mut get_block_request = GetBlockRequest::default(); 95 | get_block_request.max_block_size = max_size; 96 | get_block_request.transactions = exclude_txns; 97 | match self.mempool.get_block_async(&get_block_request) { 98 | Ok(receiver) => async move { 99 | match receiver.compat().await { 100 | Ok(response) => Ok(response 101 | .block 102 | .unwrap_or_else(Default::default) 103 | .transactions 104 | .into_iter() 105 | .filter_map(|proto_txn| { 106 | match SignedTransaction::try_from(proto_txn.clone()) { 107 | Ok(t) => Some(t), 108 | Err(e) => { 109 | security_log(SecurityEvent::InvalidTransactionConsensus) 110 | .error(&e) 111 | .data(&proto_txn) 112 | .log(); 113 | None 114 | } 115 | } 116 | }) 117 | .collect()), 118 | Err(e) => Err(e.into()), 119 | } 120 | } 121 | .boxed(), 122 | Err(e) => future::err(e.into()).boxed(), 123 | } 124 | } 125 | 126 | fn commit_txns<'a>( 127 | &'a self, 128 | txns: &Self::Payload, 129 | compute_result: &StateComputeResult, 130 | // Monotonic timestamp_usecs of committed blocks is used to GC expired transactions. 131 | timestamp_usecs: u64, 132 | ) -> Pin> + Send + 'a>> { 133 | counters::COMMITTED_BLOCKS_COUNT.inc(); 134 | counters::COMMITTED_TXNS_COUNT.inc_by(txns.len() as i64); 135 | counters::NUM_TXNS_PER_BLOCK.observe(txns.len() as f64); 136 | let req = 137 | Self::gen_commit_transactions_request(txns.as_slice(), compute_result, timestamp_usecs); 138 | self.submit_commit_transactions_request(req) 139 | } 140 | } 141 | 142 | ``` 143 | 144 | ## 总结: 145 | 146 | **这一部分的逻辑比较简单,主要使用了与mempool通信的client,主要的功能就是向mempool发送请求,具体功能的完成是mempool收到请求之后做的** -------------------------------------------------------------------------------- /consensus/consensus.md: -------------------------------------------------------------------------------- 1 | # consensus 2 | 3 | * Libra使用libraBFT共识算法,它基于BFT,是Hotstuff的一种变种,为了理解算法的大致流程,我们强烈推荐阅读这一部分的Libra官方的[代码说明文档](https://github.com/libra/libra/blob/master/consensus/README.md) 如果想进一步了解理论细节,可以阅读提出LibraBFT的论文[LibraBFT-paper](https://github.com/Jiashuo-Zhang/Libra-code-Analysis/blob/master/consensus/libra-consensus-state-machine-replication-in-the-libra-blockchain.pdf)。 4 | 5 | ## 目录 6 | 7 | ``` 8 | consensus 9 | ├── src 10 | │ └── chained_bft # Implementation of the LibraBFT protocol 11 | │ ├── block_storage # In-memory storage of blocks and related data structures 12 | │ ├── consensus_types # Consensus data types (i.e. quorum certificates) 13 | │ ├── consensusdb # Database interaction to persist consensus data for safety and liveness 14 | │ ├── liveness # Pacemaker, proposer, and other liveness related code 15 | │ ├── safety # Safety (voting) rules 16 | │ └── test_utils # Mock implementations that are used for testing only 17 | └── state_synchronizer # Synchronization between validators to catch up on committed state 18 | ``` 19 | 20 | ## 模块: 21 | 22 | * **Txn_manager**:是consensus模块与mempool模块的接口,主要用于 23 | * 当自己是leader的时候pull出一个块来进行propose 24 | * 有block被commit之后,将这个block中的txns都从mempool中删除 25 | * **State_Computer**: 是consensus模块与execution模块的接口,主要用于: 26 | * commit block 27 | * execute block 28 | * synchronize state 29 | * **BlockStore**:负责维护proposal blocks, block execution, votes, quorum certificates, and persistent storage等等数据结构。这一部分支持并发,可以并发的提供服务。 30 | * **EventProcessor**:LibraBFT本质还是事件驱动型的,这一部分就负责处理各种各样的事件,为每个事件都写了处理函数。 (e.g., process_new_round, process_proposal, process_vote). 31 | * **Pacemaker**:顾名思义,负责LibraBFT的liveness。他会检测超时的状况并进入一个新的round ,当他是当前round的leader时,这一部分还负责propose出一个block。 32 | * **SafetyRules**:用于保证共识地安全性。Libra有两个vote的rule,这个模块会确保投票时遵守这两个规则。 33 | 34 | **因为consensus的实现非常复杂,我决定从一个consensus provider的启动流程开始,比较high level的分析这些代码的功能,因此下面将只分析最核心的代码和流程,这些代码中使用的函数们一般都在更底层的代码中实现,但是我们在这里只是把他们当作API来看待 ,以后如果有必要会尽可能补上这些最底层的实现分析** 35 | 36 | #### 启动:在consensus_providers.rs中实现 37 | 38 | ```rust 39 | //这里实现了一个trait,所有实现了start和stop函数的struct都可以看作是一个consensus模块,事实上,在chained_bft_consensus_provider中,就是给struct ChainedBftProvider实现了这个trait,凭借这个来创造了一个基于LibraBFT的consensus模块。 40 | //这个文件还提供了三个函数,用来创建与mempool,execution,storage进行通信三个客户端,用于与这三个部分进行交互。 41 | 42 | /// Public interface to a consensus protocol. 43 | pub trait ConsensusProvider { 44 | /// Spawns new threads, starts the consensus operations (retrieve txns, consensus protocol, 45 | /// execute txns, commit txns, update txn status in the mempool, etc). 46 | /// The function returns after consensus has recovered its initial state, 47 | /// and has established the required connections (e.g., to mempool and 48 | /// executor). 49 | fn start(&mut self) -> Result<()>; 50 | 51 | /// Stop the consensus operations. The function returns after graceful shutdown. 52 | fn stop(&mut self); 53 | } 54 | 55 | 56 | /// Helper function to create a ConsensusProvider based on configuration 57 | ////这里实际上就是new了一个libraBFT(chainedBFTProvider),然后建立了几个client 58 | pub fn make_consensus_provider( 59 | node_config: &NodeConfig, 60 | network_sender: ConsensusNetworkSender, 61 | network_receiver: ConsensusNetworkEvents, 62 | ) -> Box { 63 | Box::new(ChainedBftProvider::new( 64 | node_config, 65 | network_sender, 66 | network_receiver, 67 | create_mempool_client(node_config), 68 | create_execution_client(node_config), 69 | )) 70 | } 71 | /// Create a mempool client assuming the mempool is running on localhost 72 | fn create_mempool_client(config: &NodeConfig) -> Arc { 73 | let port = config.mempool.mempool_service_port; 74 | let connection_str = format!("localhost:{}", port); 75 | 76 | let env = Arc::new(EnvBuilder::new().name_prefix("grpc-con-mem-").build()); 77 | Arc::new(MempoolClient::new( 78 | ChannelBuilder::new(env).connect(&connection_str), 79 | )) 80 | } 81 | 82 | /// Create an execution client assuming the mempool is running on localhost 83 | fn create_execution_client(config: &NodeConfig) -> Arc { 84 | let connection_str = format!("localhost:{}", config.execution.port); 85 | 86 | let env = Arc::new(EnvBuilder::new().name_prefix("grpc-con-exe-").build()); 87 | Arc::new(ExecutionClient::new( 88 | ChannelBuilder::new(env).connect(&connection_str), 89 | )) 90 | } 91 | 92 | /// Create a storage read client based on the config 93 | pub fn create_storage_read_client(config: &NodeConfig) -> Arc { 94 | let env = Arc::new(EnvBuilder::new().name_prefix("grpc-con-sto-").build()); 95 | Arc::new(StorageReadServiceClient::new( 96 | env, 97 | &config.storage.address, 98 | config.storage.port, 99 | )) 100 | } 101 | ``` 102 | 103 | 104 | 105 | ```rust 106 | //一个完整的ChainedBftProvider包括以下几个部分,包括3个client和一个SMR模块 107 | //事实上,开启一个ChainedBftProvider就是用其他3个client去start了一个smr 108 | 109 | /// Supports the implementation of ConsensusProvider using LibraBFT. 110 | pub struct ChainedBftProvider { 111 | smr: ChainedBftSMR, Author>, 112 | mempool_client: Arc, 113 | execution_client: Arc, 114 | synchronizer_client: Arc, 115 | } 116 | 117 | //上面提到的实现接口就是这个,为ChainedBftProvider实现了一个start和stop 118 | //可以看到start()创建了txn_manager(用mempool_client)来实现pull block和commit txns功能 119 | //state_computer则是用execution_client和synchronizer_client实现的,这一个功能主要是在statr_computrt.rs中实现的,后面会介绍 120 | //最后用上面的这两个实现了最终的smr,并且start,smr的功能我们会在chained_bft_smr中具体说 121 | impl ConsensusProvider for ChainedBftProvider { 122 | fn start(&mut self) -> Result<()> { 123 | let txn_manager = Arc::new(MempoolProxy::new(self.mempool_client.clone())); 124 | let state_computer = Arc::new(ExecutionProxy::new( 125 | self.execution_client.clone(), 126 | self.synchronizer_client.clone(), 127 | )); 128 | debug!("Starting consensus provider."); 129 | self.smr.start(txn_manager, state_computer) 130 | } 131 | 132 | fn stop(&mut self) { 133 | self.smr.stop(); 134 | debug!("Consensus provider stopped."); 135 | } 136 | } 137 | 138 | ``` 139 | 140 | ## 总结: 141 | 142 | **前半部分我们根据官方的文档了解算法的大致流程和consensus模块的主要组成,后半部分我们从最顶层的如何开启一个SMR入手,简要介绍了ChainedBftProvider的结构和各部分的作用,后面我们将分别介绍每一部分,并介绍这几部分是如何紧密联系在一起的。** 143 | 144 | -------------------------------------------------------------------------------- /consensus/libra-consensus-state-machine-replication-in-the-libra-blockchain.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jiashuo-Zhang/Libra-code-Analysis/7640948485fcacff61159c51dd160e99230da680/consensus/libra-consensus-state-machine-replication-in-the-libra-blockchain.pdf -------------------------------------------------------------------------------- /mempool/mempool.md: -------------------------------------------------------------------------------- 1 | # mempool 2 | 3 | ## 功能 4 | 5 | **总的来说,mempool就是在内存中缓存一部分交易,这一部分交易在等待执行,共识,确认,最终加入到stoage中,下面是一些细节:** 6 | 7 | * AC将验证过的交易发送到mempool,mempool中存储还未形成区块的交易 8 | * mempool中每次加入新交易,都会转发给其他validator,让他们加入到自己的mempool中 9 | * mempool每次收到别的validator发送的交易,会排序插入到自己的queue中。 10 | * 为了减少带宽使用,我们只发送有可能被加入到下个区块的交易,(This means that either the sequence number of the transaction is the next sequence number of the sender account, or it is sequential to it.For example, if the current sequence number for an account is 2 and local mempool contains transactions with sequence numbers 2, 3, 4, 7, 8, then only transactions 2, 3, and 4 will be broadcast).同时,我们不会转发其他validator转发来的交易,这些validator自己负责转发给所有的validator 11 | * mempool中的交易组成区块通过consenseus与其他validator达成一致,mempool不会主动发送交易给consensus,而是consensus主动pull mempool中的交易 12 | * mempool中的交易根据gas price排序(gloabal,在保证正确的前提下激励人们用gas price换取更快进入block。在同一账户发起的交易中,按sequence number排序, 13 | * 当一笔交易被写进storage中后,consensus模块会给mempool发送信息来噶奥苏他不用继续存储这笔交易了 14 | * 为防止攻击,mempool中的交易数目和每个交易的存在时间都有限制,时间限制为:systemTTL and client-specified expiration,超过之后会被垃圾回收。 15 | 16 | ## 与其他模块的交互 17 | 18 | 与VM,consensus,其他validator存在交互 19 | 20 | ## 其他细节 21 | 22 | 见[Libra官方关于mempool的文档](https://developers.libra.org/docs/crates/mempool) 23 | 24 | ## 目录 25 | 26 | mempool/src 27 | ├── core_mempool # main in memory data structure 28 | ├── proto # protobuf definitions for interactions with mempool 29 | ├── lib.rs 30 | ├── mempool_service.rs # gRPC service 31 | ├── runtime.rs # bundle of shared mempool and gRPC service 32 | └── shared_mempool.rs # shared mempool 33 | ## 具体实现 34 | 35 | 详见各个md模块中 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /mempool/mempool_service.md: -------------------------------------------------------------------------------- 1 | # mempool_serevr 2 | 3 | ## 功能: 4 | 5 | * 对外提供各种gRPC服务 6 | * 从这一部分,可以看到mempool对外提供的所有服务,这些服务大都利用在其他.rs文件中定义的函数。 7 | 8 | ## 代码: 9 | 10 | #### add_transaction_with_validation : 11 | 12 | **收到其他的validator发来的交易,验证数字签名之后,向mempool内加入交易** 13 | 14 | ```rust 15 | fn add_transaction_with_validation( 16 | &mut self, 17 | ctx: ::grpcio::RpcContext<'_>, 18 | mut req: crate::proto::mempool::AddTransactionWithValidationRequest, 19 | sink: ::grpcio::UnarySink, 20 | ) { 21 | trace!("[GRPC] Mempool::add_transaction_with_validation"); 22 | let _timer = SVC_COUNTERS.req(&ctx); 23 | let mut success = true; 24 | let proto_transaction = req.take_signed_txn(); 25 | match SignedTransaction::from_proto(proto_transaction) {//验证数字签名 26 | Err(e) => { 27 | success = false; 28 | ctx.spawn( 29 | sink.fail(create_grpc_invalid_arg_status( 30 | "add_transaction_with_validation", 31 | e, 32 | )) 33 | .map_err(default_reply_error_logger), 34 | ); 35 | } 36 | Ok(transaction) => { 37 | let insertion_result = self 38 | .core_mempool 39 | .lock() 40 | .expect("[add txn] acquire mempool lock")//获得锁,准备将交易加入 41 | .add_txn( 42 | transaction, 43 | req.max_gas_cost, 44 | req.latest_sequence_number, 45 | req.account_balance, 46 | TimelineState::NotReady, 47 | );//将这笔交易加入进去 48 | 49 | let mut response = 50 | crate::proto::mempool::AddTransactionWithValidationResponse::new(); 51 | response.set_status(insertion_result.into_proto()); 52 | ctx.spawn(sink.success(response).map_err(default_reply_error_logger)) 53 | } 54 | } 55 | SVC_COUNTERS.resp(&ctx, success);//response 56 | } 57 | ``` 58 | 59 | #### get_block: 60 | 61 | **返回获取一个block作为下一个待达成共识的block,在当前validator变成了proposer时会通过这个函数进行propose** 62 | 63 | ```rust 64 | fn get_block( 65 | &mut self, 66 | ctx: ::grpcio::RpcContext<'_>, 67 | req: super::proto::mempool::GetBlockRequest, 68 | sink: ::grpcio::UnarySink, 69 | ) { 70 | trace!("[GRPC] Mempool::get_block"); 71 | let _timer = SVC_COUNTERS.req(&ctx); 72 | 73 | let block_size = cmp::max(req.get_max_block_size(), 1);//限制大小 74 | OP_COUNTERS.inc_by("get_block.requested", block_size as usize); 75 | let exclude_transactions: HashSet = req 76 | .get_transactions() 77 | .iter() 78 | .map(|t| (AccountAddress::try_from(t.get_sender()), t.sequence_number)) 79 | .filter(|(address, _)| address.is_ok()) 80 | .map(|(address, seq)| (address.unwrap(), seq)) 81 | .collect(); 82 | 83 | let mut txns = self 84 | .core_mempool 85 | .lock() 86 | .expect("[get_block] acquire mempool lock") 87 | .get_block(block_size, exclude_transactions);//获得锁之后获取block 88 | 89 | let transactions = txns.drain(..).map(SignedTransaction::into_proto).collect(); 90 | 91 | let mut block = SignedTransactionsBlock::new(); 92 | block.set_transactions(::protobuf::RepeatedField::from_vec(transactions)); 93 | OP_COUNTERS.inc_by("get_block.returned", block.get_transactions().len()); 94 | let mut response = crate::proto::mempool::GetBlockResponse::new(); 95 | response.set_block(block); 96 | ctx.spawn(sink.success(response).map_err(default_reply_error_logger));//返回response 97 | SVC_COUNTERS.resp(&ctx, true); 98 | } 99 | 100 | ``` 101 | 102 | #### commit_transactions: 103 | 104 | **确认了交易被加入到storage之后删除mempool里面的对应交易** 105 | 106 | ```rust 107 | fn commit_transactions( 108 | &mut self, 109 | ctx: ::grpcio::RpcContext<'_>, 110 | req: crate::proto::mempool::CommitTransactionsRequest, 111 | sink: ::grpcio::UnarySink, 112 | ) { 113 | trace!("[GRPC] Mempool::commit_transaction"); 114 | let _timer = SVC_COUNTERS.req(&ctx); 115 | OP_COUNTERS.inc_by( 116 | "commit_transactions.requested", 117 | req.get_transactions().len(), 118 | ); 119 | let mut pool = self 120 | .core_mempool 121 | .lock() 122 | .expect("[update status] acquire mempool lock"); 123 | for transaction in req.get_transactions() { 124 | if let Ok(address) = AccountAddress::try_from(transaction.get_sender()) { 125 | let sequence_number = transaction.get_sequence_number(); 126 | pool.remove_transaction(&address, sequence_number, transaction.get_is_rejected()); 127 | } 128 | } 129 | let block_timestamp_usecs = req.get_block_timestamp_usecs(); 130 | if block_timestamp_usecs > 0 { 131 | pool.gc_by_expiration_time(Duration::from_micros(block_timestamp_usecs)); 132 | } 133 | let response = crate::proto::mempool::CommitTransactionsResponse::new(); 134 | ctx.spawn(sink.success(response).map_err(default_reply_error_logger)); 135 | SVC_COUNTERS.resp(&ctx, true); 136 | } 137 | ``` 138 | 139 | #### health_check: 140 | 141 | 检查mempool当前的状态 142 | 143 | ```rust 144 | fn health_check( 145 | &mut self, 146 | ctx: ::grpcio::RpcContext<'_>, 147 | _req: crate::proto::mempool::HealthCheckRequest, 148 | sink: ::grpcio::UnarySink, 149 | ) { 150 | trace!("[GRPC] Mempool::health_check"); 151 | let pool = self 152 | .core_mempool 153 | .lock() 154 | .expect("[health_check] acquire mempool lock"); 155 | let mut response = crate::proto::mempool::HealthCheckResponse::new(); 156 | response.set_is_healthy(pool.health_check()); 157 | ctx.spawn(sink.success(response).map_err(default_reply_error_logger)); 158 | } 159 | ``` 160 | 161 | -------------------------------------------------------------------------------- /mempool/runtime.md: -------------------------------------------------------------------------------- 1 | # runtime 2 | 3 | ## 功能: 4 | 5 | bundle of shared mempool and gRPC service 6 | 7 | 初始化了两部分,一个是grpc服务,一个是shared mempool 8 | 9 | ## 代码实现: 10 | 11 | 对各个部分进行了初始化,以及起了服务。这之后就mempool就可以正常运行了。 12 | 13 | ```rust 14 | impl MempoolRuntime { 15 | /// setup Mempool runtime 16 | pub fn bootstrap( 17 | config: &NodeConfig, 18 | network_sender: MempoolNetworkSender, 19 | network_events: MempoolNetworkEvents, 20 | ) -> Self { 21 | let mempool = Arc::new(Mutex::new(CoreMempool::new(&config))); 22 | 23 | // setup grpc server 24 | let env = Arc::new( 25 | EnvBuilder::new() 26 | .name_prefix("grpc-mempool-") 27 | .cq_count(unsafe { max(grpcio_sys::gpr_cpu_num_cores() as usize / 2, 2) }) 28 | .build(), 29 | ); 30 | let handle = MempoolService { 31 | core_mempool: Arc::clone(&mempool), 32 | }; 33 | let service = mempool_grpc::create_mempool(handle); 34 | let grpc_server = ::grpcio::ServerBuilder::new(env) 35 | .register_service(service) 36 | .bind( 37 | config.mempool.address.clone(), 38 | config.mempool.mempool_service_port, 39 | )/ 40 | .build() 41 | .expect("[mempool] unable to create grpc server"); 42 | 43 | // setup shared mempool 44 | ////下面是初始化shared mempool,先初始化了两个shared mempool需要的部分,即storage_client,还有vm_validator,之后起了shared_mempool 45 | let storage_client: Arc = Arc::new(StorageReadServiceClient::new( 46 | Arc::new(EnvBuilder::new().name_prefix("grpc-mem-sto-").build()), 47 | "localhost", 48 | config.storage.port, 49 | )); 50 | let vm_validator = Arc::new(VMValidator::new(&config, Arc::clone(&storage_client))); 51 | let shared_mempool = start_shared_mempool( 52 | config, 53 | mempool, 54 | network_sender, 55 | network_events, 56 | storage_client, 57 | vm_validator, 58 | vec![], 59 | None, 60 | ); 61 | Self { 62 | grpc_server: ServerHandle::setup(grpc_server), 63 | shared_mempool, 64 | } 65 | } 66 | } 67 | 68 | ``` 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /mempool/shared_mempool.md: -------------------------------------------------------------------------------- 1 | # shared_mempool 2 | 3 | ## 功能: 4 | 5 | * **实现shared_mempool,可以与别的validator等待共享** 6 | * **实现一个shared_mempool有两个问题**: 7 | * 和谁share? 8 | * 管理peers 9 | * 怎么share? 10 | * 如何share? 11 | * 定时向peers发出事件( outbound) 12 | * 异步地处理peers发来的事件(inbound) 13 | * 如何保持liveness?: garbage collection 14 | * 如何保证正确性?:所有共享数据结构的操作都加锁 15 | 16 | ## 代码实现: 17 | 18 | #### peer管理: 19 | 20 | ```rust 21 | /// state of last sync with peer 22 | /// `timeline_id` is position in log of ready transactions 23 | /// `is_alive` - is connection healthy 24 | #[derive(Clone)] 25 | struct PeerSyncState { 26 | timeline_id: u64, 27 | is_alive: bool, 28 | } 29 | 30 | type PeerInfo = HashMap; 31 | //map记录所有peer的状态 32 | 33 | type PeerInfo = HashMap; 34 | 35 | /// Outbound peer syncing event emitted by [`IntervalStream`].、 36 | 37 | //通俗来说应该是所有需要发送的事件 38 | #[derive(Debug)] 39 | pub(crate) struct SyncEvent; 40 | 41 | type IntervalStream = Pin> + Send + 'static>>; 42 | 43 | ///这里列出了三种要通知订阅者的时间类型,一种是同步,一种是peer状态变化,一种是收到new transaction 44 | #[derive(Copy, Clone, Debug, PartialEq)] 45 | pub enum SharedMempoolNotification { 46 | Sync, 47 | PeerStateChange, 48 | NewTransactions, 49 | } 50 | 51 | /// Struct that owns all dependencies required by shared mempool routines 52 | 53 | struct SharedMempool 54 | where 55 | V: TransactionValidation + 'static, 56 | { 57 | mempool: Arc>, 58 | network_sender: MempoolNetworkSender, 59 | config: MempoolConfig, 60 | storage_read_client: Arc, 61 | validator: Arc, 62 | peer_info: Arc>, 63 | subscribers: Vec>, 64 | } 65 | 66 | ``` 67 | 68 | #### notify_subscribers 69 | 70 | ```rust 71 | fn notify_subscribers( 72 | event: SharedMempoolNotification, 73 | subscribers: &[UnboundedSender], 74 | ) { 75 | for subscriber in subscribers { 76 | let _ = subscriber.unbounded_send(event); 77 | } 78 | } 79 | //挨个通知订阅者 80 | ``` 81 | 82 | #### peer_handle: 83 | 84 | 处理新发现peer和失去peer 85 | 86 | ```rust 87 | /// new peer discovery handler 88 | /// adds new entry to `peer_info` 89 | fn new_peer(peer_info: &Mutex, peer_id: PeerId) { 90 | peer_info 91 | .lock() 92 | .expect("[shared mempool] failed to acquire peer_info lock") 93 | .entry(peer_id)//如果当前还没有这个peer就new一个加入进去 94 | .or_insert(PeerSyncState { 95 | timeline_id: 0, 96 | is_alive: true, 97 | }) 98 | .is_alive = true; 99 | } 100 | 101 | /// lost peer handler. Marks connection as dead 102 | fn lost_peer(peer_info: &Mutex, peer_id: PeerId) { 103 | if let Some(state) = peer_info 104 | .lock() 105 | .expect("[shared mempool] failed to acquire peer_info lock") 106 | .get_mut(&peer_id)//这里每一项操作都需要加锁 107 | { 108 | state.is_alive = false; 109 | } 110 | } 111 | ``` 112 | 113 | #### sync_with_peers: 114 | 115 | **与peer进行同步,把某个timelineid之后的数据发送给peer们,更新peer的timeline** 116 | 117 | ```rust 118 | /// sync routine 119 | /// used to periodically broadcast ready to go transactions to peers 120 | async fn sync_with_peers<'a>( 121 | peer_info: &'a Mutex, 122 | mempool: &'a Mutex, 123 | network_sender: &'a mut MempoolNetworkSender, 124 | batch_size: usize, 125 | ) { 126 | // Clone the underlying peer_info map and use this to sync and collect 127 | // state updates. We do this instead of holding the lock for the whole 128 | // function since that would hold the lock across await points which is bad. 129 | let peer_info_copy = peer_info 130 | .lock() 131 | .expect("[shared mempool] failed to acquire peer_info lock") 132 | .deref() 133 | .clone(); 134 | 135 | let mut state_updates = vec![]; 136 | //对每一个peer都进行一次发送 137 | for (peer_id, peer_state) in peer_info_copy.into_iter() { 138 | if peer_state.is_alive { 139 | let timeline_id = peer_state.timeline_id; 140 | 141 | let (transactions, new_timeline_id) = mempool 142 | .lock() 143 | .expect("[shared mempool] failed to acquire mempool lock") 144 | .read_timeline(timeline_id, batch_size); 145 | ///从mempool里面取出这个peer的timeline ID之后的交易 146 | 147 | if !transactions.is_empty() {//交易不空,需要同步 148 | OP_COUNTERS.inc_by("smp.sync_with_peers", transactions.len()); 149 | let mut msg = MempoolSyncMsg::new(); 150 | msg.set_peer_id(peer_id.into()); 151 | msg.set_transactions( 152 | transactions 153 | .into_iter() 154 | .map(IntoProto::into_proto) 155 | .collect(), 156 | ); 157 | //把交易们打包 158 | 159 | debug!( 160 | "MempoolNetworkSender.send_to peer {} msg {:?}", 161 | peer_id, msg 162 | ); 163 | // Since this is a direct-send, this will only error if the network 164 | // module has unexpectedly crashed or shutdown. 165 | network_sender 166 | .send_to(peer_id, msg) 167 | .await 168 | .expect("[shared mempool] failed to direct-send mempool sync message"); 169 | } 170 | //把打包后的交易们通过network_sender发送给peer 171 | 172 | state_updates.push((peer_id, new_timeline_id)); 173 | 174 | } 175 | } 176 | 177 | // Lock the shared peer_info and apply state updates. 178 | //加锁,更新peer状态 179 | let mut peer_info = peer_info 180 | .lock() 181 | .expect("[shared mempool] failed to acquire peer_info lock"); 182 | for (peer_id, new_timeline_id) in state_updates { 183 | peer_info 184 | .entry(peer_id) 185 | .and_modify(|t| t.timeline_id = new_timeline_id);//更新timeline_id 到当前 186 | } 187 | } 188 | ``` 189 | 190 | #### process_incoming_transactions: 191 | 192 | **处理peer们发来的交易,这一部分是异步的,因为peers可能在任一时刻往这边发** 193 | 194 | ```rust 195 | // used to validate incoming transactions and add them to local Mempool 196 | async fn process_incoming_transactions( 197 | smp: SharedMempool, 198 | peer_id: PeerId, 199 | transactions: Vec, 200 | ) where 201 | V: TransactionValidation, 202 | { 203 | let validations = join_all( 204 | transactions 205 | .iter() 206 | .map(|t| smp.validator.validate_transaction(t.clone()).compat()), 207 | ) 208 | .await;//选出所有验证通过的交易,批量操作 209 | 210 | let account_states = join_all( 211 | transactions 212 | .iter() 213 | .map(|t| get_account_state(smp.storage_read_client.clone(), t.sender())), 214 | ) 215 | .await; 216 | //获得所有相关的account的state,批量操作 217 | let mut mempool = smp 218 | .mempool 219 | .lock() 220 | .expect("[shared mempool] failed to acquire mempool lock"); 221 | 222 | for (idx, transaction) in transactions.into_iter().enumerate() { 223 | if let Ok(None) = validations[idx] { 224 | if let Ok((sequence_number, balance)) = account_states[idx] { 225 | let gas_cost = transaction.max_gas_amount(); 226 | let insertion_result = mempool.add_txn( 227 | transaction, 228 | gas_cost, 229 | sequence_number, 230 | balance, 231 | TimelineState::NonQualified, 232 | ); 233 | if insertion_result.code == MempoolAddTransactionStatusCode::Valid { 234 | OP_COUNTERS.inc(&format!("smp.transactions.success.{:?}", peer_id)); 235 | } 236 | }//尝试加入mempool并返回状态 237 | } 238 | } 239 | notify_subscribers(SharedMempoolNotification::NewTransactions, &smp.subscribers);//通知订阅着有新的交易加入 240 | } 241 | 242 | ``` 243 | 244 | #### outbound_sync_task: 245 | 246 | 类似脉冲发生器的功能,定期的与外界进行sync_with_peers(并notify_subscribers) 247 | 248 | ```rust 249 | /// This task handles [`SyncEvent`], which is periodically emitted for us to 250 | /// broadcast ready to go transactions to peers. 251 | async fn outbound_sync_task(smp: SharedMempool, mut interval: IntervalStream) 252 | where 253 | V: TransactionValidation, 254 | { 255 | let peer_info = smp.peer_info; 256 | let mempool = smp.mempool; 257 | let mut network_sender = smp.network_sender; 258 | let batch_size = smp.config.shared_mempool_batch_size; 259 | let subscribers = smp.subscribers; 260 | 261 | while let Some(sync_event) = interval.next().await {///有syncevent被触发了,我们要进行一波同步 262 | trace!("SyncEvent: {:?}", sync_event); 263 | match sync_event { 264 | Ok(_) => { 265 | sync_with_peers(&peer_info, &mempool, &mut network_sender, batch_size).await; 266 | notify_subscribers(SharedMempoolNotification::Sync, &subscribers); 267 | } 268 | Err(e) => { 269 | error!("Error in outbound_sync_task timer interval: {:?}", e); 270 | break; 271 | } 272 | } 273 | } 274 | 275 | crit!("SharedMempool outbound_sync_task terminated"); 276 | } 277 | ``` 278 | 279 | #### inbound_network_task: 280 | 281 | 处理外面发来的event 282 | 283 | ```rust 284 | /// This task handles inbound network events. 285 | async fn inbound_network_task(smp: SharedMempool, network_events: MempoolNetworkEvents) 286 | where 287 | V: TransactionValidation, 288 | { 289 | let peer_info = smp.peer_info.clone(); 290 | let subscribers = smp.subscribers.clone(); 291 | let max_inbound_syncs = smp.config.shared_mempool_max_concurrent_inbound_syncs; 292 | 293 | // Handle the NewPeer/LostPeer events immediatedly, since they are not async 294 | // and we don't want to buffer them or let them get reordered. The inbound 295 | // direct-send messages are placed in a bounded FuturesUnordered queue and 296 | // allowed to execute concurrently. The .buffer_unordered() also correctly 297 | // handles back-pressure, so if mempool is slow the back-pressure will 298 | // propagate down to network. 299 | 300 | ///即时处理new peer和lost peer 301 | let f_inbound_network_task = network_events 302 | .filter_map(move |network_event| { 303 | trace!("SharedMempoolEvent::NetworkEvent::{:?}", network_event); 304 | match network_event { 305 | Ok(network_event) => match network_event { 306 | Event::NewPeer(peer_id) => { 307 | OP_COUNTERS.inc("smp.event.new_peer"); 308 | new_peer(&peer_info, peer_id); 309 | notify_subscribers( 310 | SharedMempoolNotification::PeerStateChange, 311 | &subscribers, 312 | ); 313 | future::ready(None) 314 | } 315 | Event::LostPeer(peer_id) => { 316 | OP_COUNTERS.inc("smp.event.lost_peer"); 317 | lost_peer(&peer_info, peer_id); 318 | notify_subscribers( 319 | SharedMempoolNotification::PeerStateChange, 320 | &subscribers, 321 | ); 322 | future::ready(None) 323 | } 324 | // Pass through messages to next combinator 325 | Event::Message((peer_id, msg)) => future::ready(Some((peer_id, msg))), 326 | _ => { 327 | security_log(SecurityEvent::InvalidNetworkEventMP) 328 | .error("UnexpectedNetworkEvent") 329 | .data(&network_event) 330 | .log(); 331 | unreachable!("Unexpected network event") 332 | } 333 | }, 334 | Err(e) => { 335 | security_log(SecurityEvent::InvalidNetworkEventMP) 336 | .error(&e) 337 | .log(); 338 | future::ready(None) 339 | } 340 | } 341 | }) 342 | // Run max_inbound_syncs number of `process_incoming_transactions` concurrently 343 | // 并发的处理peer发来的transactions 344 | //这里面可以看到Libra是采用了并发的思想的,这对其performace有很大的提升。 345 | .for_each_concurrent( 346 | max_inbound_syncs, /* limit */ 347 | move |(peer_id, mut msg)| { 348 | OP_COUNTERS.inc("smp.event.message"); 349 | let transactions: Vec<_> = msg 350 | .take_transactions() 351 | .into_iter() 352 | .filter_map(|txn| match SignedTransaction::from_proto(txn) { 353 | Ok(t) => Some(t), 354 | Err(e) => { 355 | security_log(SecurityEvent::InvalidTransactionMP) 356 | .error(&e) 357 | .data(&msg) 358 | .log(); 359 | None 360 | } 361 | }) 362 | .collect(); 363 | OP_COUNTERS.inc_by( 364 | &format!("smp.transactions.received.{:?}", peer_id), 365 | transactions.len(), 366 | ); 367 | process_incoming_transactions(smp.clone(), peer_id, transactions) 368 | }, 369 | ); 370 | 371 | // drive the inbound futures to completion 372 | f_inbound_network_task.await; 373 | 374 | crit!("SharedMempool inbound_network_task terminated"); 375 | } 376 | ``` 377 | 378 | #### gc_task:定期进行GC 379 | 380 | ```rust 381 | /// GC all expired transactions by SystemTTL 382 | async fn gc_task(mempool: Arc>, gc_interval_ms: u64) { 383 | let mut interval = Interval::new_interval(Duration::from_millis(gc_interval_ms)).compat(); 384 | while let Some(res) = interval.next().await { 385 | match res { 386 | Ok(_) => { 387 | mempool 388 | .lock() 389 | .expect("[shared mempool] failed to acquire mempool lock") 390 | .gc_by_system_ttl(); 391 | } 392 | Err(e) => { 393 | error!("Error in gc_task timer interval: {:?}", e); 394 | break; 395 | } 396 | } 397 | } 398 | 399 | crit!("SharedMempool gc_task terminated"); 400 | } 401 | ``` 402 | 403 | #### start_shared_mempool: 404 | 405 | **启动shared_mempool,核心就是启动了三个线程,来处理各种事件** 406 | 407 | * outbound_sync_task 408 | * inbound_network_task 409 | * gc_task 410 | 411 | 上面提到了前两个,第三个garbage collection很好理解。 412 | 413 | **这里面主要有两个配置参数** 414 | 415 | * config.mempool.shared_mempool_tick_interval_ms:outbound中隔多久发起一次同步 416 | * config.mempool.system_transaction_gc_interval_ms:gc中隔多久发起一次垃圾回收 417 | 418 | ```rust 419 | /// bootstrap of SharedMempool 420 | /// creates separate Tokio Runtime that runs following routines: 421 | /// - outbound_sync_task (task that periodically broadcasts transactions to peers) 422 | /// - inbound_network_task (task that handles inbound mempool messages and network events) 423 | /// - gc_task (task that performs GC of all expired transactions by SystemTTL) 424 | pub(crate) fn start_shared_mempool( 425 | config: &NodeConfig, 426 | mempool: Arc>, 427 | network_sender: MempoolNetworkSender, 428 | network_events: MempoolNetworkEvents, 429 | storage_read_client: Arc, 430 | validator: Arc, 431 | subscribers: Vec>, 432 | timer: Option, 433 | ) -> Runtime 434 | where 435 | V: TransactionValidation + 'static, 436 | { 437 | let runtime = Builder::new() 438 | .name_prefix("shared-mem-") 439 | .build() 440 | .expect("[shared mempool] failed to create runtime"); 441 | let executor = runtime.executor(); 442 | 443 | let peer_info = Arc::new(Mutex::new(PeerInfo::new())); 444 | 445 | let smp = SharedMempool { 446 | mempool: mempool.clone(), 447 | config: config.mempool.clone(), 448 | network_sender, 449 | storage_read_client, 450 | validator, 451 | peer_info, 452 | subscribers, 453 | }; 454 | 455 | let interval = 456 | timer.unwrap_or_else(|| default_timer(config.mempool.shared_mempool_tick_interval_ms)); 457 | 458 | 459 | executor.spawn( 460 | outbound_sync_task(smp.clone(), interval) 461 | .boxed() 462 | .unit_error() 463 | .compat(), 464 | ); 465 | 466 | executor.spawn( 467 | inbound_network_task(smp, network_events) 468 | .boxed() 469 | .unit_error() 470 | .compat(), 471 | ); 472 | 473 | executor.spawn( 474 | gc_task(mempool, config.mempool.system_transaction_gc_interval_ms) 475 | .boxed() 476 | .unit_error() 477 | .compat(), 478 | ); 479 | 480 | runtime 481 | } 482 | 483 | ``` 484 | 485 | 486 | 487 | 488 | 489 | -------------------------------------------------------------------------------- /storage/Event_store.md: -------------------------------------------------------------------------------- 1 | # Event_store 2 | 3 | ## 功能:这一部分提供event的存储,对外提供api 来获取/插入event 4 | 5 | ```rust 6 | 7 | pub(crate) struct EventStore { 8 | db: Arc,//可以看出实际上eventStore就是一个db 9 | } 10 | 11 | impl EventStore { 12 | pub fn new(db: Arc) -> Self { 13 | Self { db } 14 | } 15 | ////在下面的一系列实现中,可以看出每一个event跟触发他的transaction的version是紧密联系的,还有一些函数使用了他在同一个version中各个事件中的index 16 | 17 | 18 | //一个transaction可以触发一系列的事件,然后每一个event都会注明是哪个version的transaction触发的他,所以我们可以根据transaction的version来获取这一交易触发的所有事件。 19 | /// Get all of the events given a transaction version. 20 | /// We don't need a proof for this because it's only used to get all events 21 | /// for a version which can be proved from the root hash of the event tree. 22 | pub fn get_events_by_version(&self, version: Version) -> Result> { 23 | let mut events = vec![]; 24 | 25 | let mut iter = self.db.iter::(ReadOptions::default())?; 26 | // Grab the first event and then iterate until we get all events for this version. 27 | iter.seek(&version)?; 28 | while let Some(((ver, index), event)) = iter.next().transpose()? { 29 | if ver != version { 30 | break; 31 | } 32 | events.push(event); 33 | } 34 | 35 | Ok(events) 36 | } 37 | 38 | /// Get the event raw data given transaction version and the index of the event queried. 39 | ///这个一并返回了proof,是获取某个version的transaction触发的,第index个事件 40 | pub fn get_event_with_proof_by_version_and_index( 41 | &self, 42 | version: Version, 43 | index: u64, 44 | ) -> Result<(ContractEvent, AccumulatorProof)> { 45 | // Get event content. 46 | let event = self 47 | .db 48 | .get::(&(version, index))? 49 | .ok_or_else(|| LibraDbError::NotFound(format!("Event {} of Txn {}", index, version)))?; 50 | 51 | // Get the number of events in total for the transaction at `version`. 52 | let mut iter = self.db.iter::(ReadOptions::default())?; 53 | iter.seek_for_prev(&(version + 1))?; 54 | let num_events = match iter.next().transpose()? { 55 | Some(((ver, index), _)) if ver == version => index + 1, 56 | _ => unreachable!(), // since we've already got at least one event above 57 | }; 58 | 59 | // Get proof. 60 | let proof = 61 | Accumulator::get_proof(&EventHashReader::new(self, version), num_events, index)?; 62 | 63 | Ok((event, proof)) 64 | } 65 | 66 | fn get_txn_ver_by_seq_num(&self, access_path: &AccessPath, seq_num: u64) -> Result { 67 | let (ver, _) = self 68 | .db 69 | .get::(&(access_path.clone(), seq_num))? 70 | .ok_or_else(|| format_err!("Index entry should exist for seq_num {}", seq_num))?; 71 | Ok(ver) 72 | } 73 | 74 | /// Get the latest sequence number on `access_path` considering all transactions with versions 75 | /// no greater than `ledger_version`. 76 | ////在这个path上最新的sequence number 77 | pub fn get_latest_sequence_number( 78 | &self, 79 | ledger_version: Version, 80 | access_path: &AccessPath, 81 | ) -> Result> { 82 | let mut iter = self 83 | .db 84 | .iter::(ReadOptions::default())?; 85 | iter.seek_for_prev(&(access_path.clone(), u64::max_value())); 86 | if let Some(res) = iter.next() { 87 | let ((path, mut seq), (ver, _idx)) = res?; 88 | if path == *access_path { 89 | if ver <= ledger_version { 90 | return Ok(Some(seq)); 91 | } 92 | 93 | // Queries tend to base on very recent ledger infos, so first try to linear search 94 | // from the most recent end, for limited tries. 95 | // TODO: Optimize: Physical store use reverse order. 96 | ////先线性查找 97 | let mut n_try_recent = 10; 98 | #[cfg(test)] 99 | let mut n_try_recent = 1; 100 | while seq > 0 && n_try_recent > 0 { 101 | seq -= 1; 102 | n_try_recent -= 1; 103 | let ver = self.get_txn_ver_by_seq_num(access_path, seq)?; 104 | if ver <= ledger_version { 105 | return Ok(Some(seq)); 106 | } 107 | } 108 | 109 | // Fall back to binary search if the above short linear search didn't work out. 110 | let (mut begin, mut end) = (0, seq); 111 | while begin < end { 112 | let mid = end - (end - begin) / 2; 113 | let ver = self.get_txn_ver_by_seq_num(access_path, mid)?; 114 | if ver <= ledger_version { 115 | begin = mid; 116 | } else { 117 | end = mid - 1; 118 | } 119 | } 120 | return Ok(Some(begin)); 121 | } 122 | } 123 | Ok(None) 124 | } 125 | 126 | /// Given access path and start sequence number, return events identified by transaction index 127 | /// and index among all events yielded by the same transaction. Result won't contain records 128 | /// with a txn_version > `ledger_version` and is in ascending order. 129 | pub fn lookup_events_by_access_path( 130 | &self, 131 | access_path: &AccessPath, 132 | start_seq_num: u64, 133 | limit: u64, 134 | ledger_version: u64, 135 | ) -> Result< 136 | Vec<( 137 | u64, // sequence number 138 | Version, // transaction version it belongs to 139 | u64, // index among events for the same transaction 140 | )>, 141 | > { 142 | let mut iter = self 143 | .db 144 | .iter::(ReadOptions::default())?; 145 | iter.seek(&(access_path.clone(), start_seq_num))?; 146 | 147 | let mut result = Vec::new(); 148 | let mut cur_seq = start_seq_num; 149 | for res in iter.take(limit as usize) { 150 | let ((path, seq), (ver, idx)) = res?; 151 | if path != *access_path || ver > ledger_version { 152 | break; 153 | } 154 | ensure!( 155 | seq == cur_seq, 156 | "DB corrupt: Sequence number not continuous, expected: {}, actual: {}.", 157 | cur_seq, 158 | seq 159 | ); 160 | result.push((seq, ver, idx)); 161 | cur_seq += 1; 162 | } 163 | 164 | Ok(result) 165 | } 166 | 167 | /// Save contract events yielded by the transaction at `version` and return root hash of the 168 | /// event accumulator formed by these events. 169 | pub fn put_events( 170 | &self, 171 | version: u64, 172 | events: &[ContractEvent], 173 | batch: &mut SchemaBatch, 174 | ) -> Result { 175 | // EventSchema and EventByAccessPathSchema updates 176 | events 177 | .iter() 178 | .enumerate() 179 | .map(|(idx, event)| { 180 | batch.put::(&(version, idx as u64), event)?; 181 | batch.put::( 182 | &(event.access_path().clone(), event.sequence_number()), 183 | &(version, idx as u64), 184 | )?; 185 | Ok(()) 186 | }) 187 | .collect::>()?; 188 | 189 | // EventAccumulatorSchema updates 190 | let event_hashes: Vec = events.iter().map(ContractEvent::hash).collect(); 191 | let (root_hash, writes) = EmptyAccumulator::append(&EmptyReader, 0, &event_hashes)?; 192 | writes 193 | .into_iter() 194 | .map(|(pos, hash)| batch.put::(&(version, pos), &hash)) 195 | .collect::>()?; 196 | 197 | Ok(root_hash) 198 | } 199 | } 200 | ``` 201 | 202 | -------------------------------------------------------------------------------- /storage/accumulator.md: -------------------------------------------------------------------------------- 1 | # Accumulator 2 | 3 | ## 概念: 4 | 5 | **Merkle Accumulator就是一棵Merkle树,想象一个merkle树的结构,每一个父节点都是两个子节点的hash,这就要求子节点必须成对出现,不能出现一个节点的出度是1的情况,但是在插入的过程中一定会出现这种情况,为此,我们使用Placeholder Nodes来填补空白** 6 | 7 | **Merkle Accumulator还把节点分成了 Frozen Nodes & Non-frozen Nodes,Frozen的意思就是这个节点的值是不会变的,也就是说他的子树的所有结构都已经固定了,不可能随着插入节点而变化了,也就是说他的子树里面不能含有Placeholder Nodes ** 8 | 9 | **这一部分是storage实现的最底层的部分,其他的比如eventstroage等都是基于这个模块实现的 ** 10 | 11 | ## 代码: 12 | 13 | ####定义了几个接口和结构体,比较好理解。 14 | 15 | ```rust 16 | /// Defines the interface between `MerkleAccumulator` and underlying storage. 17 | pub trait HashReader { 18 | /// Return `HashValue` carried by the node at `Position`. 19 | fn get(&self, position: Position) -> Result; 20 | } 21 | 22 | /// A `Node` in a `MerkleAccumulator` tree is a `HashValue` at a `Position` 23 | type Node = (Position, HashValue); 24 | 25 | /// In this live Merkle Accumulator algorithms. 26 | pub struct MerkleAccumulator { 27 | reader: PhantomData, 28 | hasher: PhantomData, 29 | } 30 | 31 | impl MerkleAccumulator 32 | where 33 | R: HashReader, 34 | H: CryptoHasher, 35 | { 36 | /// Given an existing Merkle Accumulator (represented by `num_existing_leaves` and a `reader` 37 | /// that is able to fetch all existing frozen nodes), and a list of leaves to be appended, 38 | /// returns the result root hash and new nodes to be frozen. 39 | pub fn append( 40 | reader: &R, 41 | num_existing_leaves: u64, 42 | new_leaves: &[HashValue], 43 | ) -> Result<(HashValue, Vec)> { 44 | MerkleAccumulatorView::::new(reader, num_existing_leaves).append(new_leaves) 45 | } 46 | 47 | /// Get proof of inclusion of the leaf at `leaf_index` in this Merkle Accumulator of 48 | /// `num_leaves` leaves in total. Siblings are read via `reader` (or generated dynamically 49 | /// if they are non-frozen). 50 | /// 51 | /// See [`types::proof::AccumulatorProof`] for proof format. 52 | pub fn get_proof(reader: &R, num_leaves: u64, leaf_index: u64) -> Result { 53 | MerkleAccumulatorView::::new(reader, num_leaves).get_proof(leaf_index) 54 | } 55 | } 56 | ``` 57 | 58 | #### 实际实现: 59 | 60 | ```rust 61 | /// Actual implementation of Merkle Accumulator algorithms, which carries the `reader` and 62 | /// `num_leaves` on an instance for convenience 63 | struct MerkleAccumulatorView<'a, R, H> { 64 | reader: &'a R, 65 | num_leaves: u64, 66 | hasher: PhantomData, 67 | } 68 | 69 | impl<'a, R, H> MerkleAccumulatorView<'a, R, H> 70 | where 71 | R: HashReader, 72 | H: CryptoHasher, 73 | { 74 | fn new(reader: &'a R, num_leaves: u64) -> Self { 75 | Self { 76 | reader, 77 | num_leaves, 78 | hasher: PhantomData, 79 | } 80 | } 81 | 82 | /// implementation for pub interface `MerkleAccumulator::append` 83 | ////实现了append的操作,如果不看也没关系,理解干了什么就行 84 | fn append(&self, new_leaves: &[HashValue]) -> Result<(HashValue, Vec)> { 85 | // Deal with the case where new_leaves is empty 86 | if new_leaves.is_empty() { 87 | if self.num_leaves == 0 { 88 | return Ok((*ACCUMULATOR_PLACEHOLDER_HASH, Vec::new())); 89 | } else { 90 | let root_hash = self.get_hash(Position::get_root_position(self.num_leaves - 1))?; 91 | return Ok((root_hash, Vec::new())); 92 | } 93 | } 94 | 95 | let num_new_leaves = new_leaves.len(); 96 | let last_new_leaf_idx = self.num_leaves + num_new_leaves as u64 - 1; 97 | let root_level = Position::get_root_position(last_new_leaf_idx).get_level() as usize; 98 | let mut to_freeze = Vec::with_capacity(Self::max_to_freeze(num_new_leaves, root_level)); 99 | 100 | // create one new node for each new leaf hash 101 | let mut current_level = self.gen_leaf_level(new_leaves); 102 | Self::record_to_freeze( 103 | &mut to_freeze, 104 | ¤t_level, 105 | false, /* has_non_frozen */ 106 | ); 107 | 108 | // loop starting from leaf level, upwards till root_level - 1, 109 | // making new nodes of parent level and recording frozen ones. 110 | //从叶节点递推到根节点,在这过程中,检查是不是使用了placeholder,一旦使用了,那么在这之上的所有节点都会变成non forzen的,值得注意的死活,每一次的gen-parent-level是一层一层进行的,即每次生成一整个level 111 | let mut has_non_frozen = false; 112 | for _ in 0..root_level { 113 | let (parent_level, placeholder_used) = self.gen_parent_level(¤t_level)?; 114 | 115 | // If a placeholder node is used to generate the right most node of a certain level, 116 | // such level and all its parent levels have a non-frozen right most node. 117 | has_non_frozen |= placeholder_used; 118 | Self::record_to_freeze(&mut to_freeze, &parent_level, has_non_frozen); 119 | 120 | current_level = parent_level; 121 | } 122 | 123 | assert_eq!(current_level.len(), 1, "must conclude in single root node"); 124 | Ok((current_level.first().expect("unexpected None").1, to_freeze)) 125 | } 126 | 127 | 128 | 129 | 130 | 131 | 132 | /// upper bound of num of frozen nodes: 133 | /// new leaves and resulting frozen internal nodes forming a complete binary subtree 134 | /// num_new_leaves * 2 - 1 < num_new_leaves * 2 135 | /// and the full route from root of that subtree to the accumulator root turns frozen 136 | /// height - (log2(num_new_leaves) + 1) < height - 1 = root_level 137 | fn max_to_freeze(num_new_leaves: usize, root_level: usize) -> usize { 138 | num_new_leaves * 2 + root_level 139 | } 140 | 141 | 142 | fn hash_internal_node(left: HashValue, right: HashValue) -> HashValue { 143 | MerkleTreeInternalNode::::new(left, right).hash() 144 | } 145 | 146 | 147 | /// Given leaf level hashes, create leaf level nodes 148 | fn gen_leaf_level(&self, new_leaves: &[HashValue]) -> Vec { 149 | new_leaves 150 | .iter() 151 | .enumerate() 152 | .map(|(i, hash)| (Position::from_leaf_index(self.num_leaves + i as u64), *hash)) 153 | .collect() 154 | } 155 | 156 | /// Given a level of new nodes (frozen or not), return new nodes on its parent level, and 157 | /// a boolean value indicating whether a placeholder node is used to construct the last node 158 | //只有last node才会可能使用place holder(凑整) 159 | fn gen_parent_level(&self, current_level: &[Node]) -> Result<((Vec, bool))> { 160 | let mut parent_level: Vec = Vec::with_capacity(current_level.len() / 2 + 1); 161 | let mut iter = current_level.iter().peekable(); 162 | 163 | // first node may be a right child, in that case pair it with its existing sibling 164 | let (first_pos, first_hash) = iter.peek().expect("Current level is empty"); 165 | if first_pos.get_direction_for_self() == NodeDirection::Right { 166 | parent_level.push(( 167 | first_pos.get_parent(), 168 | Self::hash_internal_node(self.reader.get(first_pos.get_sibling())?, *first_hash), 169 | )); 170 | iter.next(); 171 | } 172 | 173 | // walk through in pairs of siblings, use placeholder as last right sibling if necessary 174 | let mut placeholder_used = false; 175 | while let Some((left_pos, left_hash)) = iter.next() { 176 | let right_hash = match iter.next() { 177 | Some((_, h)) => h, 178 | None => { 179 | placeholder_used = true; 180 | &ACCUMULATOR_PLACEHOLDER_HASH 181 | } 182 | }; 183 | 184 | parent_level.push(( 185 | left_pos.get_parent(), 186 | Self::hash_internal_node(*left_hash, *right_hash), 187 | )); 188 | } 189 | 190 | Ok((parent_level, placeholder_used)) 191 | } 192 | 193 | /// append a level of new nodes into output vector, skip the last one if it's a non-frozen node 194 | fn record_to_freeze(to_freeze: &mut Vec, level: &[Node], has_non_frozen: bool) { 195 | to_freeze.extend( 196 | level 197 | .iter() 198 | .take(level.len() - has_non_frozen as usize) 199 | .cloned(), 200 | ) 201 | } 202 | 203 | fn get_hash(&self, position: Position) -> Result { 204 | if position.is_placeholder(self.num_leaves - 1) { 205 | Ok(*ACCUMULATOR_PLACEHOLDER_HASH) 206 | } else if position.is_freezable(self.num_leaves - 1) { 207 | self.reader.get(position) 208 | } else { 209 | // non-frozen non-placeholder node 210 | Ok(Self::hash_internal_node( 211 | self.get_hash(position.get_left_child())?, 212 | self.get_hash(position.get_right_child())?, 213 | )) 214 | } 215 | } 216 | 217 | /// implementation for pub interface `MerkleAccumulator::get_proof` 218 | fn get_proof(&self, leaf_index: u64) -> Result { 219 | ensure!( 220 | leaf_index < self.num_leaves, 221 | "invalid leaf_index {}, num_leaves {}", 222 | leaf_index, 223 | self.num_leaves 224 | ); 225 | 226 | let leaf_pos = Position::from_leaf_index(leaf_index); 227 | let root_pos = Position::get_root_position(self.num_leaves - 1); 228 | 229 | let siblings: Vec = leaf_pos 230 | .iter_ancestor_sibling() 231 | .take(root_pos.get_level() as usize) 232 | .map(|p| self.get_hash(p)) 233 | .collect::>>()? 234 | .into_iter() 235 | .rev() 236 | .collect(); 237 | 238 | Ok(AccumulatorProof::new(siblings)) 239 | } 240 | } 241 | ``` 242 | 243 | 244 | 245 | 246 | 247 | -------------------------------------------------------------------------------- /storage/storage.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: storage 3 | title: Storage 4 | custom_edit_url: https://github.com/libra/libra/edit/master/storage/README.md 5 | --- 6 | 7 | ###最上层的是一个ledger,一个ledger中包含着一棵transaction Accumulator的root,指向包含很多个transaction info模块的一个transaction Accumulator。这个accumulator的每一个节点就是一个transaction info块,这个块中又包含了一颗sparse merkle tree(作为状态树)的树根,和一棵merkle accumulator的树根(作为event tree) 8 | 9 | ###最上层的ledger info的作用:Validators sign the corresponding LedgerInfo structure every time they agree on a set of transactions and their execution outcome. 10 | 11 | 12 | 13 | ## 下文来自https://github.com/libra/libra/edit/master/storage/README.md 14 | 15 | # Storage 16 | 17 | The storage module provides reliable and efficient persistent storage for the 18 | entire set of data on the Libra Blockchain, as well as the necessary data used 19 | internally by Libra Core. 20 | 21 | ## Overview 22 | 23 | The storage module is designed to serve two primary purposes: 24 | 25 | 1. Persist the blockchain data, specifically the transactions and their outputs 26 | that have been agreed by validators via consensus protocol. 27 | 2. Provide a response with Merkle proofs to any query that asks for a part of the 28 | blockchain data. A client can easily verify the integrity of the response if 29 | they have obtained the correct root hash. 30 | 31 | The Libra Blockchain can be viewed as a Merkle tree consisting of the following 32 | components: 33 | 34 | ![data](https://developers.libra.org/docs/assets/data.png) 35 | 36 | 37 | 38 | #### 39 | 40 | ### Ledger History 41 | 42 | Ledger history is represented by a Merkle accumulator. Each time a transaction 43 | `T` is added to the blockchain, a *TransactionInfo* structure containing the 44 | transaction `T`, the root hash for the state Merkle tree after the execution of 45 | `T` and the root hash for the event Merkle tree generated by `T` is appended to 46 | the accumulator. 47 | 48 | ### Ledger State 49 | 50 | The ledger state at each version is represented by a sparse Merkle tree that has the 51 | state of all accounts. The keys are the 256-bit hash of the addresses, and their 52 | corresponding value is the state of the entire account serialized as a binary 53 | blob. While a tree of size `2^256` is an intractable representation, subtrees 54 | consisting entirely of empty nodes are replaced with a placeholder value, and 55 | subtrees consisting of exactly one leaf are replaced with a single node. 56 | 57 | While each *TransactionInfo* structure points to a different state tree, the new 58 | tree can reuse unchanged portion of the previous tree, forming a persistent data 59 | structure. 60 | 61 | ### Events 62 | 63 | Each transaction emits a list of events and those events form a Merkle accumulator. 64 | Similar to the state Merkle tree, the root hash of the event accumulator of a 65 | transaction is recorded in the corresponding *TransactionInfo* structure. 66 | 67 | ### Ledger Info and Signatures 68 | 69 | A *LedgerInfo* structure that has the root hash of the ledger history 70 | accumulator at some version and other metadata is a binding commitment to 71 | the ledger history up to this version. Validators sign the corresponding 72 | *LedgerInfo* structure every time they agree on a set of transactions and their 73 | execution outcome. For each *LedgerInfo* structure that is stored, a set of 74 | signatures on this structure from validators are also stored, so 75 | clients can verify the structure if they have obtained the public key of each 76 | validator. 77 | 78 | ## Implementation Details 79 | 80 | The storage module uses [RocksDB](https://rocksdb.org/) as its physical storage 81 | engine. Since the storage module needs to store multiple types of data, and 82 | key-value pairs in RocksDB are byte arrays, there is a wrapper on top of RocksDB 83 | to deal with the serialization of keys and values. This wrapper enforces that all data in and 84 | out of the DB is structured according to predefined schemas. 85 | 86 | The core module that implements the main functionalities is called *LibraDB*. 87 | While we use a single RocksDB instance to store the entire set of data, related 88 | data are grouped into logical stores — for example, ledger store, state store, 89 | and transaction store, etc. 90 | 91 | For the sparse Merkle tree that represents ledger state, we optimize the disk 92 | layout by using branch nodes with 16 children that represents 4-level subtrees 93 | and extension nodes that represents a path without branches. However, we still 94 | simulate a binary tree when computing the root hash and proofs. This modification 95 | results in proofs that are shorter than the ones generated by Ethereum's Merkle 96 | Patricia tree. 97 | 98 | ## How is this module organized? 99 | ``` 100 | storage 101 | └── accumulator # Implementation of Merkle accumulator. 102 | └── libradb # Implementation of LibraDB. 103 | └── schemadb # Schematized wrapper on top of RocksDB. 104 | └── scratchpad # In-memory representation of Libra core data structures used by execution. 105 | └── sparse_merkle # Implementation of sparse Merkle tree. 106 | └── state_view # An abstraction layer representing a snapshot of state where the Move VM reads data. 107 | └── storage_client # A Rust wrapper on top of GRPC clients. 108 | └── storage_proto # All interfaces provided by the storage module. 109 | └── storage_service # Storage module as a GRPC service. 110 | ``` 111 | 112 | ###### 注:state_view和scratchpad以及schemadb偷懒没有包括,主要分析了这一部分的框架,后续慢慢完善 113 | 114 | -------------------------------------------------------------------------------- /storage/storage_service&client.md: -------------------------------------------------------------------------------- 1 | # storage_service 2 | 3 | 4 | 5 | ```rust 6 | /// Starts storage service according to config. 7 | pub fn start_storage_service(config: &NodeConfig) -> ServerHandle { 8 | let (storage_service, shutdown_receiver) = StorageService::new(&config.storage.get_dir()); 9 | spawn_service_thread_with_drop_closure( 10 | create_storage(storage_service), 11 | config.storage.address.clone(), 12 | config.storage.port, 13 | "storage", 14 | move || { 15 | shutdown_receiver 16 | .recv() 17 | .expect("Failed to receive on shutdown channel when storage service was dropped") 18 | }, 19 | ) 20 | } 21 | 22 | 23 | impl StorageService { 24 | /// This opens a [`LibraDB`] at `path` and returns a [`StorageService`] instance serving it. 25 | /// 26 | /// A receiver side of a channel is also returned through which one can receive a notice after 27 | /// all resources used by the service including the underlying [`LibraDB`] instance are 28 | /// fully dropped. 29 | /// 30 | /// example: 31 | /// ```no_run, 32 | /// # use storage_service::*; 33 | /// # use std::path::Path; 34 | /// let (service, shutdown_receiver) = StorageService::new(&Path::new("path/to/db")); 35 | /// 36 | /// drop(service); 37 | /// shutdown_receiver.recv().expect("recv() should succeed."); 38 | /// 39 | /// // LibraDB instance is guaranteed to be properly dropped at this point. 40 | /// ``` 41 | pub fn new>(path: &P) -> (Self, mpsc::Receiver<()>) { 42 | let (db_wrapper, shutdown_receiver) = LibraDBWrapper::new(path); 43 | ( 44 | Self { 45 | db: Arc::new(db_wrapper), 46 | }, 47 | shutdown_receiver, 48 | ) 49 | } 50 | } 51 | 52 | 53 | //////StorageService提供了这些功能 54 | impl StorageService { 55 | fn update_to_latest_ledger_inner( 56 | &self, 57 | req: UpdateToLatestLedgerRequest, 58 | ) -> Result { 59 | let rust_req = types::get_with_proof::UpdateToLatestLedgerRequest::from_proto(req)?; 60 | 61 | let (response_items, ledger_info_with_sigs, validator_change_events) = self 62 | .db 63 | .update_to_latest_ledger(rust_req.client_known_version, rust_req.requested_items)?; 64 | 65 | let rust_resp = types::get_with_proof::UpdateToLatestLedgerResponse { 66 | response_items, 67 | ledger_info_with_sigs, 68 | validator_change_events, 69 | }; 70 | 71 | Ok(rust_resp.into_proto()) 72 | } 73 | 74 | fn get_transactions_inner( 75 | &self, 76 | req: GetTransactionsRequest, 77 | ) -> Result { 78 | let rust_req = storage_proto::GetTransactionsRequest::from_proto(req)?; 79 | 80 | let txn_list_with_proof = self.db.get_transactions( 81 | rust_req.start_version, 82 | rust_req.batch_size, 83 | rust_req.ledger_version, 84 | rust_req.fetch_events, 85 | )?; 86 | 87 | let rust_resp = storage_proto::GetTransactionsResponse::new(txn_list_with_proof); 88 | 89 | Ok(rust_resp.into_proto()) 90 | } 91 | 92 | fn get_account_state_with_proof_by_state_root_inner( 93 | &self, 94 | req: GetAccountStateWithProofByStateRootRequest, 95 | ) -> Result { 96 | let rust_req = storage_proto::GetAccountStateWithProofByStateRootRequest::from_proto(req)?; 97 | 98 | let (account_state_blob, sparse_merkle_proof) = 99 | self.db.get_account_state_with_proof_by_state_root( 100 | rust_req.address, 101 | rust_req.state_root_hash, 102 | )?; 103 | 104 | let rust_resp = storage_proto::GetAccountStateWithProofByStateRootResponse { 105 | account_state_blob, 106 | sparse_merkle_proof, 107 | }; 108 | 109 | Ok(rust_resp.into_proto()) 110 | } 111 | 112 | fn save_transactions_inner( 113 | &self, 114 | req: SaveTransactionsRequest, 115 | ) -> Result { 116 | let rust_req = storage_proto::SaveTransactionsRequest::from_proto(req)?; 117 | self.db.save_transactions( 118 | &rust_req.txns_to_commit, 119 | rust_req.first_version, 120 | &rust_req.ledger_info_with_signatures, 121 | )?; 122 | Ok(SaveTransactionsResponse::new()) 123 | } 124 | 125 | fn get_executor_startup_info_inner(&self) -> Result { 126 | let info = self.db.get_executor_startup_info()?; 127 | let rust_resp = storage_proto::GetExecutorStartupInfoResponse { info }; 128 | Ok(rust_resp.into_proto()) 129 | } 130 | } 131 | 132 | 133 | ////////还是直接调用inner,然后把结果作为grpc的结果返回 134 | impl Storage for StorageService { 135 | fn update_to_latest_ledger( 136 | &mut self, 137 | ctx: grpcio::RpcContext<'_>, 138 | req: UpdateToLatestLedgerRequest, 139 | sink: grpcio::UnarySink, 140 | ) { 141 | debug!("[GRPC] Storage::update_to_latest_ledger"); 142 | let _timer = SVC_COUNTERS.req(&ctx); 143 | let resp = self.update_to_latest_ledger_inner(req); 144 | provide_grpc_response(resp, ctx, sink); 145 | } 146 | 147 | fn get_transactions( 148 | &mut self, 149 | ctx: grpcio::RpcContext, 150 | req: GetTransactionsRequest, 151 | sink: grpcio::UnarySink, 152 | ) { 153 | debug!("[GRPC] Storage::get_transactions"); 154 | let _timer = SVC_COUNTERS.req(&ctx); 155 | let resp = self.get_transactions_inner(req); 156 | provide_grpc_response(resp, ctx, sink); 157 | } 158 | 159 | fn get_account_state_with_proof_by_state_root( 160 | &mut self, 161 | ctx: grpcio::RpcContext, 162 | req: GetAccountStateWithProofByStateRootRequest, 163 | sink: grpcio::UnarySink, 164 | ) { 165 | debug!("[GRPC] Storage::get_account_state_with_proof_by_state_root"); 166 | let _timer = SVC_COUNTERS.req(&ctx); 167 | let resp = self.get_account_state_with_proof_by_state_root_inner(req); 168 | provide_grpc_response(resp, ctx, sink); 169 | } 170 | 171 | fn save_transactions( 172 | &mut self, 173 | ctx: grpcio::RpcContext, 174 | req: SaveTransactionsRequest, 175 | sink: grpcio::UnarySink, 176 | ) { 177 | debug!("[GRPC] Storage::save_transactions"); 178 | let _timer = SVC_COUNTERS.req(&ctx); 179 | let resp = self.save_transactions_inner(req); 180 | provide_grpc_response(resp, ctx, sink); 181 | } 182 | 183 | fn get_executor_startup_info( 184 | &mut self, 185 | ctx: grpcio::RpcContext, 186 | _req: GetExecutorStartupInfoRequest, 187 | sink: grpcio::UnarySink, 188 | ) { 189 | debug!("[GRPC] Storage::get_executor_startup_info"); 190 | let _timer = SVC_COUNTERS.req(&ctx); 191 | let resp = self.get_executor_startup_info_inner(); 192 | provide_grpc_response(resp, ctx, sink); 193 | } 194 | } 195 | 196 | 197 | 198 | ///////////////////main中的实现,包装了一个节点,然后运行节点,开启这些服务 199 | impl StorageNode { 200 | pub fn new(node_config: NodeConfig) -> Self { 201 | StorageNode { node_config } 202 | } 203 | 204 | pub fn run(&self) -> Result<()> { 205 | info!("Starting storage node"); 206 | 207 | let _handle = storage_service::start_storage_service(&self.node_config); 208 | 209 | // Start Debug interface 210 | let debug_service = 211 | node_debug_interface_grpc::create_node_debug_interface(NodeDebugService::new()); 212 | let _debug_handle = spawn_service_thread( 213 | debug_service, 214 | self.node_config.storage.address.clone(), 215 | self.node_config.debug_interface.storage_node_debug_port, 216 | "debug_service", 217 | ); 218 | 219 | info!("Started Storage Service"); 220 | loop { 221 | thread::park(); 222 | } 223 | } 224 | } 225 | 226 | fn main() { 227 | let (config, _logger, _args) = setup_executable( 228 | "Libra Storage node".to_string(), 229 | vec![ARG_PEER_ID, ARG_CONFIG_PATH, ARG_DISABLE_LOGGING], 230 | ); 231 | 232 | let storage_node = StorageNode::new(config); 233 | 234 | storage_node.run().expect("Unable to run storage node"); 235 | } 236 | 237 | ``` 238 | 239 | # client: 240 | 241 | #### read_interfaces: 242 | 243 | ```rust 244 | /// This provides storage read interfaces backed by real storage service. 245 | #[derive(Clone)] 246 | pub struct StorageReadServiceClient { 247 | client: storage_grpc::StorageClient, 248 | } 249 | 250 | impl StorageReadServiceClient { 251 | /// Constructs a `StorageReadServiceClient` with given host and port. 252 | pub fn new(env: Arc, host: &str, port: u16) -> Self { 253 | let channel = ChannelBuilder::new(env).connect(&format!("{}:{}", host, port)); 254 | let client = storage_grpc::StorageClient::new(channel); 255 | StorageReadServiceClient { client } 256 | } 257 | } 258 | 259 | impl StorageRead for StorageReadServiceClient { 260 | fn update_to_latest_ledger( 261 | &self, 262 | client_known_version: Version, 263 | requested_items: Vec, 264 | ) -> Result<( 265 | Vec, 266 | LedgerInfoWithSignatures, 267 | Vec, 268 | )> { 269 | block_on(self.update_to_latest_ledger_async(client_known_version, requested_items)) 270 | }///可以看到这里调用了加async后缀的函数 271 | 272 | 273 | fn update_to_latest_ledger_async( 274 | &self, 275 | client_known_version: Version, 276 | requested_items: Vec, 277 | ) -> Pin< 278 | Box< 279 | dyn Future< 280 | Output = Result<( 281 | Vec, 282 | LedgerInfoWithSignatures, 283 | Vec, 284 | )>, 285 | > + Send, 286 | >, 287 | > { 288 | let req = UpdateToLatestLedgerRequest { 289 | client_known_version, 290 | requested_items, 291 | }; 292 | convert_grpc_response(self.client.update_to_latest_ledger_async(&req.into_proto())) 293 | .map(|resp| { 294 | let rust_resp = UpdateToLatestLedgerResponse::from_proto(resp?)?; 295 | Ok(( 296 | rust_resp.response_items, 297 | rust_resp.ledger_info_with_sigs, 298 | rust_resp.validator_change_events, 299 | )) 300 | }) 301 | .boxed() 302 | } 303 | 304 | fn get_transactions( 305 | &self, 306 | start_version: Version, 307 | batch_size: u64, 308 | ledger_version: Version, 309 | fetch_events: bool, 310 | ) -> Result { 311 | block_on(self.get_transactions_async( 312 | start_version, 313 | batch_size, 314 | ledger_version, 315 | fetch_events, 316 | )) 317 | } 318 | 319 | fn get_transactions_async( 320 | &self, 321 | start_version: Version, 322 | batch_size: u64, 323 | ledger_version: Version, 324 | fetch_events: bool, 325 | ) -> Pin> + Send>> { 326 | let req = 327 | GetTransactionsRequest::new(start_version, batch_size, ledger_version, fetch_events); 328 | convert_grpc_response(self.client.get_transactions_async(&req.into_proto())) 329 | .map(|resp| { 330 | let rust_resp = GetTransactionsResponse::from_proto(resp?)?; 331 | Ok(rust_resp.txn_list_with_proof) 332 | }) 333 | .boxed() 334 | } 335 | 336 | fn get_account_state_with_proof_by_state_root( 337 | &self, 338 | address: AccountAddress, 339 | state_root_hash: HashValue, 340 | ) -> Result<(Option, SparseMerkleProof)> { 341 | block_on(self.get_account_state_with_proof_by_state_root_async(address, state_root_hash)) 342 | } 343 | 344 | fn get_account_state_with_proof_by_state_root_async( 345 | &self, 346 | address: AccountAddress, 347 | state_root_hash: HashValue, 348 | ) -> Pin, SparseMerkleProof)>> + Send>> 349 | { 350 | let req = GetAccountStateWithProofByStateRootRequest::new(address, state_root_hash); 351 | convert_grpc_response( 352 | self.client 353 | .get_account_state_with_proof_by_state_root_async(&req.into_proto()), 354 | ) 355 | .map(|resp| { 356 | let resp = GetAccountStateWithProofByStateRootResponse::from_proto(resp?)?; 357 | Ok(resp.into()) 358 | }) 359 | .boxed() 360 | } 361 | 362 | fn get_executor_startup_info(&self) -> Result> { 363 | block_on(self.get_executor_startup_info_async()) 364 | } 365 | 366 | fn get_executor_startup_info_async( 367 | &self, 368 | ) -> Pin>> + Send>> { 369 | let proto_req = GetExecutorStartupInfoRequest::new(); 370 | convert_grpc_response(self.client.get_executor_startup_info_async(&proto_req)) 371 | .map(|resp| { 372 | let resp = GetExecutorStartupInfoResponse::from_proto(resp?)?; 373 | Ok(resp.info) 374 | }) 375 | .boxed() 376 | } 377 | } 378 | 379 | ``` 380 | 381 | 剩下的其实都差不多,还有write啊各种,可以看storage_client客户端,以后再补充orz 382 | 383 | --------------------------------------------------------------------------------