Last active
March 21, 2018 03:11
-
-
Save doitian/eb1ad0ee4af9229ea9956773a2e303e5 to your computer and use it in GitHub Desktop.
Parity Bitcoin memory pool annotations
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // miner/src/memory_pool.rs | |
| // impl MemoryPool | |
| // https://github.com/paritytech/parity-bitcoin/blob/687f78598478e31ff556a385c07b4035ad2d4b8b/miner/src/memory_pool.rs#L652 | |
| pub fn insert_verified(&mut self, t: IndexedTransaction) { | |
| // make_entry 比较重要的一步是递归的找到在 pool 中的祖父 tx,如果 A input 指向 B, | |
| // B 是 A 的父 tx。A 的祖父 tx 是 A 的所有父 tx 和每个父 tx 的祖父 tx 的集合。 | |
| let entry = self.make_entry(t); | |
| let descendants = self.storage.remove_by_parent_hash(&entry.hash); | |
| self.storage.insert(entry); | |
| // 处理 orphan tx (tx 依赖一个还不存在的父 tx) 的办法: | |
| // 1. 当插入一个 tx 前,通过 by_input 递归的从 pool 里删除所有它的子孙 tx | |
| // 2. 插入 tx 后,再重新插入子孙 tx | |
| if let Some(descendants_iter) = descendants.map(|d| d.into_iter()) { | |
| for descendant in descendants_iter { | |
| let descendant_entry = self.make_entry(descendant); | |
| self.storage.insert(descendant_entry); | |
| } | |
| } | |
| } | |
| // impl Storage | |
| // https://github.com/paritytech/parity-bitcoin/blob/687f78598478e31ff556a385c07b4035ad2d4b8b/miner/src/memory_pool.rs#L299 | |
| pub fn insert(&mut self, entry: Entry) { | |
| // 统计 pool 总的 tx 空间 | |
| self.transactions_size_in_bytes += entry.size; | |
| // 使用 by_input 可以通过某个 tx 的 hash 找到所有 pool 中花费它的 tx 集合。 | |
| for input_hash in entry.transaction.inputs.iter().map(|input| &input.previous_output.hash) { | |
| self.references.by_input.entry(input_hash.clone()).or_insert_with(HashSet::new).insert(entry.hash.clone()); | |
| } | |
| // 更新 package 属性,一个 package 是指一个 tx 和它的所有子孙 tx 构成的集合。 | |
| for ancestor_hash in &entry.ancestors { | |
| // 根节点是不依赖 pool 中其它 tx 的 tx,是在下面的 if 判断后通过 ordered 插入的。 | |
| if let Some(ancestor_entry) = self.by_hash.get_mut(ancestor_hash) { | |
| let removed = self.references.ordered.by_package_score.remove(&(ancestor_entry as &Entry).into()); | |
| ancestor_entry.package_size += entry.size; | |
| ancestor_entry.package_miner_fee += entry.package_miner_fee; | |
| ancestor_entry.package_miner_virtual_fee += entry.package_miner_virtual_fee; | |
| if removed { | |
| self.references.ordered.by_package_score.insert((ancestor_entry as &Entry).into()); | |
| } | |
| } | |
| } | |
| // insert either to pending queue or to orderings | |
| if self.references.has_in_pool_ancestors(None, &self.by_hash, &entry.transaction) { | |
| self.references.pending.insert(entry.hash.clone()); | |
| } | |
| else { | |
| // 无依赖的根节点进入排序队列 | |
| self.references.ordered.insert_to_orderings(&entry); | |
| } | |
| // 记录双花,这里记录的是 pool 中的 tx 花掉的 tx output,要完整的检查双花还需要检查是不是在链上已经被花掉了。 | |
| // Memory pool 里的 tx 要求是不能有冲突的,不能有两个 tx 有相同的 input | |
| for input in &entry.transaction.inputs { | |
| let previous_tx = self.by_previous_output.insert(input.previous_output.clone().into(), entry.hash.clone()); | |
| assert_eq!(previous_tx, None); // transaction must be verified before => no double spend | |
| } | |
| // add to by_hash storage | |
| self.by_hash.insert(entry.hash.clone(), entry); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment