diff --git a/core/src/main/java/org/bitcoinj/kits/WalletAppKit.java b/core/src/main/java/org/bitcoinj/kits/WalletAppKit.java index 32f9d9a2c..47fb300f3 100644 --- a/core/src/main/java/org/bitcoinj/kits/WalletAppKit.java +++ b/core/src/main/java/org/bitcoinj/kits/WalletAppKit.java @@ -60,6 +60,7 @@ import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; import static org.bitcoinj.base.internal.Preconditions.checkState; @@ -151,6 +152,77 @@ public class WalletAppKit extends AbstractIdleService implements Closeable { this.filePrefix = Objects.requireNonNull(filePrefix); } + /** + * Launch an instance of WalletAppKit with asynchronous startup. Wait until the PeerGroup is initialized. + * + * @param network The network the wallet connects to + * @param directory The directory for creating {@code .wallet} and {@code .spvchain} files + * @param filePrefix The base name for the {@code .wallet} and {@code .spvchain} files + * @return the instance + */ + public static WalletAppKit launch(BitcoinNetwork network, File directory, String filePrefix) { + return WalletAppKit.launch(network, directory, filePrefix, 0); + } + + /** + * Launch an instance of WalletAppKit with asynchronous startup. Wait until the PeerGroup is initialized. + * + * @param network The network the wallet connects to + * @param directory The directory for creating {@code .wallet} and {@code .spvchain} files + * @param filePrefix The base name for the {@code .wallet} and {@code .spvchain} files + * @param configurer Callback to allow configuring the kit before it is started + * @return the instance + */ + public static WalletAppKit launch(BitcoinNetwork network, File directory, String filePrefix, Consumer configurer) { + return WalletAppKit.launch(network, directory, filePrefix, configurer, 0); + } + + /** + * Launch an instance of WalletAppKit with asynchronous startup. Wait until the PeerGroup is initialized. + * + * @param network The network the wallet connects to + * @param directory The directory for creating {@code .wallet} and {@code .spvchain} files + * @param filePrefix The base name for the {@code .wallet} and {@code .spvchain} files + * @param maxConnections maximum number of peer connections. + * @return the instance + */ + public static WalletAppKit launch(BitcoinNetwork network, File directory, String filePrefix, int maxConnections) { + return WalletAppKit.launch(network, directory, filePrefix, (c) -> {}, maxConnections); + } + + /** + * Launch an instance of WalletAppKit with asynchronous startup. Wait until the PeerGroup is initialized. + * + * @param network The network the wallet connects to + * @param directory The directory for creating {@code .wallet} and {@code .spvchain} files + * @param filePrefix The base name for the {@code .wallet} and {@code .spvchain} files + * @param configurer Callback to allow configuring the kit before it is started + * @param maxConnections maximum number of peer connections. + * @return the instance + */ + public static WalletAppKit launch(BitcoinNetwork network, File directory, String filePrefix, Consumer configurer, int maxConnections) { + WalletAppKit kit = new WalletAppKit(network, + ScriptType.P2WPKH, + KeyChainGroupStructure.BIP32, + directory, + filePrefix); + + if (network == BitcoinNetwork.REGTEST) { + // Regression test mode is designed for testing and development only, so there's no public network for it. + // If you pick this mode, you're expected to be running a local "bitcoind -regtest" instance. + kit.connectToLocalHost(); + } + + kit.setBlockingStartup(false); // Don't wait for blockchain synchronization before entering RUNNING state + configurer.accept(kit); // Call configurer before startup + kit.startAsync(); // Connect to the network and start downloading transactions + kit.awaitRunning(); // Wait for the service to reach the RUNNING state + if (maxConnections > 0) { + kit.peerGroup().setMaxConnections(maxConnections); + } + return kit; + } + /** Will only connect to the given addresses. Cannot be called after startup. */ public WalletAppKit setPeerNodes(PeerAddress... addresses) { checkState(state() == State.NEW, () -> diff --git a/examples/src/main/java/org/bitcoinj/examples/DoubleSpend.java b/examples/src/main/java/org/bitcoinj/examples/DoubleSpend.java index 4ed2b23e8..33a701d76 100644 --- a/examples/src/main/java/org/bitcoinj/examples/DoubleSpend.java +++ b/examples/src/main/java/org/bitcoinj/examples/DoubleSpend.java @@ -18,12 +18,10 @@ package org.bitcoinj.examples; import org.bitcoinj.base.Address; import org.bitcoinj.base.BitcoinNetwork; -import org.bitcoinj.base.ScriptType; import org.bitcoinj.core.*; import org.bitcoinj.kits.WalletAppKit; import org.bitcoinj.utils.BriefLogFormatter; import org.bitcoinj.utils.Threading; -import org.bitcoinj.wallet.KeyChainGroupStructure; import org.bitcoinj.wallet.Wallet; import java.io.File; @@ -38,11 +36,9 @@ import static org.bitcoinj.base.Coin.*; public class DoubleSpend { public static void main(String[] args) throws Exception { BriefLogFormatter.init(); - WalletAppKit kit = new WalletAppKit(BitcoinNetwork.REGTEST, ScriptType.P2WPKH, KeyChainGroupStructure.BIP32, new File("."), "doublespend"); - kit.connectToLocalHost(); - kit.setAutoSave(false); - kit.startAsync(); - kit.awaitRunning(); + WalletAppKit kit = WalletAppKit.launch(BitcoinNetwork.REGTEST, new File("."), "doublespend", (k) -> + k.setAutoSave(false) + ); System.out.println(kit.wallet()); diff --git a/examples/src/main/java/org/bitcoinj/examples/ForwardingService.java b/examples/src/main/java/org/bitcoinj/examples/ForwardingService.java index a86db5d59..78a4a84f2 100644 --- a/examples/src/main/java/org/bitcoinj/examples/ForwardingService.java +++ b/examples/src/main/java/org/bitcoinj/examples/ForwardingService.java @@ -17,7 +17,6 @@ package org.bitcoinj.examples; import org.bitcoinj.base.BitcoinNetwork; -import org.bitcoinj.base.ScriptType; import org.bitcoinj.base.Sha256Hash; import org.bitcoinj.base.Address; import org.bitcoinj.base.Coin; @@ -30,7 +29,6 @@ import org.bitcoinj.kits.WalletAppKit; import org.bitcoinj.utils.BriefLogFormatter; import org.bitcoinj.wallet.CoinSelection; import org.bitcoinj.wallet.CoinSelector; -import org.bitcoinj.wallet.KeyChainGroupStructure; import org.bitcoinj.wallet.SendRequest; import org.bitcoinj.wallet.Wallet; import org.bitcoinj.wallet.listeners.WalletCoinsReceivedEventListener; @@ -112,29 +110,14 @@ public class ForwardingService implements Closeable { this.network = network; listener = this::coinsReceivedListener; // Start up a basic app using a class that automates some boilerplate. - kit = new WalletAppKit(network, - ScriptType.P2WPKH, - KeyChainGroupStructure.BIP32, - directory, - getPrefix(network)); + kit = WalletAppKit.launch(network, directory, getPrefix(network), MAX_CONNECTIONS); } /** - * Start the WalletAppKit + * Start the ForwardingService * @return The receiving address for the forwarding wallet */ public Address start() { - if (network == BitcoinNetwork.REGTEST) { - // Regression test mode is designed for testing and development only, so there's no public network for it. - // If you pick this mode, you're expected to be running a local "bitcoind -regtest" instance. - kit.connectToLocalHost(); - } - - kit.setBlockingStartup(false); // Don't wait for blockchain synchronization before entering RUNNING state - kit.startAsync(); // Connect to the network and start downloading transactions - kit.awaitRunning(); // Wait for the service to reach the RUNNING state - kit.peerGroup().setMaxConnections(MAX_CONNECTIONS); - // Start listening and forwarding kit.wallet().addCoinsReceivedEventListener(listener); return kit.wallet().currentReceiveAddress(); diff --git a/examples/src/main/java/org/bitcoinj/examples/Kit.java b/examples/src/main/java/org/bitcoinj/examples/Kit.java index 29dfc22f9..41b8ec85c 100644 --- a/examples/src/main/java/org/bitcoinj/examples/Kit.java +++ b/examples/src/main/java/org/bitcoinj/examples/Kit.java @@ -17,20 +17,10 @@ package org.bitcoinj.examples; import org.bitcoinj.base.BitcoinNetwork; -import org.bitcoinj.base.ScriptType; import org.bitcoinj.core.*; import org.bitcoinj.kits.WalletAppKit; -import org.bitcoinj.wallet.KeyChainGroupStructure; -import org.bitcoinj.wallet.Wallet; -import org.bitcoinj.wallet.listeners.KeyChainEventListener; -import org.bitcoinj.wallet.listeners.ScriptsChangeEventListener; -import org.bitcoinj.wallet.listeners.WalletCoinsReceivedEventListener; -import org.bitcoinj.wallet.listeners.WalletCoinsSentEventListener; import java.io.File; -import java.util.List; - -import org.bitcoinj.core.listeners.TransactionConfidenceEventListener; /** * The following example shows how to use the by bitcoinj provided WalletAppKit. @@ -55,18 +45,14 @@ public class Kit { // For more information have a look at: https://bitcoinj.github.io/testing and https://bitcoin.org/en/developer-examples#testing-applications BitcoinNetwork network = BitcoinNetwork.TESTNET; - // Now we initialize a new WalletAppKit. The kit handles all the boilerplate for us and is the easiest way to get everything up and running. - // Have a look at the WalletAppKit documentation and its source to understand what's happening behind the scenes: https://github.com/bitcoinj/bitcoinj/blob/master/core/src/main/java/org/bitcoinj/kits/WalletAppKit.java - WalletAppKit kit = new WalletAppKit(network, ScriptType.P2WPKH, KeyChainGroupStructure.BIP32, new File("."), "walletappkit-example"); - - // In case you want to connect with your local bitcoind tell the kit to connect to localhost. - // You must do that in reg test mode. - //kit.connectToLocalHost(); - - // Now we start the kit and sync the blockchain. - // bitcoinj is working a lot with the Google Guava libraries. The WalletAppKit extends the AbstractIdleService. Have a look at the introduction to Guava services: https://github.com/google/guava/wiki/ServiceExplained - kit.startAsync(); - kit.awaitRunning(); + // Initialize and start a WalletAppKit. The kit handles all the boilerplate for us and is the easiest way to get everything up and running. + // Look at the WalletAppKit documentation and its source to understand what's happening behind the scenes: https://github.com/bitcoinj/bitcoinj/blob/master/core/src/main/java/org/bitcoinj/kits/WalletAppKit.java + // WalletAppKit extends the Guava AbstractIdleService. Have a look at the introduction to Guava services: https://github.com/google/guava/wiki/ServiceExplained + WalletAppKit kit = WalletAppKit.launch(network, new File("."), "walletappkit-example", (k) -> { + // In case you want to connect with your local bitcoind tell the kit to connect to localhost. + // This is done automatically in reg test mode. + // k.connectToLocalHost(); + }); kit.wallet().addCoinsReceivedEventListener((wallet, tx, prevBalance, newBalance) -> { System.out.println("-----> coins resceived: " + tx.getTxId()); diff --git a/examples/src/main/java/org/bitcoinj/examples/SendRequest.java b/examples/src/main/java/org/bitcoinj/examples/SendRequest.java index 2aef12d61..16c0fdc4a 100644 --- a/examples/src/main/java/org/bitcoinj/examples/SendRequest.java +++ b/examples/src/main/java/org/bitcoinj/examples/SendRequest.java @@ -19,10 +19,8 @@ package org.bitcoinj.examples; import org.bitcoinj.base.Address; import org.bitcoinj.base.BitcoinNetwork; import org.bitcoinj.base.Coin; -import org.bitcoinj.base.ScriptType; import org.bitcoinj.core.*; import org.bitcoinj.kits.WalletAppKit; -import org.bitcoinj.wallet.KeyChainGroupStructure; import org.bitcoinj.wallet.Wallet; import org.bitcoinj.wallet.Wallet.BalanceType; @@ -37,10 +35,7 @@ public class SendRequest { public static void main(String[] args) throws Exception { // We use the WalletAppKit that handles all the boilerplate for us. Have a look at the Kit.java example for more details. - WalletAppKit kit = new WalletAppKit(BitcoinNetwork.TESTNET, ScriptType.P2WPKH, KeyChainGroupStructure.BIP32, new File("."), "sendrequest-example"); - kit.startAsync(); - kit.awaitRunning(); - + WalletAppKit kit = WalletAppKit.launch(BitcoinNetwork.TESTNET, new File("."), "sendrequest-example"); // How much coins do we want to send? // The Coin class represents a monetary Bitcoin value.