3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-01-30 14:52:16 +00:00

Delete the Derby block store. It isn't that useful now we have full verification based on H2.

This commit is contained in:
Mike Hearn 2013-02-25 21:43:43 +01:00
parent 6b684a6dc6
commit a700b97f75
4 changed files with 0 additions and 537 deletions

View File

@ -158,11 +158,6 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>

View File

@ -1,331 +0,0 @@
package com.google.bitcoin.store;
/**
* 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.
*/
import com.google.bitcoin.core.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigInteger;
import java.sql.*;
/**
* A block store using the Apache Derby pure-java embedded database.
*
* @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);
private StoredBlock chainHeadBlock;
private Sha256Hash chainHeadHash;
private NetworkParameters params;
private Connection conn;
private String dbName;
private Thread committerThread;
static final String driver = "org.apache.derby.jdbc.EmbeddedDriver";
static final String CREATE_SETTINGS_TABLE = "CREATE TABLE settings ( "
+ "name VARCHAR(32) NOT NULL CONSTRAINT settings_pk PRIMARY KEY,"
+ "value BLOB"
+ ")";
static final String CREATE_BLOCKS_TABLE = "CREATE TABLE blocks ( "
+ "hash CHAR(32) FOR BIT DATA NOT NULL CONSTRAINT blocks_pk PRIMARY KEY,"
+ "chainWork BLOB NOT NULL,"
+ "height BIGINT NOT NULL,"
+ "header BLOB NOT NULL"
+ ")";
static final String CHAIN_HEAD_SETTING = "chainhead";
public static void main(String[] args) throws Exception {
DerbyBlockStore store = new DerbyBlockStore(NetworkParameters.testNet(), ".bitcoinj-test.derby");
store.resetStore();
}
public synchronized void close() {
String connectionURL = "jdbc:derby:" + dbName + ";shutdown=true";
try {
if (conn != null) {
conn.commit();
conn = null;
}
if (committerThread != null)
committerThread.interrupt();
DriverManager.getConnection(connectionURL);
} catch (SQLException ex) {
if (( (ex.getErrorCode() == 45000)
&& ("08006".equals(ex.getSQLState()) ))) {
// we got the expected exception
log.info("Derby shut down normally");
// Note that for single database shutdown, the expected
// SQL state is "08006", and the error code is 45000.
}
else {
throw new RuntimeException(ex);
}
}
}
private synchronized void commit() throws BlockStoreException {
try {
if (conn != null)
conn.commit();
} catch (SQLException ex) {
log.error("commit failed", ex);
throw new BlockStoreException(ex);
}
}
public DerbyBlockStore(NetworkParameters params, String dbName) throws BlockStoreException {
this.params = params;
this.dbName = dbName;
String connectionURL = "jdbc:derby:" + dbName + ";create=true";
try {
Class.forName(driver);
log.info(driver + " loaded. ");
} catch (java.lang.ClassNotFoundException e) {
log.error("check CLASSPATH for Derby jar ", e);
}
try {
conn = DriverManager.getConnection(connectionURL);
conn.setAutoCommit(false);
log.info("Connected to database " + connectionURL);
// Create tables if needed
if (!isTableExists("settings")) {
createTables();
}
initFromDatabase();
} catch (SQLException ex) {
throw new BlockStoreException(ex);
}
}
public void resetStore() throws BlockStoreException {
Statement s;
try {
s = conn.createStatement();
s.executeUpdate("DROP TABLE settings");
s.executeUpdate("DROP TABLE blocks");
s.close();
createTables();
initFromDatabase();
startCommitter();
} catch (SQLException ex) {
throw new RuntimeException(ex);
}
}
private void createTables() throws SQLException, BlockStoreException {
Statement s = conn.createStatement();
log.debug("DerbyBlockStore : CREATE blocks table");
s.executeUpdate(CREATE_BLOCKS_TABLE);
log.debug("DerbyBlockStore : CREATE settings table");
s.executeUpdate(CREATE_SETTINGS_TABLE);
s.executeUpdate("INSERT INTO settings(name, value) VALUES('chainhead', NULL)");
createNewStore(params);
}
private void initFromDatabase() throws SQLException, BlockStoreException {
Statement s = conn.createStatement();
ResultSet rs = s.executeQuery("SELECT value FROM settings WHERE name = 'chainhead'");
if (!rs.next()) {
throw new BlockStoreException("corrupt Derby block store - no chain head pointer");
}
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 = hash;
}
private void createNewStore(NetworkParameters params) throws BlockStoreException {
try {
// Set up the genesis block. When we start out fresh, it is by
// definition the top of the chain.
Block genesis = params.genesisBlock.cloneAsHeader();
StoredBlock storedGenesis = new StoredBlock(genesis,
genesis.getWork(), 0);
this.chainHeadBlock = storedGenesis;
this.chainHeadHash = storedGenesis.getHeader().getHash();
setChainHead(storedGenesis);
put(storedGenesis);
} catch (VerificationException e1) {
throw new RuntimeException(e1); // Cannot happen.
}
}
private boolean isTableExists(String table) throws SQLException {
Statement s = conn.createStatement();
try {
ResultSet results = s.executeQuery("SELECT * FROM " + table + " WHERE 1 = 2");
results.close();
return true;
} catch (SQLException ex) {
return false;
} finally {
s.close();
}
}
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().getBytes());
s.setBytes(2, stored.getChainWork().toByteArray());
s.setLong(3, stored.getHeight());
s.setBytes(4, stored.getHeader().unsafeBitcoinSerialize());
s.executeUpdate();
s.close();
startCommitter();
} catch (SQLException ex) {
throw new BlockStoreException(ex);
}
}
public StoredBlock get(Sha256Hash hash) throws BlockStoreException {
// Optimize for chain head
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.getBytes());
ResultSet results = s.executeQuery();
if (!results.next()) {
return null;
}
// Parse it.
BigInteger chainWork = new BigInteger(results.getBytes(1));
int height = results.getInt(2);
Block b = new Block(params, results.getBytes(3));
StoredBlock stored;
b.verifyHeader();
stored = new StoredBlock(b, chainWork, height);
return stored;
} catch (SQLException ex) {
throw new BlockStoreException(ex);
} catch (ProtocolException e) {
// Corrupted database.
throw new BlockStoreException(e);
} catch (VerificationException e) {
// Should not be able to happen unless the database contains bad
// blocks.
throw new BlockStoreException(e);
}
}
public StoredBlock getChainHead() throws BlockStoreException {
return chainHeadBlock;
}
public void setChainHead(StoredBlock chainHead) throws BlockStoreException {
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.getBytes());
s.executeUpdate();
s.close();
startCommitter();
} catch (SQLException ex) {
throw new BlockStoreException(ex);
}
}
public void dump() throws SQLException {
Statement s = conn.createStatement();
System.out.println("settings");
ResultSet rs = s.executeQuery("SELECT name, value FROM settings");
while (rs.next()) {
System.out.print(rs.getString(1));
System.out.print(" ");
System.out.println(Utils.bytesToHexString(rs.getBytes(2)));
}
rs.close();
System.out.println("blocks");
rs = s.executeQuery("SELECT hash, chainWork, height, header FROM blocks");
while (rs.next()) {
System.out.print(Utils.bytesToHexString(rs.getBytes(1)));
System.out.print(" ");
System.out.print(Utils.bytesToHexString(rs.getBytes(2)));
System.out.print(" ");
System.out.print(rs.getInt(3));
System.out.print(" ");
//System.out.print(Utils.bytesToHexString(rs.getBytes(4)));
System.out.println();
}
rs.close();
System.out.println("end");
s.close();
}
protected synchronized void startCommitter() {
if (committerThread != null)
return;
// A thread that is guaranteed to try a commit as long as
// committerThread is not null
Runnable committer = new Runnable() {
public void run() {
try {
log.info("commit scheduled");
Thread.sleep(COMMIT_INTERVAL);
} catch (InterruptedException ex) {
// ignore
}
synchronized (DerbyBlockStore.this) {
try {
if (conn != null) {
commit();
log.info("commit success");
}
else {
log.info("committer noticed that we are shutting down");
}
}
catch (BlockStoreException e) {
log.warn("commit failed");
// ignore
}
finally {
committerThread = null;
}
}
}
};
committerThread = new Thread(committer, "DerbyBlockStore committer");
committerThread.start();
}
}

View File

@ -1,71 +0,0 @@
/**
* 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.store;
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.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import java.io.File;
import static org.junit.Assert.assertEquals;
public class DerbyBlockStoreTest {
@Rule
public TemporaryFolder folder = new TemporaryFolder();
@Before
public void shutUp() {
// Prevent Derby writing a useless error log file.
System.getProperties().setProperty("derby.stream.error.file", "");
}
@Test
public void testStorage() throws Exception {
File file = new File(folder.getRoot(), "derby");
String path = file.getAbsolutePath();
NetworkParameters params = NetworkParameters.unitTests();
Address to = new ECKey().toAddress(params);
DerbyBlockStore store = new DerbyBlockStore(params, path);
store.resetStore();
store.dump();
// Check the first block in a new store is the genesis block.
StoredBlock genesis = store.getChainHead();
assertEquals(params.genesisBlock, genesis.getHeader());
// Build a new block.
StoredBlock b1 = genesis.build(genesis.getHeader().createNextBlock(to).cloneAsHeader());
store.put(b1);
store.setChainHead(b1);
store.dump();
// Check we can get it back out again if we rebuild the store object.
store = new DerbyBlockStore(params, path);
StoredBlock b2 = store.get(b1.getHeader().getHash());
assertEquals(b1, b2);
// Check the chain head was stored correctly also.
assertEquals(b1, store.getChainHead());
StoredBlock g1 = store.get(params.genesisBlock.getHash());
assertEquals(params.genesisBlock, g1.getHeader());
store.dump();
store.close();
}
}

View File

@ -1,130 +0,0 @@
/**
* 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 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.ExecutionException;
/**
* 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.
*/
public class DerbyPingService {
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 suffix = testNet ? "testnet" : "prodnet";
String filePrefix = "pingservice-" + suffix;
// 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");
long time = System.currentTimeMillis();
DerbyBlockStore blockStore = new DerbyBlockStore(params, ".bitcoinj-" + suffix);
System.out.println("Opened block store in " + (System.currentTimeMillis() - time) + " ms");
//iterateAll(blockStore);
//blockStore.close();
//System.exit(1);
// Connect to the localhost node. One minute timeout since we won't try any other peers
System.out.println("Connecting ...");
BlockChain chain = new BlockChain(params, wallet, blockStore);
final PeerGroup peerGroup = new PeerGroup(params, chain);
peerGroup.addAddress(new PeerAddress(InetAddress.getLocalHost()));
peerGroup.addWallet(wallet);
peerGroup.start();
// We want to know when the balance changes.
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);
// 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!
Wallet.SendResult sendTx = w.sendCoins(peerGroup, from, value);
assert sendTx.tx != null; // We should never try to send more coins than we have!
System.out.println("Sent coins back! Transaction hash is " + sendTx.tx.getHashAsString());
sendTx.broadcastComplete.get();
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);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
}
});
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.
}
/**
* @param blockStore
* @throws BlockStoreException
*/
static void iterateAll(DerbyBlockStore blockStore) throws BlockStoreException {
long time = System.currentTimeMillis();
StoredBlock block = blockStore.getChainHead();
int count = 0;
while (block != null) {
count++;
if (count % 1000 == 0)
System.out.println("iterated " + count);
block = block.getPrev(blockStore);
}
System.out.println("iterated " + count);
System.out.println("Iterated block store in " + (System.currentTimeMillis() - time) + " ms");
}
}