Skip to content

Instantly share code, notes, and snippets.

@doitian
Last active March 21, 2018 03:11
Show Gist options
  • Select an option

  • Save doitian/eb1ad0ee4af9229ea9956773a2e303e5 to your computer and use it in GitHub Desktop.

Select an option

Save doitian/eb1ad0ee4af9229ea9956773a2e303e5 to your computer and use it in GitHub Desktop.
Parity Bitcoin memory pool annotations
// 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