Browse Source

Keep track of invalid block signatures and avoid peers that return them

Until now, a high weight invalid block can cause other valid, lower weight alternatives to be discarded. The solution to this problem is to track invalid blocks and quickly avoid them once discovered. This gives other valid alternative blocks the opportunity to become part of a valid chain, where they would otherwise have been discarded.

As with the block minter update, this will cause a fork when the highest weight block candidate is invalid. But it is likely that the fork would be short lived, assuming that the majority of nodes pick the valid chain.
block-archive
CalDescent 3 years ago
parent
commit
44a90b4e12
  1. 38
      src/main/java/org/qortal/controller/Synchronizer.java

38
src/main/java/org/qortal/controller/Synchronizer.java

@ -342,6 +342,12 @@ public class Synchronizer {
}
}
// Ignore this peer if it holds an invalid block
if (this.containsInvalidBlock(peer.getCommonBlockData().getBlockSummariesAfterCommonBlock())) {
LOGGER.debug("Ignoring peer %s because it holds an invalid block", peer);
peers.remove(peer);
}
// Reduce minChainLength if needed. If we don't have any blocks, this peer will be excluded from chain weight comparisons later in the process, so we shouldn't update minChainLength
List <BlockSummaryData> peerBlockSummaries = peer.getCommonBlockData().getBlockSummariesAfterCommonBlock();
if (peerBlockSummaries != null && peerBlockSummaries.size() > 0)
@ -485,6 +491,36 @@ public class Synchronizer {
}
/* Invalid block signature tracking */
private void addInvalidBlockSignature(byte[] signature) {
for (byte[] invalidSignature : invalidBlockSignatures) {
if (Arrays.equals(invalidSignature, signature)) {
// Already present
return;
}
}
invalidBlockSignatures.add(signature);
}
private boolean containsInvalidBlock(List<BlockSummaryData> blockSummaries) {
if (blockSummaries == null || invalidBlockSignatures == null) {
return false;
}
// Loop through supplied block summaries and check each one against our known invalid blocks
for (BlockSummaryData blockSummary : blockSummaries) {
byte[] signature = blockSummary.getSignature();
for (byte[] invalidSignature : invalidBlockSignatures) {
if (Arrays.equals(signature, invalidSignature)) {
return true;
}
}
}
return false;
}
/**
* Attempt to synchronize blockchain with peer.
* <p>
@ -990,6 +1026,7 @@ public class Synchronizer {
if (blockResult != ValidationResult.OK) {
LOGGER.info(String.format("Peer %s sent invalid block for height %d, sig %.8s: %s", peer,
newBlock.getBlockData().getHeight(), Base58.encode(newBlock.getSignature()), blockResult.name()));
this.addInvalidBlockSignature(newBlock.getSignature());
this.timeInvalidBlockLastReceived = NTP.getTime();
return SynchronizationResult.INVALID_DATA;
}
@ -1082,6 +1119,7 @@ public class Synchronizer {
if (blockResult != ValidationResult.OK) {
LOGGER.info(String.format("Peer %s sent invalid block for height %d, sig %.8s: %s", peer,
ourHeight, Base58.encode(latestPeerSignature), blockResult.name()));
this.addInvalidBlockSignature(newBlock.getSignature());
this.timeInvalidBlockLastReceived = NTP.getTime();
return SynchronizationResult.INVALID_DATA;
}

Loading…
Cancel
Save