Class AbstractBlockChain
- Direct Known Subclasses:
BlockChain
,FullPrunedBlockChain
An AbstractBlockChain holds a series of Block
objects, links them together, and knows how to verify that
the chain follows the rules of the NetworkParameters
for this chain.
It can be connected to a Wallet
, and also TransactionReceivedInBlockListener
s that can receive transactions and
notifications of re-organizations.
An AbstractBlockChain implementation must be connected to a BlockStore
implementation. The chain object
by itself doesn't store any data, that's delegated to the store. Which store you use is a decision best made by
reading the getting started guide, but briefly, fully validating block chains need fully validating stores. In
the lightweight SPV mode, a SPVBlockStore
is the right choice.
This class implements an abstract class which makes it simple to create a BlockChain that does/doesn't do full verification. It verifies headers and is implements most of what is required to implement SPV mode, but also provides callback hooks which can be used to do full verification.
There are two subclasses of AbstractBlockChain that are useful: BlockChain
, which is the simplest
class and implements simplified payment verification. This is a lightweight and efficient mode that does
not verify the contents of blocks, just their headers. A FullPrunedBlockChain
paired with a
H2FullPrunedBlockStore
implements full verification, which is equivalent to
Bitcoin Core. To learn more about the alternative security models, please consult the articles on the
website.
The 'chain' is actually a tree although in normal operation it operates mostly as a list of Block
s.
When multiple new head blocks are found simultaneously, there are multiple stories of the economy competing to become
the one true consensus. This can happen naturally when two miners solve a block within a few seconds of each other,
or it can happen when the chain is under attack.
A reference to the head block of the best known chain is stored. If you can reach the genesis block by repeatedly walking through the prevBlock pointers, then we say this is a full chain. If you cannot reach the genesis block we say it is an orphan chain. Orphan chains can occur when blocks are solved and received during the initial block chain download, or if we connect to a peer that doesn't send us blocks in order.
A reorganize occurs when the blocks that make up the best known chain change. Note that simply adding a new block to the top of the best chain isn't a reorganize, but that a reorganize is always triggered by adding a new block that connects to some other (non best head) block. By "best" we mean the chain representing the largest amount of work done.
Every so often the block chain passes a difficulty transition point. At that time, all the blocks in the last 2016 blocks are examined and a new difficulty target is calculated from them.
-
Nested Class Summary
Modifier and TypeClassDescriptionstatic enum
Indicates whether new Block was on the best chain or not -
Field Summary
Modifier and TypeFieldDescriptionprotected StoredBlock
Tracks the top of the best known chain.static final double
False positive estimation uses a double exponential moving average.static final double
False positive estimation uses a double exponential moving average.protected final ReentrantLock
synchronization lockprotected final NetworkParameters
network parameters for this chain -
Constructor Summary
ConstructorDescriptionAbstractBlockChain
(Context context, List<? extends Wallet> wallets, BlockStore blockStore) Constructs a BlockChain connected to the given list of listeners (wallets) and a store.AbstractBlockChain
(NetworkParameters params, List<? extends Wallet> wallets, BlockStore blockStore) Constructs a BlockChain connected to the given list of listeners (wallets) and a store. -
Method Summary
Modifier and TypeMethodDescriptionboolean
Processes a received block and tries to add it to the chain.boolean
add
(FilteredBlock block) Processes a received block and tries to add it to the chain.final void
addNewBestBlockListener
(Executor executor, NewBestBlockListener listener) Adds aNewBestBlockListener
listener to the chain.void
addNewBestBlockListener
(NewBestBlockListener listener) Adds aNewBestBlockListener
listener to the chain.final void
addReorganizeListener
(Executor executor, ReorganizeListener listener) Adds a genericReorganizeListener
listener to the chain.void
addReorganizeListener
(ReorganizeListener listener) Adds a genericReorganizeListener
listener to the chain.protected abstract StoredBlock
addToBlockStore
(StoredBlock storedPrev, Block block) Adds/updates the givenBlock
with the block store.protected abstract StoredBlock
addToBlockStore
(StoredBlock storedPrev, Block header, TransactionOutputChanges txOutputChanges) Adds/updates the givenStoredBlock
with the block store.final void
addTransactionReceivedListener
(Executor executor, TransactionReceivedInBlockListener listener) Adds a genericTransactionReceivedInBlockListener
listener to the chain.void
Adds a genericTransactionReceivedInBlockListener
listener to the chain.final void
Add a wallet to the BlockChain.protected abstract TransactionOutputChanges
connectTransactions
(int height, Block block) Connect each transaction in block.transactions, verifying them as we go and removing spent outputs If an error is encountered in a transaction, no changes should be made to the underlying BlockStore.protected abstract TransactionOutputChanges
connectTransactions
(StoredBlock newBlock) Load newBlock from BlockStore and connect its transactions, returning changes to the set of unspent transactions.protected abstract void
Disconnect each transaction in the block (after reading it from the block store) Only called if(shouldVerifyTransactions())protected abstract void
doSetChainHead
(StoredBlock chainHead) Called before setting chain head in memory.Returns the hashes of the currently stored orphan blocks and then deletes them from this objects storage.estimateBlockTime
(int height) Returns an estimate of when the given block will be reached, assuming a perfect 10 minute average for each block.final int
Returns theBlockStore
the chain was constructed with.Returns the block at the head of the current best chain.double
The false positive rate is the average over all blockchain transactions of: - 1.0 if the transaction was false-positive (was irrelevant to all listeners) - 0.0 if the transaction was relevant or filtered outcom.google.common.util.concurrent.ListenableFuture<StoredBlock>
getHeightFuture
(int height) Returns a future that completes when the block chain has reached the given height.getOrphanRoot
(Sha256Hash from) An orphan block is one that does not connect to the chain anywhere (ie we can't find its parent, therefore it's an orphan).protected abstract StoredBlock
For a standard BlockChain, this should return blockStore.get(hash), for a FullPrunedBlockChain blockStore.getOnceUndoableStoredBlock(hash)protected VersionTally
boolean
isOrphan
(Sha256Hash block) Returns true if the given block is currently in the orphan blocks list.protected abstract void
Called if we (possibly) previously called disconnectTransaction/connectTransactions, but will not be calling preSetChainHead as a block failed verification.void
Removes the givenNewBestBlockListener
from the chain.void
removeReorganizeListener
(ReorganizeListener listener) Removes the givenReorganizeListener
from the chain.void
Removes the givenTransactionReceivedInBlockListener
from the chain.void
removeWallet
(Wallet wallet) Remove a wallet from the chain.void
Resets estimates of false positives.protected abstract void
rollbackBlockStore
(int height) Rollback the block store to a given height.protected void
setChainHead
(StoredBlock chainHead) protected abstract boolean
Whether or not we are maintaining a set of unspent outputs and are verifying all transactions.protected void
trackFilteredTransactions
(int count) We completed handling of a filtered block.
-
Field Details
-
lock
synchronization lock -
chainHead
Tracks the top of the best known chain.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.
-
params
network parameters for this chain -
FP_ESTIMATOR_ALPHA
public static final double FP_ESTIMATOR_ALPHAFalse positive estimation uses a double exponential moving average.- See Also:
-
FP_ESTIMATOR_BETA
public static final double FP_ESTIMATOR_BETAFalse positive estimation uses a double exponential moving average.- See Also:
-
-
Constructor Details
-
AbstractBlockChain
public AbstractBlockChain(NetworkParameters params, List<? extends Wallet> wallets, BlockStore blockStore) throws BlockStoreException Constructs a BlockChain connected to the given list of listeners (wallets) and a store.- Parameters:
params
- network parameters for this chainwallets
- list of listeners (wallets)blockStore
- where to store blocks- Throws:
BlockStoreException
- if a failure occurs while storing a block
-
AbstractBlockChain
public AbstractBlockChain(Context context, List<? extends Wallet> wallets, BlockStore blockStore) throws BlockStoreException Constructs a BlockChain connected to the given list of listeners (wallets) and a store.- Parameters:
context
- context for this networkwallets
- list of listeners (wallets)blockStore
- where to store blocks- Throws:
BlockStoreException
- if a failure occurs while storing a block
-
-
Method Details
-
addWallet
Add a wallet to the BlockChain. Note that the wallet will be unaffected by any blocks received while it was not part of this BlockChain. This method is useful if the wallet has just been created, and its keys have never been in use, or if the wallet has been loaded along with the BlockChain. Note that adding multiple wallets is not well tested!- Parameters:
wallet
- wallet to add
-
removeWallet
Remove a wallet from the chain.- Parameters:
wallet
- wallet to remove
-
addNewBestBlockListener
Adds aNewBestBlockListener
listener to the chain.- Parameters:
listener
- listener to add
-
addNewBestBlockListener
Adds aNewBestBlockListener
listener to the chain.- Parameters:
executor
- executor to listen onlistener
- listener to add
-
addReorganizeListener
Adds a genericReorganizeListener
listener to the chain.- Parameters:
listener
- listener to add
-
addReorganizeListener
Adds a genericReorganizeListener
listener to the chain.- Parameters:
executor
- executor to listen onlistener
- listener to add
-
addTransactionReceivedListener
Adds a genericTransactionReceivedInBlockListener
listener to the chain.- Parameters:
listener
- listener to add
-
addTransactionReceivedListener
public final void addTransactionReceivedListener(Executor executor, TransactionReceivedInBlockListener listener) Adds a genericTransactionReceivedInBlockListener
listener to the chain.- Parameters:
executor
- executor to listen onlistener
- listener to add
-
removeNewBestBlockListener
Removes the givenNewBestBlockListener
from the chain.- Parameters:
listener
- listener to remove
-
removeReorganizeListener
Removes the givenReorganizeListener
from the chain.- Parameters:
listener
- listener to remove
-
removeTransactionReceivedListener
Removes the givenTransactionReceivedInBlockListener
from the chain.- Parameters:
listener
- listener to remove
-
getBlockStore
Returns theBlockStore
the chain was constructed with. You can use this to iterate over the chain.- Returns:
- the
BlockStore
the chain was constructed with
-
addToBlockStore
protected abstract StoredBlock addToBlockStore(StoredBlock storedPrev, Block block) throws BlockStoreException, VerificationException Adds/updates the givenBlock
with the block store. This version is used when the transactions have not been verified.- Parameters:
storedPrev
- TheStoredBlock
which immediately precedes block.block
- TheBlock
to add/update.- Returns:
- the newly created
StoredBlock
- Throws:
BlockStoreException
- if a failure occurs while storing a blockVerificationException
- if the block is invalid
-
addToBlockStore
protected abstract StoredBlock addToBlockStore(StoredBlock storedPrev, Block header, @Nullable TransactionOutputChanges txOutputChanges) throws BlockStoreException, VerificationException Adds/updates the givenStoredBlock
with the block store. This version is used when the transactions have already been verified to properly spend txOutputChanges.- Parameters:
storedPrev
- TheStoredBlock
which immediately precedes block.header
- TheStoredBlock
to add/update.txOutputChanges
- The total sum of all changes made by this block to the set of open transaction outputs (from a call to connectTransactions), if in fully verifying mode (null otherwise).- Returns:
- the newly created
StoredBlock
- Throws:
BlockStoreException
- if a failure occurs while storing a blockVerificationException
- if the block is invalid
-
rollbackBlockStore
Rollback the block store to a given height. This is currently only supported byBlockChain
instances.- Parameters:
height
- height to roll back to- Throws:
BlockStoreException
- if the operation fails or is unsupported.
-
doSetChainHead
Called before setting chain head in memory. Should write the new head to block store and then commit any database transactions that were started by disconnectTransactions/connectTransactions.- Parameters:
chainHead
- chain head to set- Throws:
BlockStoreException
- if a failure occurs while storing a block
-
notSettingChainHead
Called if we (possibly) previously called disconnectTransaction/connectTransactions, but will not be calling preSetChainHead as a block failed verification. Can be used to abort database transactions that were started by disconnectTransactions/connectTransactions.- Throws:
BlockStoreException
- if a failure occurs while storing a block
-
getStoredBlockInCurrentScope
protected abstract StoredBlock getStoredBlockInCurrentScope(Sha256Hash hash) throws BlockStoreException For a standard BlockChain, this should return blockStore.get(hash), for a FullPrunedBlockChain blockStore.getOnceUndoableStoredBlock(hash)- Parameters:
hash
- hash of block to fetch- Returns:
- block with matching hash
- Throws:
BlockStoreException
- if a failure occurs while storing a block
-
add
Processes a received block and tries to add it to the chain. If there's something wrong with the block an exception is thrown. If the block is OK but cannot be connected to the chain at this time, returns false. If the block can be connected to the chain, returns true. Accessing block's transactions in another thread while this method runs may result in undefined behavior.- Parameters:
block
- block to add- Returns:
- true if block can be connected, false if block is valid but can't be connected
- Throws:
VerificationException
- block is invalid or contains invalid transactionsPrunedException
- a reorg that is too-long for our stored block data has occurred
-
add
Processes a received block and tries to add it to the chain. If there's something wrong with the block an exception is thrown. If the block is OK but cannot be connected to the chain at this time, returns false. If the block can be connected to the chain, returns true.- Parameters:
block
- received block- Returns:
- true if block can be connected, false if block is valid but can't be connected
- Throws:
VerificationException
- if invalid blockPrunedException
- a reorg that is too-long for our stored block data has occurred
-
shouldVerifyTransactions
protected abstract boolean shouldVerifyTransactions()Whether or not we are maintaining a set of unspent outputs and are verifying all transactions. Also indicates that all calls to add() should provide a block containing transactions- Returns:
- true if we are verifying all transactions
-
connectTransactions
protected abstract TransactionOutputChanges connectTransactions(int height, Block block) throws VerificationException, BlockStoreException Connect each transaction in block.transactions, verifying them as we go and removing spent outputs If an error is encountered in a transaction, no changes should be made to the underlying BlockStore. and a VerificationException should be thrown. Only called if(shouldVerifyTransactions())- Parameters:
height
- block height to attach atblock
- block to connect- Returns:
- The full set of all changes made to the set of open transaction outputs.
- Throws:
VerificationException
- if an attempt was made to spend an already-spent output, or if a transaction incorrectly solved an output script.BlockStoreException
- if the block store had an underlying error.
-
connectTransactions
protected abstract TransactionOutputChanges connectTransactions(StoredBlock newBlock) throws VerificationException, BlockStoreException, PrunedException Load newBlock from BlockStore and connect its transactions, returning changes to the set of unspent transactions. If an error is encountered in a transaction, no changes should be made to the underlying BlockStore. Only called if(shouldVerifyTransactions())- Parameters:
newBlock
- block to load- Returns:
- The full set of all changes made to the set of open transaction outputs.
- Throws:
PrunedException
- if newBlock does not exist as aStoredUndoableBlock
in the block store.VerificationException
- if an attempt was made to spend an already-spent output, or if a transaction incorrectly solved an output script.BlockStoreException
- if the block store had an underlying error or newBlock does not exist in the block store at all.
-
drainOrphanBlocks
Returns the hashes of the currently stored orphan blocks and then deletes them from this objects storage. Used by Peer when a filter exhaustion event has occurred and thus any orphan blocks that have been downloaded might be inaccurate/incomplete.- Returns:
- hashes of deleted blocks
-
disconnectTransactions
protected abstract void disconnectTransactions(StoredBlock block) throws PrunedException, BlockStoreException Disconnect each transaction in the block (after reading it from the block store) Only called if(shouldVerifyTransactions())- Parameters:
block
- block to disconnect- Throws:
PrunedException
- if block does not exist as aStoredUndoableBlock
in the block store.BlockStoreException
- if the block store had an underlying error or block does not exist in the block store at all.
-
getBestChainHeight
public final int getBestChainHeight()- Returns:
- the height of the best known chain, convenience for
getChainHead().getHeight()
.
-
setChainHead
- Parameters:
chainHead
- chain head to set- Throws:
BlockStoreException
- if a failure occurs while storing a block
-
getChainHead
Returns the block at the head of the current best chain. This is the block which represents the greatest amount of cumulative work done.- Returns:
- block at the head of the current best chain
-
getOrphanRoot
An orphan block is one that does not connect to the chain anywhere (ie we can't find its parent, therefore it's an orphan). Typically, this occurs when we are downloading the chain and didn't reach the head yet, and/or if a block is solved whilst we are downloading. It's possible that we see a small amount of orphan blocks which chain together, this method tries walking backwards through the known orphan blocks to find the bottom-most.- Parameters:
from
- hash of block to walk backwards from- Returns:
- from or one of froms parents, or null if "from" does not identify an orphan block
-
isOrphan
Returns true if the given block is currently in the orphan blocks list.- Parameters:
block
- block to check- Returns:
- true if block is an orphan
-
estimateBlockTime
Returns an estimate of when the given block will be reached, assuming a perfect 10 minute average for each block. This is useful for turning transaction lock times into human readable times. Note that a height in the past will still be estimated, even though the time of solving is actually known (we won't scan backwards through the chain to obtain the right answer).- Parameters:
height
- block time to estimate- Returns:
- estimated date block will be mined
-
getHeightFuture
Returns a future that completes when the block chain has reached the given height. Yields theStoredBlock
of the block that reaches that height first. The future completes on a peer thread.- Parameters:
height
- desired height- Returns:
- future that will complete when height is reached
-
getFalsePositiveRate
public double getFalsePositiveRate()The false positive rate is the average over all blockchain transactions of: - 1.0 if the transaction was false-positive (was irrelevant to all listeners) - 0.0 if the transaction was relevant or filtered out- Returns:
- the false positive rate
-
trackFilteredTransactions
protected void trackFilteredTransactions(int count) We completed handling of a filtered block. Update false-positive estimate based on the total number of transactions in the original block. count includes filtered transactions, transactions that were passed in and were relevant and transactions that were false positives (i.e. includes all transactions in the block).- Parameters:
count
- total number of transactions in original block
-
resetFalsePositiveEstimate
public void resetFalsePositiveEstimate()Resets estimates of false positives. Used when the filter is sent to the peer. -
getVersionTally
- Returns:
- version tally (not thread safe!)
-