/** * Copyright 2011 Google Inc. * * 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.examples; import com.google.bitcoin.core.*; import java.io.File; import java.io.IOException; import java.math.BigInteger; import java.net.InetAddress; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; /** * <p> * PingService demonstrates basic usage of the library. It sits on the network and when it receives coins, simply * sends them right back to the previous owner, determined rather arbitrarily by the address of the first input. * </p> * * <p> * If running on TestNet (slow but better than using real coins on prodnet) do the following: * <ol> * <li>Backup your current wallet.dat in case of unforeseen problems</li> * <li>Start your bitcoin client in test mode <code>bitcoin -testnet</code>. This will create a new sub-directory called testnet and should not interfere with normal wallets or operations.</li> * <li>(Optional) Choose a fresh address</li> * <li>(Optional) Visit the Testnet faucet (https://testnet.freebitcoins.appspot.com/) to load your client with test coins</li> * <li>Run <code>PingService -testnet</code></li> * <li>Wait for the block chain to download</li> * <li>Send some coins from your bitcoin client to the address provided in the PingService console</li> * <li>Leave it running until you get the coins back again</li> * </ol> * </p> * * <p>The testnet can be slow or flaky as it's a shared resource. You can use the <a href="http://sourceforge * .net/projects/bitcoin/files/Bitcoin/testnet-in-a-box/">testnet in a box</a> to do everything purely locally.</p> */ public class PingService { public static void main(String[] args) throws Exception { boolean testNet = args.length > 0 && args[0].equalsIgnoreCase("testnet"); final NetworkParameters params = testNet ? NetworkParameters.testNet() : NetworkParameters.prodNet(); String filePrefix = testNet ? "pingservice-testnet" : "pingservice-prodnet"; // Try to read the wallet from storage, create a new one if not possible. Wallet wallet; final File walletFile = new File(filePrefix + ".wallet"); try { wallet = Wallet.loadFromFile(walletFile); } catch (IOException e) { wallet = new Wallet(params); wallet.keychain.add(new ECKey()); wallet.saveToFile(walletFile); } // Fetch the first key in the wallet (should be the only key). ECKey key = wallet.keychain.get(0); // Load the block chain, if there is one stored locally. System.out.println("Reading block store from disk"); BlockStore blockStore = new BoundedOverheadBlockStore(params, new File(filePrefix + ".blockchain")); // Connect to the localhost node. One minute timeout since we won't try any other peers System.out.println("Connecting ..."); NetworkConnection conn = new NetworkConnection(InetAddress.getLocalHost(), params, blockStore.getChainHead().getHeight(), 60000); BlockChain chain = new BlockChain(params, wallet, blockStore); final Peer peer = new Peer(params, conn, chain, wallet); peer.start(); // We want to know when the balance changes. wallet.addEventListener(new WalletEventListener() { public void onCoinsReceived(Wallet w, Transaction tx, BigInteger prevBalance, BigInteger newBalance) { // Running on a peer thread. assert !newBalance.equals(BigInteger.ZERO); // It's impossible to pick one specific identity that you receive coins from in BitCoin as there // could be inputs from many addresses. So instead we just pick the first and assume they were all // owned by the same person. try { TransactionInput input = tx.getInputs().get(0); Address from = input.getFromAddress(); BigInteger value = tx.getValueSentToMe(w); System.out.println("Received " + Utils.bitcoinValueToFriendlyString(value) + " from " + from.toString()); // Now send the coins back! Transaction sendTx = w.sendCoins(peer, from, value); assert sendTx != null; // We should never try to send more coins than we have! System.out.println("Sent coins back! Transaction hash is " + sendTx.getHashAsString()); w.saveToFile(walletFile); } catch (ScriptException e) { // If we didn't understand the scriptSig, just crash. e.printStackTrace(); throw new RuntimeException(e); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } } }); CountDownLatch progress = peer.startBlockChainDownload(); long max = progress.getCount(); // Racy but no big deal. if (max > 0) { System.out.println("Downloading block chain. " + (max > 1000 ? "This may take a while." : "")); long current = max; int lastPercent = 0; while (current > 0) { double pct = 100.0 - (100.0 * (current / (double) max)); if ((int)pct != lastPercent) { System.out.println(String.format("Chain download %d%% done", (int) pct)); lastPercent = (int) pct; } progress.await(1, TimeUnit.SECONDS); current = progress.getCount(); } } System.out.println("Send coins to: " + key.toAddress(params).toString()); System.out.println("Waiting for coins to arrive. Press Ctrl-C to quit."); // The peer thread keeps us alive until something kills the process. } }