diff --git a/emerald-grpc b/emerald-grpc index c8e9c3d3..fb63222c 160000 --- a/emerald-grpc +++ b/emerald-grpc @@ -1 +1 @@ -Subproject commit c8e9c3d39d45719abe50b967fd5be042ecaf4795 +Subproject commit fb63222c897bfe5da8cad2166ac40f6a452f5e66 diff --git a/src/main/kotlin/io/emeraldpay/dshackle/rpc/ChainEventMapper.kt b/src/main/kotlin/io/emeraldpay/dshackle/rpc/ChainEventMapper.kt index 983e4c64..b23fd67e 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/rpc/ChainEventMapper.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/rpc/ChainEventMapper.kt @@ -147,6 +147,7 @@ class ChainEventMapper { LowerBoundType.TX -> BlockchainOuterClass.LowerBoundType.LOWER_BOUND_TX LowerBoundType.LOGS -> BlockchainOuterClass.LowerBoundType.LOWER_BOUND_LOGS LowerBoundType.TRACE -> BlockchainOuterClass.LowerBoundType.LOWER_BOUND_TRACE + LowerBoundType.PROOF -> BlockchainOuterClass.LowerBoundType.LOWER_BOUND_PROOF } } } diff --git a/src/main/kotlin/io/emeraldpay/dshackle/rpc/StreamHead.kt b/src/main/kotlin/io/emeraldpay/dshackle/rpc/StreamHead.kt index a7054cae..6f7e833e 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/rpc/StreamHead.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/rpc/StreamHead.kt @@ -107,6 +107,7 @@ class StreamHead( LowerBoundType.TX -> BlockchainOuterClass.LowerBoundType.LOWER_BOUND_TX LowerBoundType.LOGS -> BlockchainOuterClass.LowerBoundType.LOWER_BOUND_LOGS LowerBoundType.TRACE -> BlockchainOuterClass.LowerBoundType.LOWER_BOUND_TRACE + LowerBoundType.PROOF -> BlockchainOuterClass.LowerBoundType.LOWER_BOUND_PROOF } } diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/EthereumLowerBoundProofDetector.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/EthereumLowerBoundProofDetector.kt new file mode 100644 index 00000000..8d1d2a4b --- /dev/null +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/EthereumLowerBoundProofDetector.kt @@ -0,0 +1,62 @@ +package io.emeraldpay.dshackle.upstream.ethereum + +import io.emeraldpay.dshackle.Defaults +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.LowerBoundDetector +import io.emeraldpay.dshackle.upstream.lowerbound.LowerBoundType +import io.emeraldpay.dshackle.upstream.lowerbound.detector.RecursiveLowerBound +import io.emeraldpay.dshackle.upstream.lowerbound.toHex +import io.emeraldpay.dshackle.upstream.rpcclient.ListParams +import reactor.core.publisher.Flux +import reactor.core.publisher.Mono + +class EthereumLowerBoundProofDetector( + private val upstream: Upstream, +) : LowerBoundDetector(upstream.getChain()) { + companion object { + private const val NO_PROOF_DATA = "distance to target block exceeds maximum proof window" + + val NO_PROOF_ERRORS = setOf( + NO_PROOF_DATA, + "requested block is too old", + "block not found", + "proofs are available only for the 'latest' block", + "missing trie node", + ) + } + + private val recursiveLowerBound = RecursiveLowerBound(upstream, LowerBoundType.PROOF, NO_PROOF_ERRORS, lowerBounds) + + override fun period(): Long { + return 3 + } + override fun internalDetectLowerBound(): Flux { + return recursiveLowerBound.recursiveDetectLowerBound { block -> + if (block == 0L) { + Mono.just(ChainResponse(ByteArray(0), null)) + } else { + val request = ChainRequest( + "eth_getProof", + ListParams("0x0000000000000000000000000000000000000000", listOf(), block.toHex()), + ) + upstream.getIngressReader() + .read(request) + .timeout(Defaults.internalCallsTimeout) + .doOnNext { + if (it.hasResult() && it.getResult().contentEquals("null".toByteArray())) { + throw IllegalStateException(NO_PROOF_DATA) + } + } + } + }.flatMap { + Flux.just(it, lowerBoundFrom(it, LowerBoundType.PROOF)) + } + } + + override fun types(): Set { + return setOf(LowerBoundType.PROOF) + } +} diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/EthereumLowerBoundService.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/EthereumLowerBoundService.kt index 80b122c2..1c30203b 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/EthereumLowerBoundService.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/EthereumLowerBoundService.kt @@ -14,6 +14,7 @@ class EthereumLowerBoundService( EthereumLowerBoundStateDetector(upstream), EthereumLowerBoundBlockDetector(upstream), EthereumLowerBoundTxDetector(upstream), + EthereumLowerBoundProofDetector(upstream), ) } } diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/lowerbound/LowerBoundData.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/lowerbound/LowerBoundData.kt index 2e9e2afd..110a93f3 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/lowerbound/LowerBoundData.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/lowerbound/LowerBoundData.kt @@ -20,7 +20,7 @@ data class LowerBoundData( } enum class LowerBoundType { - UNKNOWN, STATE, SLOT, BLOCK, TX, LOGS, TRACE + UNKNOWN, STATE, SLOT, BLOCK, TX, LOGS, TRACE, PROOF } fun BlockchainOuterClass.LowerBoundType.fromProtoType(): LowerBoundType { @@ -33,5 +33,6 @@ fun BlockchainOuterClass.LowerBoundType.fromProtoType(): LowerBoundType { BlockchainOuterClass.LowerBoundType.LOWER_BOUND_TX -> LowerBoundType.TX BlockchainOuterClass.LowerBoundType.LOWER_BOUND_LOGS -> LowerBoundType.LOGS BlockchainOuterClass.LowerBoundType.LOWER_BOUND_TRACE -> LowerBoundType.TRACE + BlockchainOuterClass.LowerBoundType.LOWER_BOUND_PROOF -> LowerBoundType.PROOF } }