Refactoring lower bounds (#450)

This commit is contained in:
KirillPamPam
2024-04-11 18:03:32 +04:00
committed by GitHub
parent 0113862ac4
commit 55e2dc70c4
44 changed files with 619 additions and 418 deletions

View File

@@ -23,12 +23,13 @@ import io.emeraldpay.dshackle.data.BlockContainer
import io.emeraldpay.dshackle.foundation.ChainOptions
import io.emeraldpay.dshackle.reader.Reader
import io.emeraldpay.dshackle.startup.QuorumForLabels
import io.emeraldpay.dshackle.upstream.LowerBoundBlockDetector
import io.emeraldpay.dshackle.upstream.ChainRequest
import io.emeraldpay.dshackle.upstream.ChainResponse
import io.emeraldpay.dshackle.upstream.UpstreamAvailability
import io.emeraldpay.dshackle.upstream.calls.*
import io.emeraldpay.dshackle.upstream.generic.GenericUpstream
import io.emeraldpay.dshackle.upstream.ChainRequest
import io.emeraldpay.dshackle.upstream.ChainResponse
import io.emeraldpay.dshackle.upstream.lowerbound.LowerBoundData
import io.emeraldpay.dshackle.upstream.lowerbound.LowerBoundType
import org.jetbrains.annotations.NotNull
import org.reactivestreams.Publisher
@@ -75,7 +76,7 @@ class GenericUpstreamMock extends GenericUpstream {
new ConnectorFactoryMock(api, new EthereumHeadMock()),
io.emeraldpay.dshackle.upstream.starknet.StarknetChainSpecific.INSTANCE.&validator,
io.emeraldpay.dshackle.upstream.starknet.StarknetChainSpecific.INSTANCE.&upstreamSettingsDetector,
io.emeraldpay.dshackle.upstream.starknet.StarknetChainSpecific.INSTANCE.&lowerBoundBlockDetector,
io.emeraldpay.dshackle.upstream.starknet.StarknetChainSpecific.INSTANCE.&lowerBoundService,
)
this.ethereumHeadMock = this.getHead() as EthereumHeadMock
setLag(0)
@@ -108,7 +109,7 @@ class GenericUpstreamMock extends GenericUpstream {
}
@Override
LowerBoundBlockDetector.LowerBlockData getLowerBlock() {
return new LowerBoundBlockDetector.LowerBlockData(0, 0)
Collection<LowerBoundData> getLowerBounds() {
return List.of(new LowerBoundData(0, LowerBoundType.STATE))
}
}

View File

@@ -77,7 +77,7 @@ class FilteredApisSpec extends Specification {
connectorFactory,
cs.&validator,
cs.&upstreamSettingsDetector,
cs.&lowerBoundBlockDetector
cs.&lowerBoundService
)
}
def matcher = new Selector.LabelMatcher("test", ["foo"])

View File

