/* Copyright rememberjava.com. Licensed under GPL 3. See http://rememberjava.com/license */
package com.rememberjava.bitcoin;
import java.io.File;
import org.bitcoinj.core.Address;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.InsufficientMoneyException;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.kits.WalletAppKit;
import org.bitcoinj.params.TestNet3Params;
import org.bitcoinj.wallet.SendRequest;
import org.bitcoinj.wallet.Wallet;
import org.bitcoinj.wallet.Wallet.SendResult;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.impl.StaticLoggerBinder;
import com.google.common.util.concurrent.MoreExecutors;
/**
* Multiple large file and network I/O tests for the Testnet3 block chain.
* Comment in and out @Test annotations as need.
*
* For more info:
* https://en.bitcoin.it/wiki/Testnet
*
* For test coins:
* http://faucet.xeno-genesis.com
* http://tpfaucet.appspot.com
*
* For test block explorer:
* https://testnet.blockexplorer.com
*
*/
public class BitcoinjApiTest {
/**
* http://tpfaucet.appspot.com
*/
private static final String TPFAUCET_RETURN_ADR = "n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi";
private static final File WALLET_DIR = new File("/tmp");
private static final String WALLET_PREFIX = "rjtest";
private NetworkParameters params;
private WalletAppKit kit;
private Wallet wallet;
private volatile boolean receivedCoins;
private volatile boolean sentCoins;
/**
* For all tests, connect to the TestNet3 network.
*/
@Before
public void setup() {
params = TestNet3Params.get();
kit = new WalletAppKit(params, WALLET_DIR, WALLET_PREFIX);
}
/**
* Connect, sync and wait till done.
*/
private void startSync() {
kit.startAsync();
kit.awaitRunning();
sleep(1000);
wallet = kit.wallet();
}
/**
* Disconnect and wait till done.
*/
@After
public void teardown() {
kit.stopAsync();
kit.awaitTerminated();
}
/**
* Even though it is possible to run without the logger implementation classes
* in place, it is very confusing and misleading.
*
* The bitcoinj logs output connection and transaction information. Without
* them, it's difficult to know what is happening, and the application might
* seem "stuck".
*/
@Test
public void checkLogger() {
StaticLoggerBinder.getSingleton();
}
/**
* Connects to the TestNet3 network and disconnects. If there is no walled
* stored at the specified location, a new one is created and relevant blocks
* are downloaded. This can take 1 to 2 minutes. If information is stale, it
* can also take a minute to update.
*
* The walled used in this test is separate from the other tests.
*/
@Test
public void testSync() {
params = TestNet3Params.get();
kit = new WalletAppKit(params, new File("/dev/shm"), "test");
kit.startAsync();
kit.awaitRunning();
kit.stopAsync();
kit.awaitTerminated();
}
/**
* Connects and prints address information about the test wallet (from the
* TestNet3 network).
*/
@Test
public void printAddresses() {
startSync();
System.out.println("Receive Addresses:");
wallet.getIssuedReceiveAddresses().stream().forEach(this::println);
System.out.println("Watched Addresses:");
wallet.getWatchedAddresses().stream().forEach(this::println);
System.out.println("Current change address:");
System.out.println(wallet.currentChangeAddress());
}
/**
* Connects and prints wallet information (from the TestNet3 network).
*/
@Test
public void printWalletInfo() {
startSync();
Coin balance = wallet.getBalance();
println("Balance satoshis: " + balance.toString());
println("Balance friendly: " + balance.toFriendlyString());
println("Version: " + wallet.getVersion());
}
/**
* Waits for coins to be received on the prompted address. This test blocks
* until the coinsReceived callback is called.
*
* (This test is commented out to avoid blocking the other tests).
*/
// @Test
public void testReceive() {
startSync();
wallet.addCoinsReceivedEventListener(this::coinsReceived);
Address toAdr = wallet.currentReceiveKey().toAddress(params);
System.out.println("Waiting to receive coins on: " + toAdr);
while (!receivedCoins) {
sleep(100);
}
}
/**
* Callback called when the coins have been received.
*/
private void coinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
Coin value = tx.getValueSentToMe(wallet);
System.out.println("Received tx for " + value.toFriendlyString() + ": " + tx);
receivedCoins = true;
}
/**
* Sends test coins back to the TPFAUCET test network address. This test
* blocks until the broadcastComplete callback is called.
*
* (This test is commented out to avoid blocking the other test and
* inadvertently sending away our money.
*/
// @Test
public void testSend() throws InsufficientMoneyException {
startSync();
// Adjust how many coins to send. E.g. the minimum; or everything.
Coin sendValue = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE;
// Coin sendValue = wallet.getBalance().minus(Transaction.DEFAULT_TX_FEE);
Address sendToAdr = Address.fromBase58(params, TPFAUCET_RETURN_ADR);
SendRequest request = SendRequest.to(sendToAdr, sendValue);
SendResult result = wallet.sendCoins(request);
result.broadcastComplete.addListener(() -> {
println("Coins were sent. Transaction hash: " + result.tx.getHashAsString());
sentCoins = true;
}, MoreExecutors.sameThreadExecutor());
while (!sentCoins) {
sleep(100);
}
}
private void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void println(Object str) {
System.out.println(str);
}
}