com.google.bitcoin.core.FullPrunedBlockChain Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2012 Matt Corallo.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.bitcoin.core;
import com.google.bitcoin.script.Script;
import com.google.bitcoin.store.BlockStoreException;
import com.google.bitcoin.store.FullPrunedBlockStore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.concurrent.*;
import static com.google.common.base.Preconditions.checkState;
/**
* A FullPrunedBlockChain works in conjunction with a {@link FullPrunedBlockStore} to verify all the rules of the
* Bitcoin system, with the downside being a larg cost in system resources. Fully verifying means all unspent transaction
* outputs are stored. Once a transaction output is spent and that spend is buried deep enough, the data related to it
* is deleted to ensure disk space usage doesn't grow forever. For this reason a pruning node cannot serve the full
* block chain to other clients, but it nevertheless provides the same security guarantees as a regular Satoshi
* client does.
*/
public class FullPrunedBlockChain extends AbstractBlockChain {
private static final Logger log = LoggerFactory.getLogger(FullPrunedBlockChain.class);
/** Keeps a map of block hashes to StoredBlocks. */
protected final FullPrunedBlockStore blockStore;
// Whether or not to execute scriptPubKeys before accepting a transaction (i.e. check signatures).
private boolean runScripts = true;
/**
* Constructs a BlockChain connected to the given wallet and store. To obtain a {@link Wallet} you can construct
* one from scratch, or you can deserialize a saved wallet from disk using {@link Wallet#loadFromFile(java.io.File)}
*/
public FullPrunedBlockChain(NetworkParameters params, Wallet wallet, FullPrunedBlockStore blockStore) throws BlockStoreException {
this(params, new ArrayList(), blockStore);
if (wallet != null)
addWallet(wallet);
}
/**
* Constructs a BlockChain that has no wallet at all. This is helpful when you don't actually care about sending
* and receiving coins but rather, just want to explore the network data structures.
*/
public FullPrunedBlockChain(NetworkParameters params, FullPrunedBlockStore blockStore) throws BlockStoreException {
this(params, new ArrayList(), blockStore);
}
/**
* Constructs a BlockChain connected to the given list of wallets and a store.
*/
public FullPrunedBlockChain(NetworkParameters params, List listeners,
FullPrunedBlockStore blockStore) throws BlockStoreException {
super(params, listeners, blockStore);
this.blockStore = blockStore;
// Ignore upgrading for now
this.chainHead = blockStore.getVerifiedChainHead();
}
@Override
protected StoredBlock addToBlockStore(StoredBlock storedPrev, Block header, TransactionOutputChanges txOutChanges)
throws BlockStoreException, VerificationException {
StoredBlock newBlock = storedPrev.build(header);
blockStore.put(newBlock, new StoredUndoableBlock(newBlock.getHeader().getHash(), txOutChanges));
return newBlock;
}
@Override
protected StoredBlock addToBlockStore(StoredBlock storedPrev, Block block)
throws BlockStoreException, VerificationException {
StoredBlock newBlock = storedPrev.build(block);
blockStore.put(newBlock, new StoredUndoableBlock(newBlock.getHeader().getHash(), block.transactions));
return newBlock;
}
@Override
protected boolean shouldVerifyTransactions() {
return true;
}
/**
* Whether or not to run scripts whilst accepting blocks (i.e. checking signatures, for most transactions).
* If you're accepting data from an untrusted node, such as one found via the P2P network, this should be set
* to true (which is the default). If you're downloading a chain from a node you control, script execution
* is redundant because you know the connected node won't relay bad data to you. In that case it's safe to set
* this to false and obtain a significant speedup.
*/
public void setRunScripts(boolean value) {
this.runScripts = value;
}
//TODO: Remove lots of duplicated code in the two connectTransactions
// TODO: execute in order of largest transaction (by input count) first
ExecutorService scriptVerificationExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
/** A job submitted to the executor which verifies signatures. */
private static class Verifier implements Callable {
final Transaction tx;
final List