@@ -2,11 +2,15 @@ package io.emeraldpay.dshackle.upstream
import io.emeraldpay.dshackle.Chain
import io.emeraldpay.dshackle.reader.ChainReader
import io.emeraldpay.dshackle.upstream.ethereum.EthereumLowerBoundBlockDetector
import io.emeraldpay.dshackle.upstream.ethereum.EthereumLowerBoundService
import io.emeraldpay.dshackle.upstream.ethereum.ZERO_ADDRESS
import io.emeraldpay.dshackle.upstream.polkadot.PolkadotLowerBoundBlockDetector
import io.emeraldpay.dshackle.upstream.lowerbound.LowerBoundData
import io.emeraldpay.dshackle.upstream.lowerbound.LowerBoundService
import io.emeraldpay.dshackle.upstream.lowerbound.LowerBoundType
import io.emeraldpay.dshackle.upstream.lowerbound.toHex
import io.emeraldpay.dshackle.upstream.polkadot.PolkadotLowerBoundService
import io.emeraldpay.dshackle.upstream.rpcclient.ListParams
import org.junit.jupiter.api.Assertions.assertEquals
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.Arguments
import org.junit.jupiter.params.provider.MethodSource
@@ -17,13 +21,13 @@ import reactor.core.publisher.Mono
import reactor.test.StepVerifier
import java.time.Duration
class RecursiveLowerBoundBlockDetectorTest {
class RecursiveLowerBoundServiceTest {
@ParameterizedTest
@MethodSource("detectors")
fun `find lower block closer to the height`(
reader: ChainReader,
detectorClass: Class<LowerBoundBlockDetector>,
detectorClass: Class<LowerBoundService>,
) {
val head = mock<Head> {
on { getCurrentHeight() } doReturn 18000000
@@ -35,21 +39,25 @@ class RecursiveLowerBoundBlockDetectorTest {
val detector = detectorClass.getConstructor(Chain::class.java, Upstream::class.java).newInstance(Chain.UNSPECIFIED, upstream)
StepVerifier.withVirtualTime { detector.lowerBlock() }
StepVerifier.withVirtualTime { detector.detectLowerBounds() }
.expectSubscription()
.expectNoEvent(Duration.ofSeconds(15))
.expectNextMatches { it.blockNumber == 17964844L }
.expectNextMatches { it.lowerBound == 17964844L && it.type == LowerBoundType.STATE }
.thenCancel()
.verify(Duration.ofSeconds(3))
assertEquals(17964844L, detector.getCurrentLowerBlock().blockNumber)
assertThat(detector.getLowerBounds().toList())
.usingRecursiveFieldByFieldElementComparatorIgnoringFields("timestamp")
.hasSameElementsAs(
listOf(LowerBoundData(17964844L, LowerBoundType.STATE)),
)
}
@ParameterizedTest
@MethodSource("detectorsFirstBlock")
fun `lower block is 0x1`(
reader: ChainReader,
detectorClass: Class<LowerBoundBlockDetector>,
detectorClass: Class<LowerBoundService>,
) {
val head = mock<Head> {
on { getCurrentHeight() } doReturn 18000000
@@ -61,14 +69,18 @@ class RecursiveLowerBoundBlockDetectorTest {
val detector = detectorClass.getConstructor(Chain::class.java, Upstream::class.java).newInstance(Chain.UNSPECIFIED, upstream)
StepVerifier.withVirtualTime { detector.lowerBlock() }
StepVerifier.withVirtualTime { detector.detectLowerBounds() }
.expectSubscription()
.expectNoEvent(Duration.ofSeconds(15))
.expectNextMatches { it.blockNumber == 1L }
.expectNextMatches { it.lowerBound == 1L }
.thenCancel()
.verify(Duration.ofSeconds(3))
assertEquals(1, detector.getCurrentLowerBlock().blockNumber)
assertThat(detector.getLowerBounds().toList())
.usingRecursiveFieldByFieldElementComparatorIgnoringFields("timestamp")
.hasSameElementsAs(
listOf(LowerBoundData(1L, LowerBoundType.STATE)),
)
}
companion object {
@@ -96,7 +108,7 @@ class RecursiveLowerBoundBlockDetectorTest {
}
}
},
EthereumLowerBoundBlockDetector::class.java,
EthereumLowerBoundService::class.java,
),
Arguments.of(
mock<ChainReader> {
@@ -118,7 +130,7 @@ class RecursiveLowerBoundBlockDetectorTest {
}
}
},
PolkadotLowerBoundBlockDetector::class.java,
PolkadotLowerBoundService::class.java,
),
)
@@ -130,13 +142,13 @@ class RecursiveLowerBoundBlockDetectorTest {
read(any())
} doReturn Mono.just(ChainResponse("\"0x1\"".toByteArray(), null))
},
PolkadotLowerBoundBlockDetector::class.java,
PolkadotLowerBoundService::class.java,
),
Arguments.of(
mock<ChainReader> {
on { read(any()) } doReturn Mono.just(ChainResponse(ByteArray(0), null))
},
EthereumLowerBoundBlockDetector::class.java,
EthereumLowerBoundService::class.java,
),
)
}

View File

