Change to how "best block" is determined.

This commit is contained in:
catbref 2019-06-14 17:58:54 +01:00
parent c559c16a4a
commit 99ffd62a6e
9 changed files with 153 additions and 10 deletions

View File

@ -142,12 +142,11 @@ public class BlockGenerator extends Thread {
boolean newBlockGenerated = false;
generation: try {
try {
// Clear repository's "in transaction" state so we don't cause a repository deadlock
repository.discardChanges();
List<Block> goodBlocks = new ArrayList<>();
for (Block testBlock : newBlocks) {
// Is new block's timestamp valid yet?
// We do a separate check as some timestamp checks are skipped for testchains
@ -162,7 +161,7 @@ public class BlockGenerator extends Thread {
}
if (goodBlocks.isEmpty())
break generation;
continue;
// Pick random generator
int winningIndex = new Random().nextInt(goodBlocks.size());
@ -182,8 +181,10 @@ public class BlockGenerator extends Thread {
if (validationResult != ValidationResult.OK) {
// No longer valid? Report and discard
LOGGER.error("Valid, generated block now invalid '" + validationResult.name() + "' after adding unconfirmed transactions?");
// Rebuild block candidates, just to be sure
newBlocks.clear();
break generation;
continue;
}
// Add to blockchain - something else will notice and broadcast new block to network

View File

@ -29,7 +29,7 @@ import org.qora.block.BlockGenerator;
import org.qora.controller.Synchronizer.SynchronizationResult;
import org.qora.crypto.Crypto;
import org.qora.data.block.BlockData;
import org.qora.data.network.BlockSummaryData;
import org.qora.data.block.BlockSummaryData;
import org.qora.data.network.PeerData;
import org.qora.data.transaction.ArbitraryTransactionData;
import org.qora.data.transaction.ArbitraryTransactionData.DataType;

View File

@ -10,7 +10,7 @@ import org.apache.logging.log4j.Logger;
import org.qora.block.Block;
import org.qora.block.Block.ValidationResult;
import org.qora.data.block.BlockData;
import org.qora.data.network.BlockSummaryData;
import org.qora.data.block.BlockSummaryData;
import org.qora.data.transaction.TransactionData;
import org.qora.network.Peer;
import org.qora.network.message.BlockMessage;

View File

@ -1,6 +1,4 @@
package org.qora.data.network;
import org.qora.data.block.BlockData;
package org.qora.data.block;
public class BlockSummaryData {

View File

@ -7,7 +7,7 @@ import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import org.qora.data.network.BlockSummaryData;
import org.qora.data.block.BlockSummaryData;
import org.qora.transform.Transformer;
import org.qora.transform.block.BlockTransformer;

View File

@ -4,6 +4,7 @@ import java.util.List;
import org.qora.api.model.BlockForgerSummary;
import org.qora.data.block.BlockData;
import org.qora.data.block.BlockSummaryData;
import org.qora.data.block.BlockTransactionData;
import org.qora.data.transaction.TransactionData;
@ -117,6 +118,11 @@ public interface BlockRepository {
*/
public List<BlockData> getBlocks(int firstBlockHeight, int lastBlockHeight) throws DataException;
/**
* Returns block summaries for the passed height range.
*/
public List<BlockSummaryData> getBlockSummaries(int firstBlockHeight, int lastBlockHeight) throws DataException;
/**
* Saves block into repository.
*

View File

@ -9,6 +9,7 @@ import java.util.List;
import org.qora.api.model.BlockForgerSummary;
import org.qora.data.block.BlockData;
import org.qora.data.block.BlockSummaryData;
import org.qora.data.block.BlockTransactionData;
import org.qora.data.transaction.TransactionData;
import org.qora.repository.BlockRepository;
@ -265,6 +266,31 @@ public class HSQLDBBlockRepository implements BlockRepository {
}
}
@Override
public List<BlockSummaryData> getBlockSummaries(int firstBlockHeight, int lastBlockHeight) throws DataException {
String sql = "SELECT signature, height, generator FROM Blocks WHERE height BETWEEN ? AND ?";
List<BlockSummaryData> blockSummaries = new ArrayList<>();
try (ResultSet resultSet = this.repository.checkedExecute(sql, firstBlockHeight, lastBlockHeight)) {
if (resultSet == null)
return blockSummaries;
do {
byte[] signature = resultSet.getBytes(1);
int height = resultSet.getInt(2);
byte[] generatorPublicKey = resultSet.getBytes(3);
BlockSummaryData blockSummary = new BlockSummaryData(height, signature, generatorPublicKey);
blockSummaries.add(blockSummary);
} while (resultSet.next());
return blockSummaries;
} catch (SQLException e) {
throw new DataException("Unable to fetch height-ranged block summaries from repository", e);
}
}
@Override
public void save(BlockData blockData) throws DataException {
HSQLDBSaver saveHelper = new HSQLDBSaver("Blocks");

View File

@ -0,0 +1,46 @@
package org.qora.utils;
import java.util.Comparator;
import com.google.common.hash.HashCode;
public class ByteArray implements Comparable<ByteArray> {
private static final Comparator<ByteArray> COMPARATOR;
static {
COMPARATOR = Comparator.comparing(byteArray -> byteArray.comparable);
}
private final String comparable;
public final byte[] raw;
public ByteArray(byte[] content) {
this.comparable = HashCode.fromBytes(content).toString();
this.raw = content;
}
@Override
public boolean equals(Object other) {
if (this == other)
return true;
if (!(other instanceof ByteArray))
return false;
ByteArray otherByteArray = (ByteArray) other;
return this.comparable.equals(otherByteArray.comparable);
}
@Override
public int hashCode() {
return this.comparable.hashCode();
}
@Override
public int compareTo(ByteArray other) {
return COMPARATOR.compare(this, other);
}
}

View File

@ -0,0 +1,66 @@
package org.qora.test;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.junit.Before;
import org.junit.Test;
import org.qora.utils.ByteArray;
public class ByteArrayTests {
private static List<byte[]> testValues;
@Before
public void createTestValues() {
Random random = new Random();
testValues = new ArrayList<>();
for (int i = 0; i < 5; ++i) {
byte[] testValue = new byte[32];
random.nextBytes(testValue);
testValues.add(testValue);
}
}
public void fillMap(Map<ByteArray, String> map) {
for (byte[] testValue : testValues)
map.put(new ByteArray(testValue), String.valueOf(map.size()));
}
@Test
public void testByteArray() {
// Create two objects, which will have different references, but same content.
byte[] testValue = testValues.get(0);
ByteArray ba1 = new ByteArray(testValue);
ByteArray ba2 = new ByteArray(testValue);
// Confirm JVM-assigned references are different
assertNotSame(ba1, ba2);
// Confirm "equals" works as intended
assertTrue("equals did not return true", ba1.equals(ba2));
assertEquals("ba1 not equal to ba2", ba1, ba2);
// Confirm "hashCode" results match
assertEquals("hashCodes do not match", ba1.hashCode(), ba2.hashCode());
}
@Test
public void testByteArrayMap() {
Map<ByteArray, String> testMap = new HashMap<>();
fillMap(testMap);
// Create new ByteArray object with an existing value.
ByteArray ba = new ByteArray(testValues.get(3));
// Confirm object can be found in map
assertTrue("ByteArray not found in map", testMap.containsKey(ba));
}
}