Block summaries (repository/data/message/synchronizer) + BlockGenerator

Also refactored some tests.

Original commit was 06fe8fc, with commit message:
Initial implementation of random block generator, etc.
This commit is contained in:
catbref
2019-05-02 17:46:13 +01:00
parent 747f5e41cf
commit 57b982d2fb
9 changed files with 259 additions and 61 deletions

View File

@@ -66,6 +66,15 @@ public class BlockGenerator extends Thread {
List<Block> newBlocks = new ArrayList<>();
while (running) {
// Sleep for a while
try {
repository.discardChanges(); // Free repository locks, if any
Thread.sleep(1000); // No point sleeping less than this as block timestamp millisecond values must be the same
} catch (InterruptedException e) {
// We've been interrupted - time to exit
return;
}
// Check blockchain hasn't changed
BlockData lastBlockData = blockRepository.getLastBlock();
if (previousBlock == null || !Arrays.equals(previousBlock.getSignature(), lastBlockData.getSignature())) {
@@ -155,15 +164,6 @@ public class BlockGenerator extends Thread {
} finally {
blockchainLock.unlock();
}
// Sleep for a while
try {
repository.discardChanges(); // Free repository locks, if any
Thread.sleep(1000); // No point sleeping less than this as block timestamp millisecond values must be the same
} catch (InterruptedException e) {
// We've been interrupted - time to exit
return;
}
}
} catch (DataException e) {
LOGGER.warn("Repository issue while running block generator", e);

View File

@@ -11,9 +11,12 @@ import org.qora.block.Block;
import org.qora.block.Block.ValidationResult;
import org.qora.block.GenesisBlock;
import org.qora.data.block.BlockData;
import org.qora.data.network.BlockSummaryData;
import org.qora.network.Peer;
import org.qora.network.message.BlockMessage;
import org.qora.network.message.BlockSummariesMessage;
import org.qora.network.message.GetBlockMessage;
import org.qora.network.message.GetBlockSummariesMessage;
import org.qora.network.message.GetSignaturesMessage;
import org.qora.network.message.Message;
import org.qora.network.message.Message.MessageType;
@@ -264,6 +267,18 @@ public class Synchronizer {
return blockSignatures;
}
private List<BlockSummaryData> getBlockSummaries(Peer peer, byte[] parentSignature, int numberRequested) {
Message getBlockSummariesMessage = new GetBlockSummariesMessage(parentSignature, numberRequested);
Message message = peer.getResponse(getBlockSummariesMessage);
if (message == null || message.getType() != MessageType.BLOCK_SUMMARIES)
return null;
BlockSummariesMessage blockSummariesMessage = (BlockSummariesMessage) message;
return blockSummariesMessage.getBlockSummaries();
}
private List<byte[]> getBlockSignatures(Peer peer, byte[] parentSignature, int numberRequested) {
// TODO numberRequested is v2+ feature
Message getSignaturesMessage = new GetSignaturesMessage(parentSignature);

View File

@@ -0,0 +1,37 @@
package org.qora.data.network;
import org.qora.data.block.BlockData;
public class BlockSummaryData {
// Properties
private int height;
private byte[] signature;
private byte[] generatorPublicKey;
// Constructors
public BlockSummaryData(int height, byte[] signature, byte[] generatorPublicKey) {
this.height = height;
this.signature = signature;
this.generatorPublicKey = generatorPublicKey;
}
public BlockSummaryData(BlockData blockData) {
this(blockData.getHeight(), blockData.getSignature(), blockData.getGeneratorPublicKey());
}
// Getters / setters
public int getHeight() {
return this.height;
}
public byte[] getSignature() {
return this.signature;
}
public byte[] getGeneratorPublicKey() {
return this.generatorPublicKey;
}
}

View File

@@ -0,0 +1,81 @@
package org.qora.network.message;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import org.qora.data.block.BlockData;
import org.qora.data.network.BlockSummaryData;
import org.qora.transform.Transformer;
import org.qora.transform.block.BlockTransformer;
import com.google.common.primitives.Ints;
public class BlockSummariesMessage extends Message {
private static final int BLOCK_SUMMARY_LENGTH = BlockTransformer.BLOCK_SIGNATURE_LENGTH + Transformer.INT_LENGTH + Transformer.PUBLIC_KEY_LENGTH;
private List<BlockSummaryData> blockSummaries;
public BlockSummariesMessage(List<BlockData> blocksData) {
// Extract what we need from block data
this(-1, blocksData.stream().map(blockData -> new BlockSummaryData(blockData)).collect(Collectors.toList()));
}
private BlockSummariesMessage(int id, List<BlockSummaryData> blockSummaries) {
super(id, MessageType.BLOCK_SUMMARIES);
this.blockSummaries = blockSummaries;
}
public List<BlockSummaryData> getBlockSummaries() {
return this.blockSummaries;
}
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws UnsupportedEncodingException {
int count = bytes.getInt();
if (bytes.remaining() != count * BLOCK_SUMMARY_LENGTH)
return null;
List<BlockSummaryData> blockSummaries = new ArrayList<>();
for (int i = 0; i < count; ++i) {
int height = bytes.getInt();
byte[] signature = new byte[BlockTransformer.BLOCK_SIGNATURE_LENGTH];
bytes.get(signature);
byte[] generatorPublicKey = new byte[Transformer.PUBLIC_KEY_LENGTH];
bytes.get(generatorPublicKey);
BlockSummaryData blockSummary = new BlockSummaryData(height, signature, generatorPublicKey);
blockSummaries.add(blockSummary);
}
return new BlockSummariesMessage(id, blockSummaries);
}
@Override
protected byte[] toData() {
try {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bytes.write(Ints.toByteArray(this.blockSummaries.size()));
for (BlockSummaryData blockSummary : this.blockSummaries) {
bytes.write(blockSummary.getHeight());
bytes.write(blockSummary.getSignature());
bytes.write(blockSummary.getGeneratorPublicKey());
}
return bytes.toByteArray();
} catch (IOException e) {
return null;
}
}
}

View File

@@ -0,0 +1,64 @@
package org.qora.network.message;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import org.qora.transform.Transformer;
import org.qora.transform.block.BlockTransformer;
public class GetBlockSummariesMessage extends Message {
private static final int BLOCK_SIGNATURE_LENGTH = BlockTransformer.BLOCK_SIGNATURE_LENGTH;
private byte[] parentSignature;
private int numberRequested;
public GetBlockSummariesMessage(byte[] parentSignature, int numberRequested) {
this(-1, parentSignature, numberRequested);
}
private GetBlockSummariesMessage(int id, byte[] parentSignature, int numberRequested) {
super(id, MessageType.GET_BLOCK_SUMMARIES);
this.parentSignature = parentSignature;
this.numberRequested = numberRequested;
}
public byte[] getParentSignature() {
return this.parentSignature;
}
public int getNumberRequested() {
return this.numberRequested;
}
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws UnsupportedEncodingException {
if (bytes.remaining() != BLOCK_SIGNATURE_LENGTH + Transformer.INT_LENGTH)
return null;
byte[] parentSignature = new byte[BLOCK_SIGNATURE_LENGTH];
bytes.get(parentSignature);
int numberRequested = bytes.getInt();
return new GetBlockSummariesMessage(id, parentSignature, numberRequested);
}
@Override
protected byte[] toData() {
try {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bytes.write(this.parentSignature);
bytes.write(this.numberRequested);
return bytes.toByteArray();
} catch (IOException e) {
return null;
}
}
}

View File

@@ -40,7 +40,9 @@ public abstract class Message {
VERSION(10),
PEER_ID(11),
PROOF(12),
PEERS_V2(13);
PEERS_V2(13),
GET_BLOCK_SUMMARIES(14),
BLOCK_SUMMARIES(15);
public final int value;
public final Method fromByteBuffer;

View File

@@ -112,6 +112,11 @@ public interface BlockRepository {
*/
public List<BlockData> getBlocksWithGenerator(byte[] generatorPublicKey, Integer limit, Integer offset, Boolean reverse) throws DataException;
/**
* Returns blocks within height range.
*/
public List<BlockData> getBlocks(int firstBlockHeight, int lastBlockHeight) throws DataException;
/**
* Saves block into repository.
*

View File

@@ -215,6 +215,26 @@ public class HSQLDBBlockRepository implements BlockRepository {
}
}
@Override
public List<BlockData> getBlocks(int firstBlockHeight, int lastBlockHeight) throws DataException {
String sql = "SELECT " + BLOCK_DB_COLUMNS + " FROM Blocks WHERE height BETWEEN ? AND ?";
List<BlockData> blockData = new ArrayList<>();
try (ResultSet resultSet = this.repository.checkedExecute(sql, firstBlockHeight, lastBlockHeight)) {
if (resultSet == null)
return blockData;
do {
blockData.add(getBlockFromResultSet(resultSet));
} while (resultSet.next());
return blockData;
} catch (SQLException e) {
throw new DataException("Unable to fetch height-ranged blocks from repository", e);
}
}
@Override
public void save(BlockData blockData) throws DataException {
HSQLDBSaver saveHelper = new HSQLDBSaver("Blocks");