From 4c1212750112eb9296f71f89cd2e8502c829960d Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Sun, 5 Apr 2015 19:52:58 +0200 Subject: [PATCH] Context: add c'tors that take a context to [Abstract/FullPruned/]BlockChain and PeerGroup. The existing c'tors now do a consistency check against the existing context or create a new one on the fly. --- .../org/bitcoinj/core/AbstractBlockChain.java | 9 ++- .../java/org/bitcoinj/core/BlockChain.java | 29 ++++++--- .../bitcoinj/core/FullPrunedBlockChain.java | 40 ++++++++---- .../java/org/bitcoinj/core/PeerGroup.java | 61 ++++++++++++------- .../main/java/org/bitcoinj/core/Wallet.java | 2 +- .../AbstractFullPrunedBlockChainTest.java | 3 +- .../org/bitcoinj/core/BlockChainTest.java | 2 +- 7 files changed, 98 insertions(+), 48 deletions(-) diff --git a/core/src/main/java/org/bitcoinj/core/AbstractBlockChain.java b/core/src/main/java/org/bitcoinj/core/AbstractBlockChain.java index 176df42d..2cd928b5 100644 --- a/core/src/main/java/org/bitcoinj/core/AbstractBlockChain.java +++ b/core/src/main/java/org/bitcoinj/core/AbstractBlockChain.java @@ -137,16 +137,21 @@ public abstract class AbstractBlockChain { private double falsePositiveTrend; private double previousFalsePositiveRate; + /** See {@link #AbstractBlockChain(Context, List, BlockStore)} */ + public AbstractBlockChain(NetworkParameters params, List listeners, + BlockStore blockStore) throws BlockStoreException { + this(Context.getOrCreate(params), listeners, blockStore); + } /** * Constructs a BlockChain connected to the given list of listeners (eg, wallets) and a store. */ - public AbstractBlockChain(NetworkParameters params, List listeners, + public AbstractBlockChain(Context context, List listeners, BlockStore blockStore) throws BlockStoreException { this.blockStore = blockStore; chainHead = blockStore.getChainHead(); log.info("chain head is at height {}:\n{}", chainHead.getHeight(), chainHead.getHeader()); - this.params = params; + this.params = context.getParams(); this.listeners = new CopyOnWriteArrayList>(); for (BlockChainListener l : listeners) addListener(l, Threading.SAME_THREAD); } diff --git a/core/src/main/java/org/bitcoinj/core/BlockChain.java b/core/src/main/java/org/bitcoinj/core/BlockChain.java index 00df286e..8db28b1b 100644 --- a/core/src/main/java/org/bitcoinj/core/BlockChain.java +++ b/core/src/main/java/org/bitcoinj/core/BlockChain.java @@ -25,11 +25,12 @@ import org.bitcoinj.store.BlockStoreException; import java.util.ArrayList; import java.util.List; +// TODO: Rename this class to SPVBlockChain at some point. + /** - *

A BlockChain implements the simplified payment verification mode of the Bitcoin protocol. It is the right + * A BlockChain implements the simplified payment verification mode of the Bitcoin protocol. It is the right * choice to use for programs that have limited resources as it won't verify transactions signatures or attempt to store * all of the block chain. Really, this class should be called SPVBlockChain but for backwards compatibility it is not. - *

*/ public class BlockChain extends AbstractBlockChain { /** Keeps a map of block hashes to StoredBlocks. */ @@ -44,17 +45,25 @@ public class BlockChain extends AbstractBlockChain { * {@link org.bitcoinj.store.MemoryBlockStore} if you want to hold all headers in RAM and don't care about * disk serialization (this is rare).

*/ + public BlockChain(Context context, Wallet wallet, BlockStore blockStore) throws BlockStoreException { + this(context, new ArrayList(), blockStore); + addWallet(wallet); + } + + /** See {@link #BlockChain(Context, Wallet, BlockStore)}} */ public BlockChain(NetworkParameters params, Wallet wallet, BlockStore blockStore) throws BlockStoreException { - this(params, new ArrayList(), blockStore); - Context.getOrCreate(params); - if (wallet != null) - addWallet(wallet); + this(Context.getOrCreate(params), wallet, blockStore); } /** * 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 BlockChain(Context context, BlockStore blockStore) throws BlockStoreException { + this(context, new ArrayList(), blockStore); + } + + /** See {@link #BlockChain(Context, BlockStore)} */ public BlockChain(NetworkParameters params, BlockStore blockStore) throws BlockStoreException { this(params, new ArrayList(), blockStore); } @@ -62,12 +71,16 @@ public class BlockChain extends AbstractBlockChain { /** * Constructs a BlockChain connected to the given list of listeners and a store. */ - public BlockChain(NetworkParameters params, List wallets, - BlockStore blockStore) throws BlockStoreException { + public BlockChain(Context params, List wallets, BlockStore blockStore) throws BlockStoreException { super(params, wallets, blockStore); this.blockStore = blockStore; } + /** See {@link #BlockChain(Context, List, BlockStore)} */ + public BlockChain(NetworkParameters params, List wallets, BlockStore blockStore) throws BlockStoreException { + this(Context.getOrCreate(params), wallets, blockStore); + } + @Override protected StoredBlock addToBlockStore(StoredBlock storedPrev, Block blockHeader, TransactionOutputChanges txOutChanges) throws BlockStoreException, VerificationException { diff --git a/core/src/main/java/org/bitcoinj/core/FullPrunedBlockChain.java b/core/src/main/java/org/bitcoinj/core/FullPrunedBlockChain.java index 93625b61..23ddb120 100644 --- a/core/src/main/java/org/bitcoinj/core/FullPrunedBlockChain.java +++ b/core/src/main/java/org/bitcoinj/core/FullPrunedBlockChain.java @@ -54,34 +54,48 @@ public class FullPrunedBlockChain extends AbstractBlockChain { private boolean runScripts = true; /** - * Constructs a BlockChain connected to the given wallet and store. To obtain a {@link Wallet} you can construct + * Constructs a block chain 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(Context context, Wallet wallet, FullPrunedBlockStore blockStore) throws BlockStoreException { + this(context, new ArrayList(), blockStore); + addWallet(wallet); + } + + /** + * Constructs a block chain 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); + this(Context.getOrCreate(params), wallet, blockStore); } - /** - * 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. - */ + /** Constructs a block chain connected to the given store. */ + public FullPrunedBlockChain(Context context, FullPrunedBlockStore blockStore) throws BlockStoreException { + this(context, new ArrayList(), blockStore); + } + + /** See {@link #FullPrunedBlockChain(Context, Wallet, FullPrunedBlockStore)} */ public FullPrunedBlockChain(NetworkParameters params, FullPrunedBlockStore blockStore) throws BlockStoreException { - this(params, new ArrayList(), blockStore); + this(Context.getOrCreate(params), blockStore); } /** - * Constructs a BlockChain connected to the given list of wallets and a store. + * Constructs a block chain connected to the given list of wallets and a store. */ - public FullPrunedBlockChain(NetworkParameters params, List listeners, - FullPrunedBlockStore blockStore) throws BlockStoreException { - super(params, listeners, blockStore); + public FullPrunedBlockChain(Context context, List listeners, FullPrunedBlockStore blockStore) throws BlockStoreException { + super(context, listeners, blockStore); this.blockStore = blockStore; // Ignore upgrading for now this.chainHead = blockStore.getVerifiedChainHead(); } + /** See {@link #FullPrunedBlockChain(Context, List, FullPrunedBlockStore)} */ + public FullPrunedBlockChain(NetworkParameters params, List listeners, + FullPrunedBlockStore blockStore) throws BlockStoreException { + this(Context.getOrCreate(params), listeners, blockStore); + } + @Override protected StoredBlock addToBlockStore(StoredBlock storedPrev, Block header, TransactionOutputChanges txOutChanges) throws BlockStoreException, VerificationException { diff --git a/core/src/main/java/org/bitcoinj/core/PeerGroup.java b/core/src/main/java/org/bitcoinj/core/PeerGroup.java index 4e16e725..757439a9 100644 --- a/core/src/main/java/org/bitcoinj/core/PeerGroup.java +++ b/core/src/main/java/org/bitcoinj/core/PeerGroup.java @@ -249,24 +249,36 @@ public class PeerGroup implements TransactionBroadcaster { /** Whether bloom filter support is enabled when using a non FullPrunedBlockchain*/ private volatile boolean vBloomFilteringEnabled = true; - /** - * Creates a PeerGroup with the given parameters. No chain is provided so this node will report its chain height - * as zero to other peers. This constructor is useful if you just want to explore the network but aren't interested - * in downloading block data. - * - * @param params Network parameters - */ - + /** See {@link #PeerGroup(Context)} */ public PeerGroup(NetworkParameters params) { this(params, null); } /** - * Creates a PeerGroup for the given network and chain. Blocks will be passed to the chain as they are broadcast + * Creates a PeerGroup with the given context. No chain is provided so this node will report its chain height + * as zero to other peers. This constructor is useful if you just want to explore the network but aren't interested + * in downloading block data. + */ + public PeerGroup(Context context) { + this(context, null); + } + + /** See {@link #PeerGroup(Context, AbstractBlockChain)} */ + public PeerGroup(NetworkParameters params, @Nullable AbstractBlockChain chain) { + this(Context.getOrCreate(params), chain, new NioClientManager()); + } + + /** + * Creates a PeerGroup for the given context and chain. Blocks will be passed to the chain as they are broadcast * and downloaded. This is probably the constructor you want to use. */ - public PeerGroup(NetworkParameters params, @Nullable AbstractBlockChain chain) { - this(params, chain, new NioClientManager()); + public PeerGroup(Context context, @Nullable AbstractBlockChain chain) { + this(context, chain, new NioClientManager()); + } + + /** See {@link #newWithTor(Context, AbstractBlockChain, TorClient)} */ + public static PeerGroup newWithTor(NetworkParameters params, @Nullable AbstractBlockChain chain, TorClient torClient) throws TimeoutException { + return newWithTor(Context.getOrCreate(params), chain, torClient); } /** @@ -283,33 +295,38 @@ public class PeerGroup implements TransactionBroadcaster { * * @throws java.util.concurrent.TimeoutException if Tor fails to start within 20 seconds. */ - public static PeerGroup newWithTor(NetworkParameters params, @Nullable AbstractBlockChain chain, TorClient torClient) throws TimeoutException { + public static PeerGroup newWithTor(Context context, @Nullable AbstractBlockChain chain, TorClient torClient) throws TimeoutException { checkNotNull(torClient); DRMWorkaround.maybeDisableExportControls(); BlockingClientManager manager = new BlockingClientManager(torClient.getSocketFactory()); final int CONNECT_TIMEOUT_MSEC = TOR_TIMEOUT_SECONDS * 1000; manager.setConnectTimeoutMillis(CONNECT_TIMEOUT_MSEC); - PeerGroup result = new PeerGroup(params, chain, manager, torClient); + PeerGroup result = new PeerGroup(context, chain, manager, torClient); result.setConnectTimeoutMillis(CONNECT_TIMEOUT_MSEC); - result.addPeerDiscovery(new TorDiscovery(params, torClient)); + result.addPeerDiscovery(new TorDiscovery(context.getParams(), torClient)); return result; } - /** - * Creates a new PeerGroup allowing you to specify the {@link ClientConnectionManager} which is used to create new - * connections and keep track of existing ones. - */ + /** See {@link #PeerGroup(Context, AbstractBlockChain, ClientConnectionManager)} */ public PeerGroup(NetworkParameters params, @Nullable AbstractBlockChain chain, ClientConnectionManager connectionManager) { - this(params, chain, connectionManager, null); + this(Context.getOrCreate(params), chain, connectionManager, null); } /** * Creates a new PeerGroup allowing you to specify the {@link ClientConnectionManager} which is used to create new * connections and keep track of existing ones. */ - private PeerGroup(NetworkParameters params, @Nullable AbstractBlockChain chain, ClientConnectionManager connectionManager, @Nullable TorClient torClient) { - this.params = checkNotNull(params); - this.context = Context.getOrCreate(params); + public PeerGroup(Context context, @Nullable AbstractBlockChain chain, ClientConnectionManager connectionManager) { + this(context, chain, connectionManager, null); + } + + /** + * Creates a new PeerGroup allowing you to specify the {@link ClientConnectionManager} which is used to create new + * connections and keep track of existing ones. + */ + private PeerGroup(Context context, @Nullable AbstractBlockChain chain, ClientConnectionManager connectionManager, @Nullable TorClient torClient) { + this.context = checkNotNull(context); + this.params = context.getParams(); this.chain = chain; fastCatchupTimeSecs = params.getGenesisBlock().getTimeSeconds(); wallets = new CopyOnWriteArrayList(); diff --git a/core/src/main/java/org/bitcoinj/core/Wallet.java b/core/src/main/java/org/bitcoinj/core/Wallet.java index 0ce0ef6c..0280df71 100644 --- a/core/src/main/java/org/bitcoinj/core/Wallet.java +++ b/core/src/main/java/org/bitcoinj/core/Wallet.java @@ -209,7 +209,7 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha * {@link #loadFromFile}. */ public Wallet(NetworkParameters params) { - this(params, new KeyChainGroup(params)); + this(Context.getOrCreate(params)); } /** diff --git a/core/src/test/java/org/bitcoinj/core/AbstractFullPrunedBlockChainTest.java b/core/src/test/java/org/bitcoinj/core/AbstractFullPrunedBlockChainTest.java index 32e8eaf4..26af981d 100644 --- a/core/src/test/java/org/bitcoinj/core/AbstractFullPrunedBlockChainTest.java +++ b/core/src/test/java/org/bitcoinj/core/AbstractFullPrunedBlockChainTest.java @@ -214,12 +214,13 @@ public abstract class AbstractFullPrunedBlockChainTest { @Test public void testFirst100KBlocks() throws Exception { NetworkParameters params = MainNetParams.get(); + Context context = new Context(params); File blockFile = new File(getClass().getResource("first-100k-blocks.dat").getFile()); BlockFileLoader loader = new BlockFileLoader(params, Arrays.asList(blockFile)); store = createStore(params, 10); resetStore(store); - chain = new FullPrunedBlockChain(params, store); + chain = new FullPrunedBlockChain(context, store); for (Block block : loader) chain.add(block); try { diff --git a/core/src/test/java/org/bitcoinj/core/BlockChainTest.java b/core/src/test/java/org/bitcoinj/core/BlockChainTest.java index e3834a31..8031de49 100644 --- a/core/src/test/java/org/bitcoinj/core/BlockChainTest.java +++ b/core/src/test/java/org/bitcoinj/core/BlockChainTest.java @@ -396,7 +396,7 @@ public class BlockChainTest { @Test public void estimatedBlockTime() throws Exception { NetworkParameters params = MainNetParams.get(); - BlockChain prod = new BlockChain(params, new MemoryBlockStore(params)); + BlockChain prod = new BlockChain(new Context(params), new MemoryBlockStore(params)); Date d = prod.estimateBlockTime(200000); // The actual date of block 200,000 was 2012-09-22 10:47:00 assertEquals(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US).parse("2012-10-23T08:35:05.000-0700"), d);