mirror of
https://github.com/bitcoinj/bitcoinj.git
synced 2024-11-19 09:50:32 +01:00
Require block stores to track the best chain head, add for the MemoryBlockStore.
This commit is contained in:
parent
ce927609ba
commit
990f367ef4
@ -69,16 +69,12 @@ public class BlockChain {
|
|||||||
|
|
||||||
public BlockChain(NetworkParameters params, Wallet wallet) {
|
public BlockChain(NetworkParameters params, Wallet wallet) {
|
||||||
// TODO: Let the user pass in a BlockStore object so they can choose how to store the headers.
|
// TODO: Let the user pass in a BlockStore object so they can choose how to store the headers.
|
||||||
blockStore = new MemoryBlockStore();
|
|
||||||
try {
|
try {
|
||||||
// Set up the genesis block. When we start out fresh, it is by definition the top of the chain.
|
blockStore = new MemoryBlockStore(params);
|
||||||
Block genesisHeader = params.genesisBlock.cloneAsHeader();
|
chainHead = blockStore.getChainHead();
|
||||||
chainHead = new StoredBlock(genesisHeader, genesisHeader.getWork(), 0);
|
LOG("chain head is: " + chainHead.header.toString());
|
||||||
blockStore.put(chainHead);
|
|
||||||
} catch (BlockStoreException e) {
|
} catch (BlockStoreException e) {
|
||||||
// Cannot happen.
|
throw new RuntimeException(e);
|
||||||
} catch (VerificationException e) {
|
|
||||||
// Genesis block always verifies.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.params = params;
|
this.params = params;
|
||||||
@ -146,7 +142,7 @@ public class BlockChain {
|
|||||||
blockStore.put(newStoredBlock);
|
blockStore.put(newStoredBlock);
|
||||||
if (storedPrev.equals(chainHead)) {
|
if (storedPrev.equals(chainHead)) {
|
||||||
// This block connects to the best known block, it is a normal continuation of the system.
|
// This block connects to the best known block, it is a normal continuation of the system.
|
||||||
chainHead = newStoredBlock;
|
setChainHead(newStoredBlock);
|
||||||
LOG("Received new block, chain is now " + chainHead.height + " blocks high");
|
LOG("Received new block, chain is now " + chainHead.height + " blocks high");
|
||||||
} else {
|
} else {
|
||||||
// This block connects to somewhere other than the top of the chain.
|
// This block connects to somewhere other than the top of the chain.
|
||||||
@ -154,7 +150,7 @@ public class BlockChain {
|
|||||||
// This chain has overtaken the one we currently believe is best. Reorganize is required.
|
// This chain has overtaken the one we currently believe is best. Reorganize is required.
|
||||||
wallet.reorganize(chainHead, newStoredBlock);
|
wallet.reorganize(chainHead, newStoredBlock);
|
||||||
// Update the pointer to the best known block.
|
// Update the pointer to the best known block.
|
||||||
chainHead = newStoredBlock;
|
setChainHead(newStoredBlock);
|
||||||
} else {
|
} else {
|
||||||
LOG("Received a block which forks the chain, but it did not cause a reorganize.");
|
LOG("Received a block which forks the chain, but it did not cause a reorganize.");
|
||||||
}
|
}
|
||||||
@ -167,6 +163,15 @@ public class BlockChain {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setChainHead(StoredBlock chainHead) {
|
||||||
|
this.chainHead = chainHead;
|
||||||
|
try {
|
||||||
|
blockStore.setChainHead(chainHead);
|
||||||
|
} catch (BlockStoreException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates the additional fields a StoredBlock holds given the previous block in the chain and the new block.
|
* Calculates the additional fields a StoredBlock holds given the previous block in the chain and the new block.
|
||||||
*/
|
*/
|
||||||
|
@ -39,4 +39,14 @@ interface BlockStore {
|
|||||||
* parameter. If no such block is found, returns null.
|
* parameter. If no such block is found, returns null.
|
||||||
*/
|
*/
|
||||||
StoredBlock get(byte[] hash) throws BlockStoreException;
|
StoredBlock get(byte[] hash) throws BlockStoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link StoredBlock} that represents the top of the chain of greatest total work.
|
||||||
|
*/
|
||||||
|
StoredBlock getChainHead() throws BlockStoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the {@link StoredBlock} that represents the top of the chain of greatest total work.
|
||||||
|
*/
|
||||||
|
void setChainHead(StoredBlock chainHead) throws BlockStoreException;
|
||||||
}
|
}
|
||||||
|
@ -20,4 +20,7 @@ package com.google.bitcoin.core;
|
|||||||
* Thrown when something goes wrong with storing a block. Examples: out of disk space.
|
* Thrown when something goes wrong with storing a block. Examples: out of disk space.
|
||||||
*/
|
*/
|
||||||
public class BlockStoreException extends Exception {
|
public class BlockStoreException extends Exception {
|
||||||
|
public BlockStoreException(Throwable t) {
|
||||||
|
super(t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.google.bitcoin.core;
|
package com.google.bitcoin.core;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -27,18 +28,60 @@ class MemoryBlockStore implements BlockStore {
|
|||||||
// We use a ByteBuffer to hold hashes here because the Java array equals()/hashcode() methods do not operate on
|
// We use a ByteBuffer to hold hashes here because the Java array equals()/hashcode() methods do not operate on
|
||||||
// the contents of the array but just inherit the default Object behavior. ByteBuffer provides the functionality
|
// the contents of the array but just inherit the default Object behavior. ByteBuffer provides the functionality
|
||||||
// needed to act as a key in a map.
|
// needed to act as a key in a map.
|
||||||
private Map<ByteBuffer, StoredBlock> blockMap;
|
//
|
||||||
|
// The StoredBlocks are also stored as serialized objects to ensure we don't have assumptions that would make
|
||||||
|
// things harder for disk based implementations.
|
||||||
|
private Map<ByteBuffer, byte[]> blockMap;
|
||||||
|
private StoredBlock chainHead;
|
||||||
|
|
||||||
MemoryBlockStore() {
|
MemoryBlockStore(NetworkParameters params) {
|
||||||
blockMap = new HashMap<ByteBuffer, StoredBlock>();
|
blockMap = new HashMap<ByteBuffer, byte[]>();
|
||||||
|
// Insert the genesis block.
|
||||||
|
try {
|
||||||
|
Block genesisHeader = params.genesisBlock.cloneAsHeader();
|
||||||
|
StoredBlock storedGenesis = new StoredBlock(genesisHeader, genesisHeader.getWork(), 0);
|
||||||
|
put(storedGenesis);
|
||||||
|
setChainHead(storedGenesis);
|
||||||
|
} catch (BlockStoreException e) {
|
||||||
|
throw new RuntimeException(e); // Cannot happen.
|
||||||
|
} catch (VerificationException e) {
|
||||||
|
throw new RuntimeException(e); // Cannot happen.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void put(StoredBlock block) throws BlockStoreException {
|
public synchronized void put(StoredBlock block) throws BlockStoreException {
|
||||||
byte[] hash = block.header.getHash();
|
byte[] hash = block.header.getHash();
|
||||||
blockMap.put(ByteBuffer.wrap(hash), block);
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
ObjectOutputStream oos = new ObjectOutputStream(bos);
|
||||||
|
oos.writeObject(block);
|
||||||
|
oos.close();
|
||||||
|
blockMap.put(ByteBuffer.wrap(hash), bos.toByteArray());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new BlockStoreException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized StoredBlock get(byte[] hash) throws BlockStoreException {
|
public synchronized StoredBlock get(byte[] hash) throws BlockStoreException {
|
||||||
return blockMap.get(ByteBuffer.wrap(hash));
|
try {
|
||||||
|
byte[] serializedBlock = blockMap.get(ByteBuffer.wrap(hash));
|
||||||
|
if (serializedBlock == null)
|
||||||
|
return null;
|
||||||
|
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(serializedBlock));
|
||||||
|
StoredBlock storedBlock = (StoredBlock) ois.readObject();
|
||||||
|
return storedBlock;
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new BlockStoreException(e);
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
throw new BlockStoreException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public StoredBlock getChainHead() {
|
||||||
|
return chainHead;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChainHead(StoredBlock chainHead) throws BlockStoreException {
|
||||||
|
this.chainHead = chainHead;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user