Split the BlockChain.add method out into some smaller functions.

This commit is contained in:
Mike Hearn
2011-04-21 09:19:05 +00:00
parent 90c7ec80ff
commit 1e2f3ae3e2

View File

@@ -113,22 +113,9 @@ public class BlockChain {
LOG(block.toString()); LOG(block.toString());
throw e; throw e;
} }
// If this block is a full block, scan, otherwise it's just headers (eg from getheaders or a unit test). // Inform the wallet about transactions relevant to our keys, then throw away the transaction data.
if (block.transactions != null) { extractRelevantTransactions(block);
// Scan the transactions to find out if any sent money to us. We don't care about the rest. assert block.transactions == null;
// TODO: We should also scan to see if any of our own keys sent money to somebody else and became spent.
for (Transaction tx : block.transactions) {
try {
scanTransaction(tx);
} catch (ScriptException e) {
// We don't want scripts we don't understand to break the block chain,
// so just note that this tx was not scanned here and continue.
LOG("Failed to parse a script: " + e.toString());
}
}
}
// We don't need the transaction data anymore. Free up some memory.
block.transactions = null;
if (blockStore.get(block.getHash()) != null) { if (blockStore.get(block.getHash()) != null) {
LOG("Already have block"); LOG("Already have block");
@@ -143,27 +130,9 @@ public class BlockChain {
unconnectedBlocks.add(block); unconnectedBlocks.add(block);
return false; return false;
} else { } else {
// The block connects to somewhere on the chain. Not necessarily the top of the best known chain. // It connects to somewhere on the chain. Not necessarily the top of the best known chain.
checkDifficultyTransitions(storedPrev, block); checkDifficultyTransitions(storedPrev, block);
StoredBlock newStoredBlock = storedPrev.build(block); connectAndStoreBlock(block, storedPrev);
// Store it.
blockStore.put(newStoredBlock);
if (storedPrev.equals(chainHead)) {
// This block connects to the best known block, it is a normal continuation of the system.
setChainHead(newStoredBlock);
LOG("Received block " + block.getHashAsString() + ", chain is now " + chainHead.getHeight() +
" blocks high");
} else {
// This block connects to somewhere other than the top of the chain.
if (newStoredBlock.moreWorkThan(chainHead)) {
// This chain has overtaken the one we currently believe is best. Reorganize is required.
wallet.reorganize(chainHead, newStoredBlock);
// Update the pointer to the best known block.
setChainHead(newStoredBlock);
} else {
LOG("Received a block which forks the chain, but it did not cause a reorganize.");
}
}
} }
if (tryConnecting) if (tryConnecting)
@@ -172,6 +141,48 @@ public class BlockChain {
return true; return true;
} }
private void connectAndStoreBlock(Block block, StoredBlock storedPrev) throws BlockStoreException, VerificationException {
StoredBlock newStoredBlock = storedPrev.build(block);
blockStore.put(newStoredBlock);
if (storedPrev.equals(chainHead)) {
// This block connects to the best known block, it is a normal continuation of the system.
setChainHead(newStoredBlock);
LOG("Received block " + block.getHashAsString() + ", chain is now " + chainHead.getHeight() +
" blocks high");
} else {
// This block connects to somewhere other than the top of the chain.
if (newStoredBlock.moreWorkThan(chainHead)) {
// This chain has overtaken the one we currently believe is best. Reorganize is required.
wallet.reorganize(chainHead, newStoredBlock);
// Update the pointer to the best known block.
setChainHead(newStoredBlock);
} else {
LOG("Received a block which forks the chain, but it did not cause a reorganize.");
}
}
}
private void extractRelevantTransactions(Block block) throws VerificationException {
// If this block is a full block, scan, otherwise it's just headers (eg from getheaders or a unit test).
if (block.transactions != null) {
// Scan the transactions to find out if any sent money to us. We don't care about the rest.
// TODO: We should also scan to see if any of our own keys sent money to somebody else and became spent.
for (Transaction tx : block.transactions) {
try {
scanTransaction(tx);
} catch (ScriptException e) {
// We don't want scripts we don't understand to break the block chain,
// so just note that this tx was not scanned here and continue.
LOG("Failed to parse a script: " + e.toString());
}
}
}
// Throw away the transactions. We have to do this because we can't hold all the transaction data for the
// production chain in memory at once. Because BitCoinJ implements client mode/simplified payment
// verification we don't store the transactions to disk or use them later anyway.
block.transactions = null;
}
private void setChainHead(StoredBlock chainHead) { private void setChainHead(StoredBlock chainHead) {
this.chainHead = chainHead; this.chainHead = chainHead;
try { try {