mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-07-30 19:41:24 +00:00
Make BlockStore and StoredBlock public. Move StoredBlock building into the class itself.
This commit is contained in:
@@ -72,7 +72,7 @@ public class BlockChain {
|
|||||||
try {
|
try {
|
||||||
blockStore = new MemoryBlockStore(params);
|
blockStore = new MemoryBlockStore(params);
|
||||||
chainHead = blockStore.getChainHead();
|
chainHead = blockStore.getChainHead();
|
||||||
LOG("chain head is: " + chainHead.header.toString());
|
LOG("chain head is: " + chainHead.getHeader().toString());
|
||||||
} catch (BlockStoreException e) {
|
} catch (BlockStoreException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@@ -137,13 +137,13 @@ public class BlockChain {
|
|||||||
} else {
|
} else {
|
||||||
// The block connects to somewhere on the chain. Not necessarily the top of the best known chain.
|
// The block connects to somewhere on the chain. Not necessarily the top of the best known chain.
|
||||||
checkDifficultyTransitions(storedPrev, block);
|
checkDifficultyTransitions(storedPrev, block);
|
||||||
StoredBlock newStoredBlock = buildStoredBlock(storedPrev, block);
|
StoredBlock newStoredBlock = storedPrev.build(block);
|
||||||
// Store it.
|
// Store it.
|
||||||
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.
|
||||||
setChainHead(newStoredBlock);
|
setChainHead(newStoredBlock);
|
||||||
LOG("Received new block, chain is now " + chainHead.height + " blocks high");
|
LOG("Received new block, chain is now " + chainHead.getHeight() + " 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.
|
||||||
if (newStoredBlock.moreWorkThan(chainHead)) {
|
if (newStoredBlock.moreWorkThan(chainHead)) {
|
||||||
@@ -172,17 +172,6 @@ public class BlockChain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the additional fields a StoredBlock holds given the previous block in the chain and the new block.
|
|
||||||
*/
|
|
||||||
private StoredBlock buildStoredBlock(StoredBlock storedPrev, Block block) throws VerificationException {
|
|
||||||
// Stored blocks track total work done in this chain, because the canonical chain is the one that represents
|
|
||||||
// the largest amount of work done not the tallest.
|
|
||||||
BigInteger chainWork = storedPrev.chainWork.add(block.getWork());
|
|
||||||
int height = storedPrev.height + 1;
|
|
||||||
return new StoredBlock(block, chainWork, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For each block in unconnectedBlocks, see if we can now fit it on top of the chain and if so, do so.
|
* For each block in unconnectedBlocks, see if we can now fit it on top of the chain and if so, do so.
|
||||||
*/
|
*/
|
||||||
@@ -219,12 +208,12 @@ public class BlockChain {
|
|||||||
*/
|
*/
|
||||||
private void checkDifficultyTransitions(StoredBlock storedPrev, Block next)
|
private void checkDifficultyTransitions(StoredBlock storedPrev, Block next)
|
||||||
throws BlockStoreException, VerificationException {
|
throws BlockStoreException, VerificationException {
|
||||||
Block prev = storedPrev.header;
|
Block prev = storedPrev.getHeader();
|
||||||
// Is this supposed to be a difficulty transition point?
|
// Is this supposed to be a difficulty transition point?
|
||||||
if ((storedPrev.height + 1) % params.interval != 0) {
|
if ((storedPrev.getHeight() + 1) % params.interval != 0) {
|
||||||
// No ... so check the difficulty didn't actually change.
|
// No ... so check the difficulty didn't actually change.
|
||||||
if (next.getDifficultyTarget() != prev.getDifficultyTarget())
|
if (next.getDifficultyTarget() != prev.getDifficultyTarget())
|
||||||
throw new VerificationException("Unexpected change in difficulty at height " + storedPrev.height +
|
throw new VerificationException("Unexpected change in difficulty at height " + storedPrev.getHeight() +
|
||||||
": " + Long.toHexString(next.getDifficultyTarget()) + " vs " +
|
": " + Long.toHexString(next.getDifficultyTarget()) + " vs " +
|
||||||
Long.toHexString(prev.getDifficultyTarget()));
|
Long.toHexString(prev.getDifficultyTarget()));
|
||||||
return;
|
return;
|
||||||
@@ -239,10 +228,10 @@ public class BlockChain {
|
|||||||
throw new VerificationException(
|
throw new VerificationException(
|
||||||
"Difficulty transition point but we did not find a way back to the genesis block.");
|
"Difficulty transition point but we did not find a way back to the genesis block.");
|
||||||
}
|
}
|
||||||
cursor = blockStore.get(cursor.header.getPrevBlockHash());
|
cursor = blockStore.get(cursor.getHeader().getPrevBlockHash());
|
||||||
}
|
}
|
||||||
|
|
||||||
Block blockIntervalAgo = cursor.header;
|
Block blockIntervalAgo = cursor.getHeader();
|
||||||
int timespan = (int) (prev.getTime() - blockIntervalAgo.getTime());
|
int timespan = (int) (prev.getTime() - blockIntervalAgo.getTime());
|
||||||
// Limit the adjustment step.
|
// Limit the adjustment step.
|
||||||
if (timespan < params.targetTimespan / 4)
|
if (timespan < params.targetTimespan / 4)
|
||||||
|
@@ -26,7 +26,7 @@ package com.google.bitcoin.core;
|
|||||||
*
|
*
|
||||||
* BlockStores are thread safe.
|
* BlockStores are thread safe.
|
||||||
*/
|
*/
|
||||||
interface BlockStore {
|
public interface BlockStore {
|
||||||
/**
|
/**
|
||||||
* Saves the given block header+extra data. The key isn't specified explicitly as it can be calculated from the
|
* Saves the given block header+extra data. The key isn't specified explicitly as it can be calculated from the
|
||||||
* StoredBlock directly. Can throw if there is a problem with the underlying storage layer such as running out of
|
* StoredBlock directly. Can throw if there is a problem with the underlying storage layer such as running out of
|
||||||
|
@@ -20,6 +20,10 @@ 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(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
public BlockStoreException(Throwable t) {
|
public BlockStoreException(Throwable t) {
|
||||||
super(t);
|
super(t);
|
||||||
}
|
}
|
||||||
|
@@ -50,7 +50,7 @@ class MemoryBlockStore implements BlockStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void put(StoredBlock block) throws BlockStoreException {
|
public synchronized void put(StoredBlock block) throws BlockStoreException {
|
||||||
byte[] hash = block.header.getHash();
|
byte[] hash = block.getHeader().getHash();
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
try {
|
try {
|
||||||
ObjectOutputStream oos = new ObjectOutputStream(bos);
|
ObjectOutputStream oos = new ObjectOutputStream(bos);
|
||||||
|
@@ -304,7 +304,7 @@ public class Peer {
|
|||||||
// We don't do the exponential thinning here, so if we get onto a fork of the chain we will end up
|
// We don't do the exponential thinning here, so if we get onto a fork of the chain we will end up
|
||||||
// redownloading the whole thing again.
|
// redownloading the whole thing again.
|
||||||
blockLocator.add(params.genesisBlock.getHash());
|
blockLocator.add(params.genesisBlock.getHash());
|
||||||
Block topBlock = blockChain.getChainHead().header;
|
Block topBlock = blockChain.getChainHead().getHeader();
|
||||||
if (!topBlock.equals(params.genesisBlock))
|
if (!topBlock.equals(params.genesisBlock))
|
||||||
blockLocator.add(0, topBlock.getHash());
|
blockLocator.add(0, topBlock.getHash());
|
||||||
GetBlocksMessage message = new GetBlocksMessage(params, blockLocator, toHash);
|
GetBlocksMessage message = new GetBlocksMessage(params, blockLocator, toHash);
|
||||||
|
@@ -28,35 +28,46 @@ import java.math.BigInteger;
|
|||||||
*
|
*
|
||||||
* StoredBlocks are put inside a {@link BlockStore} which saves them to memory or disk.
|
* StoredBlocks are put inside a {@link BlockStore} which saves them to memory or disk.
|
||||||
*/
|
*/
|
||||||
class StoredBlock implements Serializable {
|
public class StoredBlock implements Serializable {
|
||||||
private static final long serialVersionUID = -6097565241243701771L;
|
private static final long serialVersionUID = -6097565241243701771L;
|
||||||
|
|
||||||
/**
|
private Block header;
|
||||||
* The block header this object wraps. The referenced block object must not have any transactions in it.
|
private BigInteger chainWork;
|
||||||
*/
|
private int height;
|
||||||
Block header;
|
|
||||||
|
|
||||||
/**
|
public StoredBlock(Block header, BigInteger chainWork, int height) {
|
||||||
* The total sum of work done in this block, and all the blocks below it in the chain. Work is a measure of how
|
|
||||||
* many tries are needed to solve a block. If the target is set to cover 10% of the total hash value space,
|
|
||||||
* then the work represented by a block is 10.
|
|
||||||
*/
|
|
||||||
BigInteger chainWork;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Position in the chain for this block. The genesis block has a height of zero.
|
|
||||||
*/
|
|
||||||
int height;
|
|
||||||
|
|
||||||
StoredBlock(Block header, BigInteger chainWork, int height) {
|
|
||||||
assert header.transactions == null : "Should not have transactions in a block header object";
|
assert header.transactions == null : "Should not have transactions in a block header object";
|
||||||
this.header = header;
|
this.header = header;
|
||||||
this.chainWork = chainWork;
|
this.chainWork = chainWork;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The block header this object wraps. The referenced block object must not have any transactions in it.
|
||||||
|
*/
|
||||||
|
public Block getHeader() {
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The total sum of work done in this block, and all the blocks below it in the chain. Work is a measure of how
|
||||||
|
* many tries are needed to solve a block. If the target is set to cover 10% of the total hash value space,
|
||||||
|
* then the work represented by a block is 10.
|
||||||
|
*/
|
||||||
|
public BigInteger getChainWork() {
|
||||||
|
return chainWork;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Position in the chain for this block. The genesis block has a height of zero.
|
||||||
|
*/
|
||||||
|
public int getHeight() {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns true if this objects chainWork is higher than the others. */
|
/** Returns true if this objects chainWork is higher than the others. */
|
||||||
boolean moreWorkThan(StoredBlock other) {
|
public boolean moreWorkThan(StoredBlock other) {
|
||||||
return chainWork.compareTo(other.chainWork) > 0;
|
return chainWork.compareTo(other.chainWork) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,4 +77,16 @@ class StoredBlock implements Serializable {
|
|||||||
StoredBlock o = (StoredBlock) other;
|
StoredBlock o = (StoredBlock) other;
|
||||||
return o.header.equals(header) && o.chainWork.equals(chainWork) && o.height == height;
|
return o.header.equals(header) && o.chainWork.equals(chainWork) && o.height == height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new StoredBlock, calculating the additional fields by adding to the values in this block.
|
||||||
|
*/
|
||||||
|
public StoredBlock build(Block block) throws VerificationException {
|
||||||
|
// Stored blocks track total work done in this chain, because the canonical chain is the one that represents
|
||||||
|
// the largest amount of work done not the tallest.
|
||||||
|
BigInteger chainWork = this.chainWork.add(block.getWork());
|
||||||
|
int height = this.height + 1;
|
||||||
|
return new StoredBlock(block, chainWork, height);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -383,8 +383,8 @@ public class Wallet implements Serializable {
|
|||||||
// This runs on any peer thread with the block chain synchronized. Thus we do not have to worry about it
|
// This runs on any peer thread with the block chain synchronized. Thus we do not have to worry about it
|
||||||
// being called simultaneously or repeatedly.
|
// being called simultaneously or repeatedly.
|
||||||
LOG("Re-organize!");
|
LOG("Re-organize!");
|
||||||
LOG("Old chain head: " + chainHead.header.toString());
|
LOG("Old chain head: " + chainHead.getHeader().toString());
|
||||||
LOG("New chain head: " + newStoredBlock.header.toString());
|
LOG("New chain head: " + newStoredBlock.getHeader().toString());
|
||||||
|
|
||||||
// TODO: Implement me!
|
// TODO: Implement me!
|
||||||
// For each transaction we have to track which blocks they appeared in. Once a re-org takes place,
|
// For each transaction we have to track which blocks they appeared in. Once a re-org takes place,
|
||||||
|
Reference in New Issue
Block a user