From d20f2d0c7f480197b72ef8d985509af349095dcb Mon Sep 17 00:00:00 2001 From: KirillPamPam Date: Thu, 17 Apr 2025 18:09:38 +0400 Subject: [PATCH] Reset lower bounds if they're too different (#655) --- .../upstream/lowerbound/LowerBounds.kt | 7 +- .../lowerbound/LowerBoundsPredictionTest.kt | 67 ++++++++++++++++++- 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/lowerbound/LowerBounds.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/lowerbound/LowerBounds.kt index 30736067..cfcb078f 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/lowerbound/LowerBounds.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/lowerbound/LowerBounds.kt @@ -22,14 +22,19 @@ class LowerBounds( fun updateBound(newBound: LowerBoundData) { if (lowerBounds.containsKey(newBound.type)) { val lowerBoundCoeffs = lowerBounds[newBound.type]!! + val lastBound = lowerBoundCoeffs.getLastBound() // we add only bounds with different timestamps - if (newBound.timestamp != lowerBoundCoeffs.getLastBound().timestamp) { + if (newBound.timestamp != lastBound.timestamp) { if (newBound.lowerBound == 1L) { // this is the fully archival node, so there is no need to accumulate bounds and calculate the coeffs lowerBoundCoeffs.updateCoeffs(0.0, 1.0) lowerBoundCoeffs.clearBounds() lowerBoundCoeffs.addBound(newBound) + } else if (newBound.lowerBound < lastBound.lowerBound || (newBound.lowerBound - lastBound.lowerBound) >= 100000) { + lowerBoundCoeffs.updateCoeffs(averageSpeed, calculateB(newBound)) + lowerBoundCoeffs.clearBounds() + lowerBoundCoeffs.addBound(newBound) } else { // accumulate up to MAX_BOUNDS and preserve this size if (lowerBoundCoeffs.boundsSize() == MAX_BOUNDS) { diff --git a/src/test/kotlin/io/emeraldpay/dshackle/upstream/lowerbound/LowerBoundsPredictionTest.kt b/src/test/kotlin/io/emeraldpay/dshackle/upstream/lowerbound/LowerBoundsPredictionTest.kt index 5015bfa1..0aae8346 100644 --- a/src/test/kotlin/io/emeraldpay/dshackle/upstream/lowerbound/LowerBoundsPredictionTest.kt +++ b/src/test/kotlin/io/emeraldpay/dshackle/upstream/lowerbound/LowerBoundsPredictionTest.kt @@ -194,13 +194,78 @@ class LowerBoundsPredictionTest { lowerBounds.updateBound(lowerBound1) val predicted = lowerBounds.predictNextBound(LowerBoundType.STATE) - println(predicted) assertThat(predicted) .isLessThan(37996030) .isGreaterThan(37996020) } + @Test + fun `reset all bound if the next bound is less than the current one`() { + val lowerBounds = LowerBounds(Chain.ETHEREUM__MAINNET) + val lowerBoundState1 = LowerBoundData(15060L, 1010, LowerBoundType.STATE) + val lowerBoundState2 = LowerBoundData(100L, 1020, LowerBoundType.STATE) + val lowerBoundState3 = LowerBoundData(105L, 1030, LowerBoundType.STATE) + val lowerBoundState4 = LowerBoundData(108L, 1040, LowerBoundType.STATE) + val lowerBoundState5 = LowerBoundData(5L, 1050, LowerBoundType.STATE) + + lowerBounds.updateBound(lowerBoundState1) + lowerBounds.updateBound(lowerBoundState2) + + assertThat(lowerBounds.getAllBounds(LowerBoundType.STATE)) + .hasSize(1) + assertThat(lowerBounds.getLastBound(LowerBoundType.STATE)) + .isEqualTo(lowerBoundState2) + + lowerBounds.updateBound(lowerBoundState3) + lowerBounds.updateBound(lowerBoundState4) + + assertThat(lowerBounds.getAllBounds(LowerBoundType.STATE)) + .hasSize(3) + assertThat(lowerBounds.getLastBound(LowerBoundType.STATE)) + .isEqualTo(lowerBoundState4) + + lowerBounds.updateBound(lowerBoundState5) + + assertThat(lowerBounds.getAllBounds(LowerBoundType.STATE)) + .hasSize(1) + assertThat(lowerBounds.getLastBound(LowerBoundType.STATE)) + .isEqualTo(lowerBoundState5) + } + + @Test + fun `reset all bound if the next bound is much bigger than the current one`() { + val lowerBounds = LowerBounds(Chain.ETHEREUM__MAINNET) + val lowerBoundState1 = LowerBoundData(15060L, 1010, LowerBoundType.STATE) + val lowerBoundState2 = LowerBoundData(130000L, 1020, LowerBoundType.STATE) + val lowerBoundState3 = LowerBoundData(131000L, 1030, LowerBoundType.STATE) + val lowerBoundState4 = LowerBoundData(132000L, 1040, LowerBoundType.STATE) + val lowerBoundState5 = LowerBoundData(232000L, 1050, LowerBoundType.STATE) + + lowerBounds.updateBound(lowerBoundState1) + lowerBounds.updateBound(lowerBoundState2) + + assertThat(lowerBounds.getAllBounds(LowerBoundType.STATE)) + .hasSize(1) + assertThat(lowerBounds.getLastBound(LowerBoundType.STATE)) + .isEqualTo(lowerBoundState2) + + lowerBounds.updateBound(lowerBoundState3) + lowerBounds.updateBound(lowerBoundState4) + + assertThat(lowerBounds.getAllBounds(LowerBoundType.STATE)) + .hasSize(3) + assertThat(lowerBounds.getLastBound(LowerBoundType.STATE)) + .isEqualTo(lowerBoundState4) + + lowerBounds.updateBound(lowerBoundState5) + + assertThat(lowerBounds.getAllBounds(LowerBoundType.STATE)) + .hasSize(1) + assertThat(lowerBounds.getLastBound(LowerBoundType.STATE)) + .isEqualTo(lowerBoundState5) + } + @Test fun `update different bounds`() { val lowerBounds = LowerBounds(Chain.ETHEREUM__MAINNET)