@@ -6,8 +6,10 @@ import io.emeraldpay.dshackle.reader.ChainReader
import io.emeraldpay.dshackle.upstream.ChainRequest
import io.emeraldpay.dshackle.upstream.ChainResponse
import io.emeraldpay.dshackle.upstream.Upstream
import io.emeraldpay.dshackle.upstream.lowerbound.LowerBoundData
import io.emeraldpay.dshackle.upstream.lowerbound.LowerBoundType
import io.emeraldpay.dshackle.upstream.rpcclient.ListParams
import org.junit.jupiter.api.Assertions.assertEquals
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
@@ -15,7 +17,7 @@ import reactor.core.publisher.Mono
import reactor.test.StepVerifier
import java.time.Duration
class SolanaLowerBoundBlockDetectorTest {
class SolanaLowerBoundServiceTest {
@Test
fun `get solana lower block and slot`() {
@@ -54,16 +56,23 @@ class SolanaLowerBoundBlockDetectorTest {
on { getIngressReader() } doReturn reader
}
val detector = SolanaLowerBoundBlockDetector(Chain.UNSPECIFIED, upstream)
val detector = SolanaLowerBoundService(Chain.UNSPECIFIED, upstream)
StepVerifier.withVirtualTime { detector.lowerBlock() }
StepVerifier.withVirtualTime { detector.detectLowerBounds() }
.expectSubscription()
.expectNoEvent(Duration.ofSeconds(15))
.expectNextMatches { it.blockNumber == 21000000L && it.slot == 25000000L }
.expectNextMatches { it.lowerBound == 21000000L && it.type == LowerBoundType.STATE }
.expectNextMatches { it.lowerBound == 25000000L && it.type == LowerBoundType.SLOT }
.thenCancel()
.verify(Duration.ofSeconds(3))
assertEquals(21000000, detector.getCurrentLowerBlock().blockNumber)
assertEquals(25000000, detector.getCurrentLowerBlock().slot)
assertThat(detector.getLowerBounds().toList())
.usingRecursiveFieldByFieldElementComparatorIgnoringFields("timestamp")
.hasSameElementsAs(
listOf(
LowerBoundData(21000000L, LowerBoundType.STATE),
LowerBoundData(25000000L, LowerBoundType.SLOT),
),
)
}
}

View File

@@ -1,24 +0,0 @@
package io.emeraldpay.dshackle.upstream.starknet
import io.emeraldpay.dshackle.Chain
import io.emeraldpay.dshackle.upstream.LowerBoundBlockDetector
import io.emeraldpay.dshackle.upstream.Upstream
import org.junit.jupiter.api.Test
import org.mockito.kotlin.mock
import reactor.test.StepVerifier
import java.time.Duration
class StarknetLowerBoundBlockDetectorTest {
@Test
fun `starknet lower block is 1`() {
val detector = StarknetLowerBoundBlockDetector(Chain.UNSPECIFIED, mock<Upstream>())
StepVerifier.withVirtualTime { detector.lowerBlock() }
.expectSubscription()
.expectNoEvent(Duration.ofSeconds(15))
.expectNext(LowerBoundBlockDetector.LowerBlockData(1))
.thenCancel()
.verify(Duration.ofSeconds(3))
}
}

View File

@@ -0,0 +1,22 @@
package io.emeraldpay.dshackle.upstream.starknet
import io.emeraldpay.dshackle.upstream.lowerbound.LowerBoundData
import io.emeraldpay.dshackle.upstream.lowerbound.LowerBoundType
import org.junit.jupiter.api.Test
import reactor.test.StepVerifier
import java.time.Duration
class StarknetLowerBoundStateDetectorTest {
@Test
fun `starknet lower block is 1`() {
val detector = StarknetLowerBoundStateDetector()
StepVerifier.withVirtualTime { detector.detectLowerBound() }
.expectSubscription()
.expectNoEvent(Duration.ofSeconds(15))
.expectNext(LowerBoundData(1, LowerBoundType.STATE))
.thenCancel()
.verify(Duration.ofSeconds(3))
}
}