Document BlockQueue

This commit is contained in:
nicksavers 2014-10-07 13:09:23 +02:00
parent 8ae2e9a3a4
commit 8b381635e3
1 changed files with 71 additions and 13 deletions

View File

@ -11,6 +11,10 @@ import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
/** /**
* The processing queue for blocks to be validated and added to the blockchain.
* This class also maintains the list of hashes from the peer with the heaviest sub-tree.
* Based on these hashes, blocks are added to the queue.
*
* @author Roman Mandeleil * @author Roman Mandeleil
* Created on: 27/07/2014 11:28 * Created on: 27/07/2014 11:28
*/ */
@ -18,9 +22,17 @@ public class BlockQueue {
private static Logger logger = LoggerFactory.getLogger("blockchain"); private static Logger logger = LoggerFactory.getLogger("blockchain");
/** The list of hashes of the heaviest chain on the network,
* for which this client doesn't have the blocks yet */
private Deque<byte[]> blockHashQueue = new ConcurrentLinkedDeque<>(); private Deque<byte[]> blockHashQueue = new ConcurrentLinkedDeque<>();
/** Queue with blocks to be validated and added to the blockchain */
private Queue<Block> blockReceivedQueue = new ConcurrentLinkedQueue<>(); private Queue<Block> blockReceivedQueue = new ConcurrentLinkedQueue<>();
/** Highest known total difficulty, representing the heaviest chain on the network */
private BigInteger highestTotalDifficulty; private BigInteger highestTotalDifficulty;
/** Last block in the queue to be processed */
private Block lastBlock; private Block lastBlock;
private Timer timer = new Timer("BlockQueueTimer"); private Timer timer = new Timer("BlockQueueTimer");
@ -33,6 +45,9 @@ public class BlockQueue {
}, 10, 10); }, 10, 10);
} }
/**
* Processing the queue adding blocks to the chain.
*/
private void nudgeQueue() { private void nudgeQueue() {
if (blockReceivedQueue.isEmpty()) if (blockReceivedQueue.isEmpty())
return; return;
@ -41,18 +56,28 @@ public class BlockQueue {
WorldManager.getInstance().getBlockchain().add(block); WorldManager.getInstance().getBlockchain().add(block);
} }
/**
* Add a list of blocks to the processing queue.
* The list is validated by making sure the first block in the received list of blocks
* is the next expected block number of the queue.
*
* The queue is configured to contain a maximum number of blocks to avoid memory issues
* If the list exceeds that, the rest of the received blocks in the list are discarded.
*
* @param blockList - the blocks received from a peer to be added to the queue
*/
public void addBlocks(List<Block> blockList) { public void addBlocks(List<Block> blockList) {
Block lastReceivedBlock = blockList.get(blockList.size() - 1); Block lastReceivedBlock = blockList.get(0);
if (lastReceivedBlock.getNumber() != getLastBlock().getNumber() + 1) if (lastReceivedBlock.getNumber() != getLastBlock().getNumber() + 1)
return; return;
for (int i = blockList.size() - 1; i >= 0; --i) { for (Block block : blockList) {
if (blockReceivedQueue.size() > SystemProperties.CONFIG.maxBlocksQueued()) if (blockReceivedQueue.size() > SystemProperties.CONFIG.maxBlocksQueued())
return; return;
this.lastBlock = blockList.get(i); this.lastBlock = block;
logger.trace("Last block now index: [{}]", lastBlock.getNumber()); logger.trace("Last block now index: [{}]", lastBlock.getNumber());
blockReceivedQueue.add(lastBlock); blockReceivedQueue.add(lastBlock);
} }
@ -60,25 +85,35 @@ public class BlockQueue {
blockReceivedQueue.size()); blockReceivedQueue.size());
} }
public BigInteger getHighestTotalDifficulty() { /**
return highestTotalDifficulty; * Returns the last block in the queue. If the queue is empty,
} * this will return the last block added to the blockchain.
*
public void setHighestTotalDifficulty(BigInteger highestTotalDifficulty) { * @return The last known block this client on the network
this.highestTotalDifficulty = highestTotalDifficulty; */
}
public Block getLastBlock() { public Block getLastBlock() {
if (blockReceivedQueue.isEmpty()) if (blockReceivedQueue.isEmpty())
return WorldManager.getInstance().getBlockchain().getLastBlock(); return WorldManager.getInstance().getBlockchain().getLastBlock();
return lastBlock; return lastBlock;
} }
/**
* Reset the queue of hashes of blocks to be retrieved
* and add the best hash to the top of the queue
*
* @param hash - the best hash
*/
public void setBestHash(byte[] hash) { public void setBestHash(byte[] hash) {
blockHashQueue.clear(); blockHashQueue.clear();
blockHashQueue.addLast(hash); blockHashQueue.addLast(hash);
} }
/**
* Returns the last added hash to the queue representing
* the latest known block on the network
*
* @return The best hash on the network known to the client
*/
public byte[] getBestHash() { public byte[] getBestHash() {
return blockHashQueue.peekLast(); return blockHashQueue.peekLast();
} }
@ -87,6 +122,12 @@ public class BlockQueue {
blockHashQueue.addLast(hash); blockHashQueue.addLast(hash);
} }
/**
* Return a list of hashes from blocks that still need to be downloaded.
*
* @param amount - the number of hashes to return
* @return A list of hashes for which blocks need to be retrieved.
*/
public List<byte[]> getHashes(int amount) { public List<byte[]> getHashes(int amount) {
List<byte[]> hashes = new ArrayList<>(); List<byte[]> hashes = new ArrayList<>();
for (int i = 0; i < amount; i++) { for (int i = 0; i < amount; i++) {
@ -114,10 +155,27 @@ public class BlockQueue {
} }
} }
public BigInteger getHighestTotalDifficulty() {
return highestTotalDifficulty;
}
public void setHighestTotalDifficulty(BigInteger highestTotalDifficulty) {
this.highestTotalDifficulty = highestTotalDifficulty;
}
/**
* Returns the current number of blocks in the queue
*
* @return the current number of blocks in the queue
*/
public int size() { public int size() {
return blockReceivedQueue.size(); return blockReceivedQueue.size();
} }
/**
* Cancel and purge the timer-thread that
* processes the blocks in the queue
*/
public void close() { public void close() {
timer.cancel(); timer.cancel();
timer.purge(); timer.purge();