Repository navigation
fix(net): correct block validation, fetching, and peer contribution #7005
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: release_v4.8.3
Are you sure you want to change the base?
Changes from all commits
9a5d1b6
1afae71
2d5125f
1f4eb95
29312f3
fbc11c6
018b8c4
fa3b818
a25d6dd
9e3f752
62b4d0a
d4c9362
d0f96c5
28d03e3
adab431
ffa1bf0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -103,8 +103,8 @@ public class PeerConnection { | |
| * clamped to fetchBlock.timeout only afterwards, so sustained degradation saturates | ||
| * within 1-3 samples (issue #6923). Accepted cost: one transient outlier (~10x a | ||
| * healthy estimate) can jump the estimate straight to the clamp, needing ~9 healthy | ||
| * samples to decay; hard-timeout fallback and the saturation gate (one secondary | ||
| * fetch per tick) bound the impact meanwhile. | ||
| * samples to decay; backup dispatch still requires an elapsed timeout or sufficient | ||
| * expected benefit. | ||
| */ | ||
| private static final int FETCH_LATENCY_EWMA_FACTOR = 10; | ||
|
|
||
|
|
@@ -142,6 +142,11 @@ public class PeerConnection { | |
| private Cache<Item, Long> advInvReceive = CacheBuilder.newBuilder().maximumSize(invCacheSize) | ||
| .expireAfterWrite(1, TimeUnit.HOURS).recordStats().build(); | ||
|
|
||
| // Eligible block INV receipt times, pending successful block processing before activity updates. | ||
| @Getter | ||
| private Cache<Item, Long> advBlockInvReceive = CacheBuilder.newBuilder().maximumSize(100) | ||
| .expireAfterWrite(1, TimeUnit.MINUTES).build(); | ||
|
|
||
| @Setter | ||
| @Getter | ||
| private Cache<Item, Long> advInvSpread = CacheBuilder.newBuilder().maximumSize(invCacheSize) | ||
|
|
@@ -195,7 +200,7 @@ public void setChannel(Channel channel) { | |
| this.isRelayPeer = true; | ||
| } | ||
| this.nodeStatistics = TronStatsManager.getNodeStatistics(channel.getInetAddress()); | ||
| lastInteractiveTime = System.currentTimeMillis(); | ||
| updateLastInteractiveTime(System.currentTimeMillis()); | ||
| p2pRateLimiter.register(SYNC_BLOCK_CHAIN.asByte(), | ||
| Args.getInstance().getRateLimiterSyncBlockChain()); | ||
| p2pRateLimiter.register(FETCH_INV_DATA.asByte(), | ||
|
|
@@ -238,7 +243,7 @@ public long getFetchLatency() { | |
| } | ||
|
|
||
| private long clampFetchLatency(long latency) { | ||
| // Saturation intentionally makes the >= timeout gate in FetchBlockService trigger. | ||
| // Bound measured latency without treating saturation as an elapsed fetch timeout. | ||
| return StrictMathWrapper.max(0, | ||
| StrictMathWrapper.min(CommonParameter.getInstance().fetchBlockTimeout, latency)); | ||
| } | ||
|
|
@@ -248,10 +253,39 @@ public void setBlockBothHave(BlockId blockId) { | |
| this.blockBothHaveUpdateTime = System.currentTimeMillis(); | ||
| } | ||
|
|
||
| public synchronized void updateLastInteractiveTime(long time) { | ||
| if (time > lastInteractiveTime) { | ||
| lastInteractiveTime = time; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Returns whether there are no outstanding inventory or sync requests. | ||
| * | ||
| * <p>Sync blocks already being processed and sync direction flags are not checked. | ||
| */ | ||
| public boolean isIdle() { | ||
| return advInvRequest.isEmpty() && isSyncIdle(); | ||
| } | ||
|
|
||
| /** | ||
| * Returns whether there are no outstanding block or sync requests and no sync blocks | ||
| * being processed. Outstanding transaction inventory requests do not make this check fail. | ||
| * | ||
| * <p>Callers must check connection state and sync direction flags separately before fetching. | ||
| */ | ||
| public boolean isBlockFetchIdle() { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [SHOULD] Stale sync-processing state prevents block fetching after synchronization completes. The new Reproduction scenario:
The previous Confirmed with real handlers: synchronization completes with empty request and download queues; the old Please clean up stale
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch. Fixed in 28d03e3. Chain inventory updates now trigger another |
||
| return advInvRequest.keySet().stream() | ||
| .noneMatch(item -> item.getType() == Protocol.Inventory.InventoryType.BLOCK) | ||
| && isSyncIdle() && syncBlockInProcess.isEmpty(); | ||
| } | ||
|
|
||
| /** | ||
| * Returns whether there are no outstanding sync block or chain-summary requests. | ||
| * | ||
| * <p>This does not mean synchronization is complete: received blocks may still be processing, | ||
| * and sync direction flags are not checked. | ||
| */ | ||
| public boolean isSyncIdle() { | ||
| return syncBlockRequested.isEmpty() && syncChainRequested == null; | ||
| } | ||
|
|
@@ -284,6 +318,7 @@ public void onDisconnect() { | |
| syncService.onDisconnect(this); | ||
| advService.onDisconnect(this); | ||
| advInvReceive.invalidateAll(); | ||
| advBlockInvReceive.invalidateAll(); | ||
| advInvSpread.invalidateAll(); | ||
| advInvRequest.clear(); | ||
| syncBlockIdCache.invalidateAll(); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.