diff --git a/pom.xml b/pom.xml
index 8bfd8ebd..e9aa3f16 100644
--- a/pom.xml
+++ b/pom.xml
@@ -245,6 +245,12 @@
true
+
+ org.apache.derby
+ derby
+ 10.8.2.2
+
+
@@ -263,4 +269,4 @@
1.6.2
-
\ No newline at end of file
+
diff --git a/src/com/google/bitcoin/examples/DerbyPingService.java b/src/com/google/bitcoin/examples/DerbyPingService.java
index a168facc..8808b38f 100644
--- a/src/com/google/bitcoin/examples/DerbyPingService.java
+++ b/src/com/google/bitcoin/examples/DerbyPingService.java
@@ -16,14 +16,26 @@
package com.google.bitcoin.examples;
-import com.google.bitcoin.core.*;
+import com.google.bitcoin.core.AbstractWalletEventListener;
+import com.google.bitcoin.core.Address;
+import com.google.bitcoin.core.BlockChain;
+import com.google.bitcoin.core.ECKey;
+import com.google.bitcoin.core.NetworkParameters;
+import com.google.bitcoin.core.PeerAddress;
+import com.google.bitcoin.core.PeerGroup;
+import com.google.bitcoin.core.ScriptException;
+import com.google.bitcoin.core.StoredBlock;
+import com.google.bitcoin.core.Transaction;
+import com.google.bitcoin.core.TransactionInput;
+import com.google.bitcoin.core.Utils;
+import com.google.bitcoin.core.Wallet;
+import com.google.bitcoin.store.BlockStoreException;
+import com.google.bitcoin.store.DerbyBlockStore;
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;
/**
* PingService demonstrates basic usage of the library. It sits on the network and when it receives coins, simply
@@ -61,14 +73,14 @@ public class DerbyPingService {
// 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);
- peer.start();
+ final PeerGroup peerGroup = new PeerGroup(blockStore, params, chain);
+ peerGroup.addAddress(new PeerAddress(InetAddress.getLocalHost()));
+ peerGroup.start();
// We want to know when the balance changes.
- wallet.addEventListener(new WalletEventListener() {
+ wallet.addEventListener(new AbstractWalletEventListener() {
+ @Override
public void onCoinsReceived(Wallet w, Transaction tx, BigInteger prevBalance, BigInteger newBalance) {
// Running on a peer thread.
assert !newBalance.equals(BigInteger.ZERO);
@@ -81,7 +93,7 @@ public class DerbyPingService {
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);
+ Transaction sendTx = w.sendCoins(peerGroup, 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);
@@ -96,18 +108,8 @@ public class DerbyPingService {
}
});
- 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;
- while (current > 0) {
- double pct = 100.0 - (100.0 * (current / (double)max));
- System.out.println(String.format("Chain download %d%% done", (int)pct));
- progress.await(1, TimeUnit.SECONDS);
- current = progress.getCount();
- }
- }
+ peerGroup.downloadBlockChain();
+
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.
@@ -117,7 +119,7 @@ public class DerbyPingService {
* @param blockStore
* @throws BlockStoreException
*/
- private static void iterateAll(DerbyBlockStore blockStore) throws BlockStoreException {
+ static void iterateAll(DerbyBlockStore blockStore) throws BlockStoreException {
long time = System.currentTimeMillis();
StoredBlock block = blockStore.getChainHead();
int count = 0;
diff --git a/src/com/google/bitcoin/core/DerbyBlockStore.java b/src/com/google/bitcoin/store/DerbyBlockStore.java
similarity index 91%
rename from src/com/google/bitcoin/core/DerbyBlockStore.java
rename to src/com/google/bitcoin/store/DerbyBlockStore.java
index 4c22aea2..0d20ea17 100644
--- a/src/com/google/bitcoin/core/DerbyBlockStore.java
+++ b/src/com/google/bitcoin/store/DerbyBlockStore.java
@@ -1,4 +1,4 @@
-package com.google.bitcoin.core;
+package com.google.bitcoin.store;
/**
* Copyright 2011 Google Inc.
@@ -16,6 +16,14 @@ package com.google.bitcoin.core;
* limitations under the License.
*/
+import com.google.bitcoin.core.Block;
+import com.google.bitcoin.core.NetworkParameters;
+import com.google.bitcoin.core.ProtocolException;
+import com.google.bitcoin.core.Sha256Hash;
+import com.google.bitcoin.core.StoredBlock;
+import com.google.bitcoin.core.Utils;
+import com.google.bitcoin.core.VerificationException;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -33,9 +41,6 @@ import java.sql.Statement;
* @author miron@google.com (Miron Cuperman)
*/
public class DerbyBlockStore implements BlockStore {
- /**
- *
- */
private static final int COMMIT_INTERVAL = 2 * 1000;
private static final Logger log = LoggerFactory.getLogger(DerbyBlockStore.class);
@@ -161,13 +166,13 @@ public class DerbyBlockStore implements BlockStore {
if (!rs.next()) {
throw new BlockStoreException("corrupt Derby block store - no chain head pointer");
}
- byte[] hash = rs.getBytes(1);
+ Sha256Hash hash = new Sha256Hash(rs.getBytes(1));
this.chainHeadBlock = get(hash);
if (this.chainHeadBlock == null)
{
throw new BlockStoreException("corrupt Derby block store - head block not found");
}
- this.chainHeadHash = new Sha256Hash(hash);
+ this.chainHeadHash = hash;
}
private void createNewStore(NetworkParameters params) throws BlockStoreException {
@@ -178,7 +183,7 @@ public class DerbyBlockStore implements BlockStore {
StoredBlock storedGenesis = new StoredBlock(genesis,
genesis.getWork(), 0);
this.chainHeadBlock = storedGenesis;
- this.chainHeadHash = new Sha256Hash(storedGenesis.getHeader().getHash());
+ this.chainHeadHash = storedGenesis.getHeader().getHash();
setChainHead(storedGenesis);
put(storedGenesis);
} catch (VerificationException e1) {
@@ -199,13 +204,12 @@ public class DerbyBlockStore implements BlockStore {
}
}
- @Override
public void put(StoredBlock stored) throws BlockStoreException {
try {
PreparedStatement s =
conn.prepareStatement("INSERT INTO blocks(hash, chainWork, height, header)"
+ " VALUES(?, ?, ?, ?)");
- s.setBytes(1, stored.getHeader().getHash());
+ s.setBytes(1, stored.getHeader().getHash().getBytes());
s.setBytes(2, stored.getChainWork().toByteArray());
s.setLong(3, stored.getHeight());
s.setBytes(4, stored.getHeader().bitcoinSerialize());
@@ -217,15 +221,14 @@ public class DerbyBlockStore implements BlockStore {
}
}
- @Override
- public StoredBlock get(byte[] hash) throws BlockStoreException {
+ public StoredBlock get(Sha256Hash hash) throws BlockStoreException {
// Optimize for chain head
- if (chainHeadHash != null && chainHeadHash.equals(new Sha256Hash(hash)))
+ if (chainHeadHash != null && chainHeadHash.equals(hash))
return chainHeadBlock;
try {
PreparedStatement s = conn
- .prepareStatement("SELECT chainWork, height, header FROM blocks WHERE hash = ?");
- s.setBytes(1, hash);
+ .prepareStatement("SELECT chainWork, height, header FROM blocks WHERE hash = ?");
+ s.setBytes(1, hash.getBytes());
ResultSet results = s.executeQuery();
if (!results.next()) {
return null;
@@ -240,7 +243,7 @@ public class DerbyBlockStore implements BlockStore {
stored = new StoredBlock(params.genesisBlock.cloneAsHeader(),
params.genesisBlock.getWork(), 0);
} else {
- b.verify();
+ b.verifyHeader();
stored = new StoredBlock(b, chainWork, height);
}
return stored;
@@ -257,21 +260,19 @@ public class DerbyBlockStore implements BlockStore {
}
@SuppressWarnings("unused")
- @Override
public StoredBlock getChainHead() throws BlockStoreException {
return chainHeadBlock;
}
- @Override
public void setChainHead(StoredBlock chainHead) throws BlockStoreException {
- byte[] hash = chainHead.getHeader().getHash();
- this.chainHeadHash = new Sha256Hash(hash);
+ Sha256Hash hash = chainHead.getHeader().getHash();
+ this.chainHeadHash = hash;
this.chainHeadBlock = chainHead;
try {
PreparedStatement s = conn
.prepareStatement("UPDATE settings SET value = ? WHERE name = ?");
s.setString(2, CHAIN_HEAD_SETTING);
- s.setBytes(1, hash);
+ s.setBytes(1, hash.getBytes());
s.executeUpdate();
s.close();
startCommitter();
@@ -316,7 +317,6 @@ public class DerbyBlockStore implements BlockStore {
// A thread that is guaranteed to try a commit as long as
// committerThread is not null
Runnable committer = new Runnable() {
- @Override
public void run() {
try {
log.info("commit scheduled");
diff --git a/tests/com/google/bitcoin/core/DerbyBlockStoreTest.java b/tests/com/google/bitcoin/store/DerbyBlockStoreTest.java
similarity index 73%
rename from tests/com/google/bitcoin/core/DerbyBlockStoreTest.java
rename to tests/com/google/bitcoin/store/DerbyBlockStoreTest.java
index a7645fce..e8519a95 100644
--- a/tests/com/google/bitcoin/core/DerbyBlockStoreTest.java
+++ b/tests/com/google/bitcoin/store/DerbyBlockStoreTest.java
@@ -13,20 +13,30 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.google.bitcoin.core;
+package com.google.bitcoin.store;
import static org.junit.Assert.assertEquals;
+import com.google.bitcoin.core.Address;
+import com.google.bitcoin.core.ECKey;
+import com.google.bitcoin.core.NetworkParameters;
+import com.google.bitcoin.core.StoredBlock;
+
import org.junit.Test;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
public class DerbyBlockStoreTest {
/**
- *
+ * This path will be deleted recursively!
*/
private static final String DB_NAME = ".bitcoinj.unittest.derby";
@Test
public void testStorage() throws Exception {
+ deleteRecursively(new File(DB_NAME));
NetworkParameters params = NetworkParameters.unitTests();
Address to = new ECKey().toAddress(params);
DerbyBlockStore store = new DerbyBlockStore(params, DB_NAME);
@@ -49,4 +59,13 @@ public class DerbyBlockStoreTest {
assertEquals(b1, store.getChainHead());
store.dump();
}
+
+ void deleteRecursively(File f) throws IOException {
+ if (f.isDirectory()) {
+ for (File c : f.listFiles())
+ deleteRecursively(c);
+ }
+ if (!f.delete())
+ throw new FileNotFoundException("Failed to delete file: " + f);
+ }
}