Synchronizer: filter out peers reporting to hold invalid block signatures.

We already mark peers as misbehaved if they returned invalid signatures, but this wasn't sufficient when multiple copies of the same invalid block exist on the network (e.g. after a hard fork). In these cases, we need to be more proactive to avoid syncing with these peers, to increase the chances of preserving other candidate blocks.
This commit is contained in:
CalDescent 2022-06-25 12:45:19 +01:00
parent 23408827b3
commit a2568936a0
2 changed files with 45 additions and 0 deletions

View File

@ -722,6 +722,43 @@ public class Controller extends Thread {
return lastMisbehaved != null && lastMisbehaved > NTP.getTime() - MISBEHAVIOUR_COOLOFF;
};
public static final Predicate<Peer> hasInvalidBlock = peer -> {
final PeerChainTipData peerChainTipData = peer.getChainTipData();
Map<String, Long> invalidBlockSignatures = Synchronizer.getInstance().getInvalidBlockSignatures();
List<byte[]> peerSignatures = new ArrayList<>();
// Add peer's latest block signature
if (peerChainTipData != null) {
peerSignatures.add(peerChainTipData.getLastBlockSignature());
}
// Add peer's blocks since common block
if (peer.getCommonBlockData() == null) {
List<BlockSummaryData> peerSummaries = peer.getCommonBlockData().getBlockSummariesAfterCommonBlock();
if (peerSummaries != null) {
for (BlockSummaryData blockSummaryData : peerSummaries) {
peerSignatures.add(blockSummaryData.getSignature());
}
}
}
// Shortcut if no data
if (peerSignatures.isEmpty() || invalidBlockSignatures == null || invalidBlockSignatures.isEmpty()) {
return false;
}
// Loop through our known invalid blocks and check each one against supplied block summaries
for (String invalidSignature58 : invalidBlockSignatures.keySet()) {
byte[] invalidSignature = Base58.decode(invalidSignature58);
for (byte[] peerSignature : peerSignatures) {
if (Arrays.equals(peerSignature, invalidSignature)) {
return true;
}
}
}
return false;
};
public static final Predicate<Peer> hasNoRecentBlock = peer -> {
final Long minLatestBlockTimestamp = getMinimumLatestBlockTimestamp();
final PeerChainTipData peerChainTipData = peer.getChainTipData();

View File

@ -241,6 +241,10 @@ public class Synchronizer extends Thread {
// Compare the peers against each other, and against our chain, which will return an updated list excluding those without common blocks
peers = Synchronizer.getInstance().comparePeers(peers);
// Disregard peers that hold invalid blocks
// Make sure this is after findCommonBlocksWithPeers() so that peers' summaries can be updated
peers.removeIf(Controller.hasInvalidBlock);
// We may have added more inferior chain tips when comparing peers, so remove any peers that are currently on those chains
peers.removeIf(Controller.hasInferiorChainTip);
@ -840,6 +844,10 @@ public class Synchronizer extends Thread {
/* Invalid block signature tracking */
public Map<String, Long> getInvalidBlockSignatures() {
return this.invalidBlockSignatures;
}
private void addInvalidBlockSignature(byte[] signature) {
Long now = NTP.getTime();
if (now == null) {