Bitcoin源码阅读笔记二

bitcoinj core篇

AbstractBlockChain.java

弄懂这个抽象类实现的功能对源码的理解非常重要,因为他是bitcoinj主要使用的7大对象之一。AbstractBlockChain的实现需要BlockStore存储所有数据、SPVBlockStore存储在SPV模式下的轻量数据、Block是组成链的必要数据结构、连接Wallet帮助其接收交易数据和通知。AbstractBlockChain有两个子类:BlockChain是一个非常简单的子类,实现了简易的交易验证,帮助SPV模式下的节点高效率的校验header信息而不校验完成的信息,这一点对推广移动应用非常有价值。FullPrunedBlockChain联合FullPrunedBlockStore实现了对block的完整校验。

1
2
3
4
5
6
7
8
public abstract class AbstractBlockChain{
private static final Logger log = LoggerFactory.getLogger(AbstractBlockChain.class);
protected final ReentrantLock lock = Threading.lock("blockchain");

/** Keeps a map of block hashes to StoredBlocks. */
private final BlockStore blockStore;

}

BlockStore将会在后面详细介绍,这段代码中值得注意的是ReentrantLock。多线程和并发不是什么新内容,一般使用核心类库Thread构造、启动和操作线程。Java语言中包括了跨线程传达并发性约束的构造Synchronized和volatile。volatile主要用在多个线程感知实例变量被更改了场合,从而使得各个线程获得最新的值。它强制线程每次从主内存中讲到变量,而不是从线程的私有内存中读取变量,从而保证了数据的可见性。相比于volatile, synchronized更重量级一点不仅可以修饰变量还可以修饰方法。并且在保证了可见性的同事也保证了原子性。

java.util.concurrent.lock 中的 Lock 框架是锁定的一个抽象,它允许把锁定的实现作为 Java 类,而不是作为语言的特性来实现。这就为 Lock 的多种实现留下了空间,各种实现可能有不同的调度算法、性能特性或者锁定语义。 ReentrantLock 类实现了 Lock ,它拥有与 synchronized 相同的并发性和内存语义,但是添加了类似锁投票、定时锁等候和可中断锁等候的一些特性。此外,它还提供了在激烈争用情况下更佳的性能。(换句话说,当许多线程都想访问共享资源时,JVM 可以花更少的时候来调度线程,把更多时间用在执行线程上。)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**
* Tracks the top of the best known chain.<p>
*
* Following this one down to the genesis block produces the story of the economy from the creation of Bitcoin
* until the present day. The chain head can change if a new set of blocks is received that results in a chain of
* greater work than the one obtained by following this one down. In that case a reorganize is triggered,
* potentially invalidating transactions in our wallet.
*/
protected StoredBlock chainHead;

// TODO: Scrap this and use a proper read/write for all of the block chain objects.
// The chainHead field is read/written synchronized with this object rather than BlockChain. However writing is
// also guaranteed to happen whilst BlockChain is synchronized (see setChainHead). The goal of this is to let
// clients quickly access the chain head even whilst the block chain is downloading and thus the BlockChain is
// locked most of the time.
private final Object chainHeadLock = new Object();

protected final NetworkParameters params;
private final CopyOnWriteArrayList<ListenerRegistration<NewBestBlockListener>> newBestBlockListeners;
private final CopyOnWriteArrayList<ListenerRegistration<ReorganizeListener>> reorganizeListeners;
private final CopyOnWriteArrayList<ListenerRegistration<TransactionReceivedInBlockListener>> transactionReceivedListeners;

class OrphanBlock {
final Block block;
final List<Sha256Hash> filteredTxHashes;
final Map<Sha256Hash, Transaction> filteredTxn;
OrphanBlock(Block block, @Nullable List<Sha256Hash> filteredTxHashes, @Nullable Map<Sha256Hash, Transaction> filteredTxn) {
final boolean filtered = filteredTxHashes != null && filteredTxn != null;
Preconditions.checkArgument((block.transactions == null && filtered)
|| (block.transactions != null && !filtered));
this.block = block;
this.filteredTxHashes = filteredTxHashes;
this.filteredTxn = filteredTxn;
}
}
// Holds blocks that we have received but can't plug into the chain yet, eg because they were created whilst we
// were downloading the block chain.
private final LinkedHashMap<Sha256Hash, OrphanBlock> orphanBlocks = new LinkedHashMap<Sha256Hash, OrphanBlock>();

孤立块代表接收到但是没有被记入主链的区块,可能由于网络传播的延迟导致同一时间段内发现的两个区块,其中一个更快的传播到了更多的节点处。孤立块的变化情况可以用来反映区块链网络中自私挖掘而情况,因为自私挖掘策略的执行会导致被抛弃的区块数量增加。关于自私挖掘(Selfish Mining)后面我会整理论文专门写一篇来详细的介绍。

removeListener()addListener()批量注销和注册三个监听分别是add|removeReorganizeListeneradd|removeNewBestBlockListeneradd|removeTransactionReceivedListener

坚持原创技术分享,记录点滴成长历程!