forked from Qortal/qortal
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:
parent
23408827b3
commit
a2568936a0
@ -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();
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user