Logs subscription via eth_getLogs (#356)
move retrieving logs subscription to eth_getLogs by hash
This commit is contained in:
@@ -1,185 +0,0 @@
|
||||
package io.emeraldpay.dshackle.upstream.ethereum
|
||||
|
||||
import io.emeraldpay.dshackle.data.BlockContainer
|
||||
import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.dshackle.test.ApiReaderMock
|
||||
import io.emeraldpay.dshackle.test.TestingCommons
|
||||
import io.emeraldpay.dshackle.upstream.AbstractHead
|
||||
import io.emeraldpay.dshackle.upstream.BlockValidator
|
||||
import io.emeraldpay.dshackle.upstream.Lifecycle
|
||||
import io.emeraldpay.dshackle.upstream.forkchoice.MostWorkForkChoice
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
||||
import io.emeraldpay.etherjar.domain.BlockHash
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
import reactor.core.publisher.Sinks
|
||||
import reactor.core.scheduler.Schedulers
|
||||
import reactor.test.StepVerifier
|
||||
import spock.lang.Specification
|
||||
import java.time.Duration
|
||||
|
||||
class EnrichedMergedHeadSpec extends Specification {
|
||||
|
||||
def "ensures that heads are running on start"() {
|
||||
setup:
|
||||
def head1 = Mock(TestHead) {
|
||||
_ * isRunning() >> false
|
||||
_ * getFlux() >> Flux.empty()
|
||||
}
|
||||
def head2 = Mock(TestHead) {
|
||||
_ * isRunning() >> true
|
||||
_ * getFlux() >> Flux.empty()
|
||||
}
|
||||
def head3 = Mock(TestHead) {
|
||||
_ * isRunning() >> false
|
||||
_ * getFlux() >> Flux.empty()
|
||||
}
|
||||
|
||||
def api = new ApiReaderMock()
|
||||
when:
|
||||
def merged = new EnrichedMergedHead([head1, head2], head3, Schedulers.boundedElastic(), new BlockReader(api))
|
||||
merged.start()
|
||||
|
||||
then:
|
||||
1 * head3.start()
|
||||
1 * head1.start()
|
||||
merged.isRunning()
|
||||
}
|
||||
|
||||
def "if enriched block comes from reference head we pass it along instantly"() {
|
||||
setup:
|
||||
def block = TestingCommons.enrichedBlockForEthereum(100)
|
||||
def api = new ApiReaderMock()
|
||||
def head = Stub(TestHead) {
|
||||
_ * isRunning() >> true
|
||||
_ * getFlux() >> Flux.just(block)
|
||||
}
|
||||
when:
|
||||
def merge = new EnrichedMergedHead([], head, Schedulers.boundedElastic(), new BlockReader(api))
|
||||
|
||||
then:
|
||||
StepVerifier.create(merge.getFlux())
|
||||
.then { merge.start() }
|
||||
.expectNext(block)
|
||||
.thenCancel()
|
||||
.verify(Duration.ofMillis(100))
|
||||
block.enriched
|
||||
}
|
||||
|
||||
def "enriched block arrived in sources before reference block"() {
|
||||
setup:
|
||||
def enrichedBlock = TestingCommons.enrichedBlockForEthereum(100)
|
||||
def block = TestingCommons.blockForEthereum(100)
|
||||
Sinks.Many<BlockContainer> refSink = Sinks.many().multicast().directBestEffort()
|
||||
def headRef = Stub(TestHead) {
|
||||
_ * isRunning() >> true
|
||||
_ * getFlux() >> refSink.asFlux()
|
||||
}
|
||||
def headSource = Stub(TestHead) {
|
||||
_ * isRunning() >> true
|
||||
_ * getFlux() >> Flux.just(enrichedBlock)
|
||||
}
|
||||
when:
|
||||
def merge = new EnrichedMergedHead([headSource], headRef, Schedulers.boundedElastic(), new BlockReader(new ApiReaderMock()))
|
||||
then:
|
||||
StepVerifier.create(merge.getFlux())
|
||||
.then { merge.start() }
|
||||
.expectNoEvent(Duration.ofMillis(100))
|
||||
.then { refSink.tryEmitNext(block) }
|
||||
.expectNext(enrichedBlock)
|
||||
.thenCancel()
|
||||
.verify(Duration.ofMillis(200))
|
||||
}
|
||||
|
||||
def "enriched block arrived in source after reference block, but before deadline"() {
|
||||
setup:
|
||||
def enrichedBlock = TestingCommons.enrichedBlockForEthereum(100)
|
||||
def block = TestingCommons.blockForEthereum(100)
|
||||
Sinks.Many<BlockContainer> sourceSink = Sinks.many().multicast().directBestEffort()
|
||||
def headRef = Stub(TestHead) {
|
||||
_ * isRunning() >> true
|
||||
_ * getFlux() >> Flux.just(block)
|
||||
}
|
||||
def headSource = Stub(TestHead) {
|
||||
_ * isRunning() >> true
|
||||
_ * getFlux() >> sourceSink.asFlux()
|
||||
}
|
||||
when:
|
||||
def merge = new EnrichedMergedHead([headSource], headRef, Schedulers.boundedElastic(), new BlockReader(new ApiReaderMock()))
|
||||
then:
|
||||
StepVerifier.create(merge.getFlux())
|
||||
.then { merge.start() }
|
||||
.expectNoEvent(Duration.ofMillis(600))
|
||||
.then { sourceSink.tryEmitNext(enrichedBlock) }
|
||||
.expectNext(enrichedBlock)
|
||||
.thenCancel()
|
||||
.verify(Duration.ofSeconds(1))
|
||||
}
|
||||
|
||||
def "enriched blocks does not arrive before deadline"() {
|
||||
setup:
|
||||
def enrichedBlock = TestingCommons.enrichedBlockForEthereum(100)
|
||||
def block = TestingCommons.blockForEthereum(100)
|
||||
def headRef = Stub(TestHead) {
|
||||
_ * isRunning() >> true
|
||||
_ * getFlux() >> Flux.just(block)
|
||||
}
|
||||
def headSource = Stub(TestHead) {
|
||||
_ * isRunning() >> true
|
||||
_ * getFlux() >> Flux.just(block)
|
||||
}
|
||||
def api = new ApiReaderMock().tap {
|
||||
answer("eth_getBlockByHash", [block.hash.toHexWithPrefix(), false], enrichedBlock.toBlock())
|
||||
}
|
||||
when:
|
||||
def merge = new EnrichedMergedHead([headSource], headRef, Schedulers.boundedElastic(), new BlockReader(api))
|
||||
then:
|
||||
StepVerifier.create(merge.getFlux())
|
||||
.then { merge.start() }
|
||||
.expectNoEvent(Duration.ofSeconds(1))
|
||||
.expectNext(enrichedBlock)
|
||||
.thenCancel()
|
||||
.verify(Duration.ofMillis(1200))
|
||||
}
|
||||
|
||||
class BlockReader implements Reader<BlockHash, BlockContainer> {
|
||||
private ApiReaderMock mockApi
|
||||
BlockReader(ApiReaderMock api) {
|
||||
mockApi = api
|
||||
}
|
||||
|
||||
Mono<BlockContainer> read(BlockHash hash) {
|
||||
return mockApi.read(new JsonRpcRequest("eth_getBlockByHash", [hash.toHex(), false]))
|
||||
.map {
|
||||
def t = it
|
||||
def a = 1
|
||||
return it
|
||||
}
|
||||
.flatMap(JsonRpcResponse::requireResult)
|
||||
.map { BlockContainer.fromEthereumJson(it, "test") }
|
||||
}
|
||||
}
|
||||
|
||||
class TestHead extends AbstractHead implements Lifecycle {
|
||||
|
||||
TestHead() {
|
||||
super(new MostWorkForkChoice(), Schedulers.boundedElastic(), new BlockValidator.AlwaysValid(), 100_000)
|
||||
}
|
||||
|
||||
@Override
|
||||
void start() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
void stop() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isRunning() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.Global
|
||||
import io.emeraldpay.dshackle.cache.Caches
|
||||
import io.emeraldpay.dshackle.cache.CurrentBlockCache
|
||||
import io.emeraldpay.dshackle.data.BlockId
|
||||
import io.emeraldpay.dshackle.data.DefaultContainer
|
||||
import io.emeraldpay.dshackle.reader.RpcReader
|
||||
import io.emeraldpay.dshackle.reader.RpcReaderFactory
|
||||
@@ -17,6 +18,7 @@ import io.emeraldpay.etherjar.domain.BlockHash
|
||||
import io.emeraldpay.etherjar.domain.TransactionId
|
||||
import io.emeraldpay.etherjar.domain.Wei
|
||||
import io.emeraldpay.etherjar.rpc.json.TransactionJson
|
||||
import io.emeraldpay.etherjar.rpc.json.TransactionLogJson
|
||||
import io.emeraldpay.etherjar.rpc.json.TransactionReceiptJson
|
||||
import org.apache.commons.collections4.Factory
|
||||
import reactor.core.publisher.Mono
|
||||
@@ -128,6 +130,38 @@ class EthereumDirectReaderSpec extends Specification {
|
||||
.verify(Duration.ofSeconds(1))
|
||||
}
|
||||
|
||||
def "Reads logs by block hash"() {
|
||||
setup:
|
||||
def json = new TransactionLogJson().tap {
|
||||
address = Address.from(address1)
|
||||
blockHash = BlockHash.from(hash1)
|
||||
}
|
||||
def calls = Mock(Factory) {
|
||||
1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false)
|
||||
}
|
||||
EthereumDirectReader reader = new EthereumDirectReader(
|
||||
Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock()
|
||||
)
|
||||
reader.rpcReaderFactory = Mock(RpcReaderFactory) {
|
||||
1 * create(_) >> Mock(RpcReader) {
|
||||
1 * read(new JsonRpcRequest("eth_getLogs", [Map.of("blockHash", hash1)])) >> Mono.just(
|
||||
new RpcReader.Result(
|
||||
Global.objectMapper.writeValueAsBytes([json]), null, 1, resolver
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
when:
|
||||
def act = reader.logsByHashReader.read(BlockId.from(hash1))
|
||||
then:
|
||||
StepVerifier.create(act)
|
||||
.expectNextMatches { logs ->
|
||||
logs.data[0].blockHash == BlockHash.from(hash1)
|
||||
}
|
||||
.expectComplete()
|
||||
.verify(Duration.ofSeconds(1))
|
||||
}
|
||||
|
||||
def "Reads tx"() {
|
||||
setup:
|
||||
def json = new TransactionJson().tap {
|
||||
|
||||
@@ -45,27 +45,17 @@ class ConnectBlockUpdatesSpec extends Specification {
|
||||
totalDifficulty = BigInteger.ONE
|
||||
timestamp = Instant.now()
|
||||
parentHash = parent
|
||||
transactions = [
|
||||
new TransactionRefJson(TransactionId.from("0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af")),
|
||||
new TransactionRefJson(TransactionId.from("0x5c241a64e7ce536fdb6b8912091151f18a23dd71cc76a48a4b7d453e339efbe2"))
|
||||
]
|
||||
transactions = []
|
||||
})
|
||||
when:
|
||||
def act = connectBlockUpdates.extractUpdates(block)
|
||||
.collectList().block(Duration.ofSeconds(3))
|
||||
|
||||
then:
|
||||
act.size() == 2
|
||||
act.size() == 1
|
||||
with(act[0]) {
|
||||
it.blockNumber == 13412871
|
||||
it.blockHash == BlockId.from("0xe5be2159b2b7daf6b126babdcbaa349da668b92d6b8c7db1350fd527fec4885c")
|
||||
it.transactionId == TxId.from("0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af")
|
||||
it.type == ConnectBlockUpdates.UpdateType.NEW
|
||||
}
|
||||
with(act[1]) {
|
||||
it.blockNumber == 13412871
|
||||
it.blockHash == BlockId.from("0xe5be2159b2b7daf6b126babdcbaa349da668b92d6b8c7db1350fd527fec4885c")
|
||||
it.transactionId == TxId.from("0x5c241a64e7ce536fdb6b8912091151f18a23dd71cc76a48a4b7d453e339efbe2")
|
||||
it.type == ConnectBlockUpdates.UpdateType.NEW
|
||||
}
|
||||
}
|
||||
@@ -79,27 +69,17 @@ class ConnectBlockUpdatesSpec extends Specification {
|
||||
totalDifficulty = BigInteger.ONE
|
||||
timestamp = Instant.now()
|
||||
parentHash = parent
|
||||
transactions = [
|
||||
new TransactionRefJson(TransactionId.from("0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af")),
|
||||
new TransactionRefJson(TransactionId.from("0x5c241a64e7ce536fdb6b8912091151f18a23dd71cc76a48a4b7d453e339efbe2"))
|
||||
]
|
||||
transactions = []
|
||||
})
|
||||
when:
|
||||
def act = connectBlockUpdates.whenReplaced(block, "ConnectBlockUpdatesSpec")
|
||||
.collectList().block(Duration.ofSeconds(3))
|
||||
|
||||
then:
|
||||
act.size() == 2
|
||||
act.size() == 1
|
||||
with(act[0]) {
|
||||
it.blockNumber == 13412871
|
||||
it.blockHash == BlockId.from("0xe5be2159b2b7daf6b126babdcbaa349da668b92d6b8c7db1350fd527fec4885c")
|
||||
it.transactionId == TxId.from("0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af")
|
||||
it.type == ConnectBlockUpdates.UpdateType.DROP
|
||||
}
|
||||
with(act[1]) {
|
||||
it.blockNumber == 13412871
|
||||
it.blockHash == BlockId.from("0xe5be2159b2b7daf6b126babdcbaa349da668b92d6b8c7db1350fd527fec4885c")
|
||||
it.transactionId == TxId.from("0x5c241a64e7ce536fdb6b8912091151f18a23dd71cc76a48a4b7d453e339efbe2")
|
||||
it.type == ConnectBlockUpdates.UpdateType.DROP
|
||||
}
|
||||
}
|
||||
@@ -113,10 +93,7 @@ class ConnectBlockUpdatesSpec extends Specification {
|
||||
totalDifficulty = BigInteger.ONE
|
||||
timestamp = Instant.now()
|
||||
parentHash = parent
|
||||
transactions = [
|
||||
new TransactionRefJson(TransactionId.from("0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af")),
|
||||
new TransactionRefJson(TransactionId.from("0x5c241a64e7ce536fdb6b8912091151f18a23dd71cc76a48a4b7d453e339efbe2"))
|
||||
]
|
||||
transactions = []
|
||||
})
|
||||
def block2 = BlockContainer.from(new BlockJson<TransactionRefJson>().tap {
|
||||
hash = BlockHash.from("0x668b92d6b8c7db1350fd527fec4885ce5be2159b2b7daf6b126babdcbaa349da")
|
||||
@@ -124,10 +101,7 @@ class ConnectBlockUpdatesSpec extends Specification {
|
||||
totalDifficulty = BigInteger.ONE
|
||||
timestamp = Instant.now()
|
||||
parentHash = parent
|
||||
transactions = [
|
||||
new TransactionRefJson(TransactionId.from("0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af")),
|
||||
new TransactionRefJson(TransactionId.from("0x5c241a64e7ce536fdb6b8912091151f18a23dd71cc76a48a4b7d453e339efbe2"))
|
||||
]
|
||||
transactions = []
|
||||
})
|
||||
def block3 = BlockContainer.from(new BlockJson<TransactionRefJson>().tap {
|
||||
hash = BlockHash.from("0xdb1350fd527fec4885ce5be2159b2b7daf6b126babdcbaa349da668b92d6b8c7")
|
||||
@@ -135,10 +109,7 @@ class ConnectBlockUpdatesSpec extends Specification {
|
||||
totalDifficulty = BigInteger.ONE
|
||||
parentHash = parent
|
||||
timestamp = Instant.now()
|
||||
transactions = [
|
||||
new TransactionRefJson(TransactionId.from("0x9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af6c88df9d65ccc")),
|
||||
new TransactionRefJson(TransactionId.from("0xdb6b8912091151f18a23dd71cc76a48a4b7d453e339efbe25c241a64e7ce536f"))
|
||||
]
|
||||
transactions = []
|
||||
})
|
||||
|
||||
when:
|
||||
@@ -177,10 +148,7 @@ class ConnectBlockUpdatesSpec extends Specification {
|
||||
totalDifficulty = BigInteger.ONE
|
||||
timestamp = Instant.now()
|
||||
parentHash = parent
|
||||
transactions = [
|
||||
new TransactionRefJson(TransactionId.from("0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af")),
|
||||
new TransactionRefJson(TransactionId.from("0x5c241a64e7ce536fdb6b8912091151f18a23dd71cc76a48a4b7d453e339efbe2"))
|
||||
]
|
||||
transactions = []
|
||||
})
|
||||
def block2 = BlockContainer.from(new BlockJson<TransactionRefJson>().tap {
|
||||
hash = BlockHash.from("0x668b92d6b8c7db1350fd527fec4885ce5be2159b2b7daf6b126babdcbaa349da")
|
||||
@@ -188,10 +156,7 @@ class ConnectBlockUpdatesSpec extends Specification {
|
||||
totalDifficulty = BigInteger.ONE
|
||||
timestamp = Instant.now()
|
||||
parentHash = parent
|
||||
transactions = [
|
||||
new TransactionRefJson(TransactionId.from("0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af")),
|
||||
new TransactionRefJson(TransactionId.from("0x5c241a64e7ce536fdb6b8912091151f18a23dd71cc76a48a4b7d453e339efbe2"))
|
||||
]
|
||||
transactions = []
|
||||
})
|
||||
|
||||
when:
|
||||
@@ -200,29 +165,15 @@ class ConnectBlockUpdatesSpec extends Specification {
|
||||
.collectList().block(Duration.ofSeconds(1))
|
||||
|
||||
then:
|
||||
act.size() == 4
|
||||
act.size() == 2
|
||||
with(act[0]) {
|
||||
it.blockNumber == 13412871
|
||||
it.blockHash == BlockId.from("0xe5be2159b2b7daf6b126babdcbaa349da668b92d6b8c7db1350fd527fec4885c")
|
||||
it.transactionId == TxId.from("0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af")
|
||||
it.type == ConnectBlockUpdates.UpdateType.DROP
|
||||
}
|
||||
with(act[1]) {
|
||||
it.blockNumber == 13412871
|
||||
it.blockHash == BlockId.from("0xe5be2159b2b7daf6b126babdcbaa349da668b92d6b8c7db1350fd527fec4885c")
|
||||
it.transactionId == TxId.from("0x5c241a64e7ce536fdb6b8912091151f18a23dd71cc76a48a4b7d453e339efbe2")
|
||||
it.type == ConnectBlockUpdates.UpdateType.DROP
|
||||
}
|
||||
with(act[2]) {
|
||||
it.blockNumber == 13412871
|
||||
it.blockHash == BlockId.from("0x668b92d6b8c7db1350fd527fec4885ce5be2159b2b7daf6b126babdcbaa349da")
|
||||
it.transactionId == TxId.from("0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af")
|
||||
it.type == ConnectBlockUpdates.UpdateType.NEW
|
||||
}
|
||||
with(act[3]) {
|
||||
it.blockNumber == 13412871
|
||||
it.blockHash == BlockId.from("0x668b92d6b8c7db1350fd527fec4885ce5be2159b2b7daf6b126babdcbaa349da")
|
||||
it.transactionId == TxId.from("0x5c241a64e7ce536fdb6b8912091151f18a23dd71cc76a48a4b7d453e339efbe2")
|
||||
it.type == ConnectBlockUpdates.UpdateType.NEW
|
||||
}
|
||||
}
|
||||
@@ -233,7 +184,7 @@ class ConnectBlockUpdatesSpec extends Specification {
|
||||
1 * getFlux() >> Flux.never()
|
||||
}
|
||||
def up = Mock(GenericMultistream) {
|
||||
1 * getEnrichedHead(Selector.empty) >> head
|
||||
1 * getHead(Selector.empty) >> head
|
||||
}
|
||||
def connectBlockUpdates = new ConnectBlockUpdates(up, Schedulers.boundedElastic())
|
||||
|
||||
|
||||
@@ -20,6 +20,11 @@ import io.emeraldpay.dshackle.data.BlockId
|
||||
import io.emeraldpay.dshackle.data.TxId
|
||||
import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumDirectReader
|
||||
import io.emeraldpay.etherjar.domain.Address
|
||||
import io.emeraldpay.etherjar.domain.BlockHash
|
||||
import io.emeraldpay.etherjar.domain.TransactionId
|
||||
import io.emeraldpay.etherjar.hex.HexData
|
||||
import io.emeraldpay.etherjar.rpc.json.TransactionLogJson
|
||||
import reactor.core.publisher.Mono
|
||||
import spock.lang.Specification
|
||||
|
||||
@@ -27,28 +32,28 @@ import java.time.Duration
|
||||
|
||||
class ProduceLogsSpec extends Specification {
|
||||
|
||||
def logs = [new TransactionLogJson().tap {
|
||||
blockHash = BlockHash.from("0x668b92d6b8c7db1350fd527fec4885ce5be2159b2b7daf6b126babdcbaa349da")
|
||||
address = Address.from("0xe0aadb0a012dbcdc529c4c743d3e0385a0b54d3d")
|
||||
blockNumber = 1
|
||||
logIndex = 1
|
||||
data = HexData.empty()
|
||||
transactionIndex = 1
|
||||
topics = []
|
||||
transactionHash = TransactionId.from("0xb5e554178a94fd993111f2ae64cb708cb0899d7b5182024e70d5c468164a8bec")
|
||||
}]
|
||||
|
||||
def "Produce added as nothing with no logs"() {
|
||||
setup:
|
||||
String receipt = '{\n' +
|
||||
' "blockHash": "0x668b92d6b8c7db1350fd527fec4885ce5be2159b2b7daf6b126babdcbaa349da",\n' +
|
||||
' "blockNumber": "0x1",\n' +
|
||||
' "from": "0x5e78dd1e81ecdf078e029117eca98eaa71f46bdb",\n' +
|
||||
' "logs": [\n' +
|
||||
' ],\n' +
|
||||
' "transactionHash": "0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af",\n' +
|
||||
' "transactionIndex": "0x0"\n' +
|
||||
' }'
|
||||
|
||||
def receipts = Mock(Reader) {
|
||||
1 * it.read(TxId.from("0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af")) >>
|
||||
Mono.just(new EthereumDirectReader.Result<>(receipt.getBytes(), null))
|
||||
def logs = Mock(Reader) {
|
||||
1 * it.read(BlockId.from("0x668b92d6b8c7db1350fd527fec4885ce5be2159b2b7daf6b126babdcbaa349da")) >>
|
||||
Mono.just(new EthereumDirectReader.Result<>([], null))
|
||||
}
|
||||
def producer = new ProduceLogs(receipts, Chain.ETHEREUM__MAINNET)
|
||||
def producer = new ProduceLogs(logs, Chain.ETHEREUM__MAINNET)
|
||||
def update = new ConnectBlockUpdates.Update(
|
||||
BlockId.from("0x668b92d6b8c7db1350fd527fec4885ce5be2159b2b7daf6b126babdcbaa349da"),
|
||||
13412871,
|
||||
1,
|
||||
ConnectBlockUpdates.UpdateType.NEW,
|
||||
TxId.from("0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af"),
|
||||
"upstream"
|
||||
)
|
||||
when:
|
||||
@@ -59,67 +64,18 @@ class ProduceLogsSpec extends Specification {
|
||||
act.size() == 0
|
||||
}
|
||||
|
||||
def "Produce added as nothing with null receipt"() {
|
||||
def "Produce added with logs"() {
|
||||
setup:
|
||||
String receipt = 'null'
|
||||
|
||||
def receipts = Mock(Reader) {
|
||||
1 * it.read(TxId.from("0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af")) >>
|
||||
Mono.just(new EthereumDirectReader.Result<>(receipt.getBytes(), null))
|
||||
def logs = Mock(Reader) {
|
||||
1 * it.read(BlockId.from("0x668b92d6b8c7db1350fd527fec4885ce5be2159b2b7daf6b126babdcbaa349da")) >>
|
||||
Mono.just(new EthereumDirectReader.Result<>(logs, null))
|
||||
}
|
||||
def producer = new ProduceLogs(receipts, Chain.ETHEREUM__MAINNET)
|
||||
def producer = new ProduceLogs(logs, Chain.ETHEREUM__MAINNET)
|
||||
def update = new ConnectBlockUpdates.Update(
|
||||
BlockId.from("0x668b92d6b8c7db1350fd527fec4885ce5be2159b2b7daf6b126babdcbaa349da"),
|
||||
13412871,
|
||||
1,
|
||||
ConnectBlockUpdates.UpdateType.NEW,
|
||||
TxId.from("0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af"),
|
||||
"upstream"
|
||||
)
|
||||
when:
|
||||
def act = producer.produceAdded(update)
|
||||
.collectList().block(Duration.ofSeconds(1))
|
||||
|
||||
then:
|
||||
act.size() == 0
|
||||
}
|
||||
|
||||
def "Produce added with single log"() {
|
||||
setup:
|
||||
String receipt = '{\n' +
|
||||
' "blockHash": "0x668b92d6b8c7db1350fd527fec4885ce5be2159b2b7daf6b126babdcbaa349da",\n' +
|
||||
' "blockNumber": "0x1",\n' +
|
||||
' "from": "0x5e78dd1e81ecdf078e029117eca98eaa71f46bdb",\n' +
|
||||
' "logs": [\n' +
|
||||
' {\n' +
|
||||
' "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",\n' +
|
||||
' "topics": [\n' +
|
||||
' "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",\n' +
|
||||
' "0x0000000000000000000000005e78dd1e81ecdf078e029117eca98eaa71f46bdb",\n' +
|
||||
' "0x00000000000000000000000099897cb0e667d354b920fc38a40a5100b2a01566"\n' +
|
||||
' ],\n' +
|
||||
' "data": "0x00000000000000000000000000000000000000000000000000000007505d91f0",\n' +
|
||||
' "blockNumber": "0xc7f3b4",\n' +
|
||||
' "transactionHash": "0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af",\n' +
|
||||
' "transactionIndex": "0x0",\n' +
|
||||
' "blockHash": "0x668b92d6b8c7db1350fd527fec4885ce5be2159b2b7daf6b126babdcbaa349da",\n' +
|
||||
' "logIndex": "0x0",\n' +
|
||||
' "removed": false\n' +
|
||||
' }' +
|
||||
' ],\n' +
|
||||
' "transactionHash": "0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af",\n' +
|
||||
' "transactionIndex": "0x0"\n' +
|
||||
' }'
|
||||
|
||||
def receipts = Mock(Reader) {
|
||||
1 * it.read(TxId.from("0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af")) >>
|
||||
Mono.just(new EthereumDirectReader.Result<>(receipt.getBytes(), null))
|
||||
}
|
||||
def producer = new ProduceLogs(receipts, Chain.ETHEREUM__MAINNET)
|
||||
def update = new ConnectBlockUpdates.Update(
|
||||
BlockId.from("0x668b92d6b8c7db1350fd527fec4885ce5be2159b2b7daf6b126babdcbaa349da"),
|
||||
13412871,
|
||||
ConnectBlockUpdates.UpdateType.NEW,
|
||||
TxId.from("0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af"),
|
||||
"upstream"
|
||||
)
|
||||
when:
|
||||
@@ -128,244 +84,27 @@ class ProduceLogsSpec extends Specification {
|
||||
|
||||
then:
|
||||
act.size() == 1
|
||||
with(act[0]) {
|
||||
it.transactionHash.toHex() == "0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af"
|
||||
}
|
||||
}
|
||||
|
||||
def "Produce added with no data"() {
|
||||
setup:
|
||||
String receipt = '{\n' +
|
||||
' "blockHash": "0x668b92d6b8c7db1350fd527fec4885ce5be2159b2b7daf6b126babdcbaa349da",\n' +
|
||||
' "blockNumber": "0x1",\n' +
|
||||
' "from": "0x5e78dd1e81ecdf078e029117eca98eaa71f46bdb",\n' +
|
||||
' "logs": [\n' +
|
||||
' {\n' +
|
||||
' "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",\n' +
|
||||
' "topics": [\n' +
|
||||
' "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"\n' +
|
||||
' ],\n' +
|
||||
' "blockNumber": "0xc7f3b4",\n' +
|
||||
' "transactionHash": "0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af",\n' +
|
||||
' "transactionIndex": "0x0",\n' +
|
||||
' "blockHash": "0x668b92d6b8c7db1350fd527fec4885ce5be2159b2b7daf6b126babdcbaa349da",\n' +
|
||||
' "logIndex": "0x0",\n' +
|
||||
' "removed": false\n' +
|
||||
' }' +
|
||||
' ],\n' +
|
||||
' "transactionHash": "0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af",\n' +
|
||||
' "transactionIndex": "0x0"\n' +
|
||||
' }'
|
||||
|
||||
def receipts = Mock(Reader) {
|
||||
1 * it.read(TxId.from("0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af")) >>
|
||||
Mono.just(new EthereumDirectReader.Result<>(receipt.getBytes(), null))
|
||||
}
|
||||
def producer = new ProduceLogs(receipts, Chain.ETHEREUM__MAINNET)
|
||||
def update = new ConnectBlockUpdates.Update(
|
||||
BlockId.from("0x668b92d6b8c7db1350fd527fec4885ce5be2159b2b7daf6b126babdcbaa349da"),
|
||||
13412871,
|
||||
ConnectBlockUpdates.UpdateType.NEW,
|
||||
TxId.from("0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af"),
|
||||
"upstream"
|
||||
)
|
||||
when:
|
||||
def act = producer.produceAdded(update)
|
||||
.collectList().block(Duration.ofSeconds(1))
|
||||
|
||||
then:
|
||||
act.size() == 1
|
||||
with(act[0]) {
|
||||
it.transactionHash.toHex() == "0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af"
|
||||
// Geth actually renders it as null, so this check may be wrong
|
||||
it.data != null && it.data.size == 0
|
||||
}
|
||||
}
|
||||
|
||||
def "Produce added with multiple logs"() {
|
||||
setup:
|
||||
String receipt = '{\n' +
|
||||
' "blockHash": "0x668b92d6b8c7db1350fd527fec4885ce5be2159b2b7daf6b126babdcbaa349da",\n' +
|
||||
' "blockNumber": "0x1",\n' +
|
||||
' "from": "0x5e78dd1e81ecdf078e029117eca98eaa71f46bdb",\n' +
|
||||
' "logs": [\n' +
|
||||
' {\n' +
|
||||
' "address": "0x298d492e8c1d909d3f63bc4a36c66c64acb3d695",\n' +
|
||||
' "topics": [\n' +
|
||||
' "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",\n' +
|
||||
' "0x0000000000000000000000005c6006105b1b777a13d58d96393ad9e556882025",\n' +
|
||||
' "0x00000000000000000000000075b8c48bdb04d426aed57b36bb835ad2dc321c30"\n' +
|
||||
' ],\n' +
|
||||
' "data": "0x0000000000000000000000000000000000000000000000013e7ec767db370000",\n' +
|
||||
' "blockNumber": "0xccc493",\n' +
|
||||
' "transactionHash": "0xb5e554178a94fd993111f2ae64cb708cb0899d7b5182024e70d5c468164a8bec",\n' +
|
||||
' "transactionIndex": "0x57",\n' +
|
||||
' "blockHash": "0x7e2661ac0e2f34dd2d6f449eea45aeec8470a0948af9daa33e684226640d819c",\n' +
|
||||
' "logIndex": "0xb4",\n' +
|
||||
' "removed": false\n' +
|
||||
' },\n' +
|
||||
' {\n' +
|
||||
' "address": "0x298d492e8c1d909d3f63bc4a36c66c64acb3d695",\n' +
|
||||
' "topics": [\n' +
|
||||
' "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",\n' +
|
||||
' "0x0000000000000000000000005c6006105b1b777a13d58d96393ad9e556882025",\n' +
|
||||
' "0x0000000000000000000000000000000000000000000000000000000000000000"\n' +
|
||||
' ],\n' +
|
||||
' "data": "0x00000000000000000000000000000000000000000000000023636b7d513f0000",\n' +
|
||||
' "blockNumber": "0xccc493",\n' +
|
||||
' "transactionHash": "0xb5e554178a94fd993111f2ae64cb708cb0899d7b5182024e70d5c468164a8bec",\n' +
|
||||
' "transactionIndex": "0x57",\n' +
|
||||
' "blockHash": "0x7e2661ac0e2f34dd2d6f449eea45aeec8470a0948af9daa33e684226640d819c",\n' +
|
||||
' "logIndex": "0xb5",\n' +
|
||||
' "removed": false\n' +
|
||||
' },\n' +
|
||||
' {\n' +
|
||||
' "address": "0x298d492e8c1d909d3f63bc4a36c66c64acb3d695",\n' +
|
||||
' "topics": [\n' +
|
||||
' "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",\n' +
|
||||
' "0x0000000000000000000000005c6006105b1b777a13d58d96393ad9e556882025",\n' +
|
||||
' "0x0000000000000000000000001b46b72c5280f30fbe8a958b4f3c348fd0fd2e55"\n' +
|
||||
' ],\n' +
|
||||
' "data": "0x00000000000000000000000000000000000000000000011316d590258fba0000",\n' +
|
||||
' "blockNumber": "0xccc493",\n' +
|
||||
' "transactionHash": "0xb5e554178a94fd993111f2ae64cb708cb0899d7b5182024e70d5c468164a8bec",\n' +
|
||||
' "transactionIndex": "0x57",\n' +
|
||||
' "blockHash": "0x7e2661ac0e2f34dd2d6f449eea45aeec8470a0948af9daa33e684226640d819c",\n' +
|
||||
' "logIndex": "0xb6",\n' +
|
||||
' "removed": false\n' +
|
||||
' },\n' +
|
||||
' {\n' +
|
||||
' "address": "0x298d492e8c1d909d3f63bc4a36c66c64acb3d695",\n' +
|
||||
' "topics": [\n' +
|
||||
' "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925",\n' +
|
||||
' "0x0000000000000000000000005c6006105b1b777a13d58d96393ad9e556882025",\n' +
|
||||
' "0x0000000000000000000000001b46b72c5280f30fbe8a958b4f3c348fd0fd2e55"\n' +
|
||||
' ],\n' +
|
||||
' "data": "0x0000000000000000000000000000000000000000000014188a101e403a500000",\n' +
|
||||
' "blockNumber": "0xccc493",\n' +
|
||||
' "transactionHash": "0xb5e554178a94fd993111f2ae64cb708cb0899d7b5182024e70d5c468164a8bec",\n' +
|
||||
' "transactionIndex": "0x57",\n' +
|
||||
' "blockHash": "0x7e2661ac0e2f34dd2d6f449eea45aeec8470a0948af9daa33e684226640d819c",\n' +
|
||||
' "logIndex": "0xb7",\n' +
|
||||
' "removed": false\n' +
|
||||
' },\n' +
|
||||
' {\n' +
|
||||
' "address": "0x1b46b72c5280f30fbe8a958b4f3c348fd0fd2e55",\n' +
|
||||
' "topics": [\n' +
|
||||
' "0x90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a15",\n' +
|
||||
' "0x0000000000000000000000005c6006105b1b777a13d58d96393ad9e556882025",\n' +
|
||||
' "0x0000000000000000000000000000000000000000000000000000000000000000"\n' +
|
||||
' ],\n' +
|
||||
' "data": "0x00000000000000000000000000000000000000000000011478b7c30abc300000",\n' +
|
||||
' "blockNumber": "0xccc493",\n' +
|
||||
' "transactionHash": "0xb5e554178a94fd993111f2ae64cb708cb0899d7b5182024e70d5c468164a8bec",\n' +
|
||||
' "transactionIndex": "0x57",\n' +
|
||||
' "blockHash": "0x7e2661ac0e2f34dd2d6f449eea45aeec8470a0948af9daa33e684226640d819c",\n' +
|
||||
' "logIndex": "0xb8",\n' +
|
||||
' "removed": false\n' +
|
||||
' }' +
|
||||
' ],\n' +
|
||||
' "transactionHash": "0xb5e554178a94fd993111f2ae64cb708cb0899d7b5182024e70d5c468164a8bec",\n' +
|
||||
' "transactionIndex": "0x57"\n' +
|
||||
' }'
|
||||
|
||||
def receipts = Mock(Reader) {
|
||||
1 * it.read(TxId.from("0xb5e554178a94fd993111f2ae64cb708cb0899d7b5182024e70d5c468164a8bec")) >>
|
||||
Mono.just(new EthereumDirectReader.Result<>(receipt.getBytes(), null))
|
||||
}
|
||||
def producer = new ProduceLogs(receipts, Chain.ETHEREUM__MAINNET)
|
||||
def update = new ConnectBlockUpdates.Update(
|
||||
BlockId.from("0x668b92d6b8c7db1350fd527fec4885ce5be2159b2b7daf6b126babdcbaa349da"),
|
||||
13412871,
|
||||
ConnectBlockUpdates.UpdateType.NEW,
|
||||
TxId.from("0xb5e554178a94fd993111f2ae64cb708cb0899d7b5182024e70d5c468164a8bec"),
|
||||
"upstream"
|
||||
)
|
||||
when:
|
||||
def act = producer.produceAdded(update)
|
||||
.collectList().block(Duration.ofSeconds(1))
|
||||
|
||||
then:
|
||||
act.size() == 5
|
||||
act*.transactionHash.every { it.toHex() == "0xb5e554178a94fd993111f2ae64cb708cb0899d7b5182024e70d5c468164a8bec" }
|
||||
act*.logIndex == [180, 181, 182, 183, 184]
|
||||
act*.address.every { it.toHex() == "0xe0aadb0a012dbcdc529c4c743d3e0385a0b54d3d" }
|
||||
act*.removed.every { !it }
|
||||
}
|
||||
|
||||
def "Produce removed"() {
|
||||
setup:
|
||||
String receipt = '{\n' +
|
||||
' "blockHash": "0x668b92d6b8c7db1350fd527fec4885ce5be2159b2b7daf6b126babdcbaa349da",\n' +
|
||||
' "blockNumber": "0x1",\n' +
|
||||
' "from": "0x5e78dd1e81ecdf078e029117eca98eaa71f46bdb",\n' +
|
||||
' "logs": [\n' +
|
||||
' {\n' +
|
||||
' "address": "0x298d492e8c1d909d3f63bc4a36c66c64acb3d695",\n' +
|
||||
' "topics": [\n' +
|
||||
' "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",\n' +
|
||||
' "0x0000000000000000000000005c6006105b1b777a13d58d96393ad9e556882025",\n' +
|
||||
' "0x00000000000000000000000075b8c48bdb04d426aed57b36bb835ad2dc321c30"\n' +
|
||||
' ],\n' +
|
||||
' "data": "0x0000000000000000000000000000000000000000000000013e7ec767db370000",\n' +
|
||||
' "blockNumber": "0xccc493",\n' +
|
||||
' "transactionHash": "0xb5e554178a94fd993111f2ae64cb708cb0899d7b5182024e70d5c468164a8bec",\n' +
|
||||
' "transactionIndex": "0x57",\n' +
|
||||
' "blockHash": "0x7e2661ac0e2f34dd2d6f449eea45aeec8470a0948af9daa33e684226640d819c",\n' +
|
||||
' "logIndex": "0xb4",\n' +
|
||||
' "removed": false\n' +
|
||||
' },\n' +
|
||||
' {\n' +
|
||||
' "address": "0x298d492e8c1d909d3f63bc4a36c66c64acb3d695",\n' +
|
||||
' "topics": [\n' +
|
||||
' "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",\n' +
|
||||
' "0x0000000000000000000000005c6006105b1b777a13d58d96393ad9e556882025",\n' +
|
||||
' "0x0000000000000000000000000000000000000000000000000000000000000000"\n' +
|
||||
' ],\n' +
|
||||
' "data": "0x00000000000000000000000000000000000000000000000023636b7d513f0000",\n' +
|
||||
' "blockNumber": "0xccc493",\n' +
|
||||
' "transactionHash": "0xb5e554178a94fd993111f2ae64cb708cb0899d7b5182024e70d5c468164a8bec",\n' +
|
||||
' "transactionIndex": "0x57",\n' +
|
||||
' "blockHash": "0x7e2661ac0e2f34dd2d6f449eea45aeec8470a0948af9daa33e684226640d819c",\n' +
|
||||
' "logIndex": "0xb5",\n' +
|
||||
' "removed": false\n' +
|
||||
' },\n' +
|
||||
' {\n' +
|
||||
' "address": "0x298d492e8c1d909d3f63bc4a36c66c64acb3d695",\n' +
|
||||
' "topics": [\n' +
|
||||
' "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",\n' +
|
||||
' "0x0000000000000000000000005c6006105b1b777a13d58d96393ad9e556882025",\n' +
|
||||
' "0x0000000000000000000000001b46b72c5280f30fbe8a958b4f3c348fd0fd2e55"\n' +
|
||||
' ],\n' +
|
||||
' "data": "0x00000000000000000000000000000000000000000000011316d590258fba0000",\n' +
|
||||
' "blockNumber": "0xccc493",\n' +
|
||||
' "transactionHash": "0xb5e554178a94fd993111f2ae64cb708cb0899d7b5182024e70d5c468164a8bec",\n' +
|
||||
' "transactionIndex": "0x57",\n' +
|
||||
' "blockHash": "0x7e2661ac0e2f34dd2d6f449eea45aeec8470a0948af9daa33e684226640d819c",\n' +
|
||||
' "logIndex": "0xb6",\n' +
|
||||
' "removed": false\n' +
|
||||
' }\n' +
|
||||
' ],\n' +
|
||||
' "transactionHash": "0xb5e554178a94fd993111f2ae64cb708cb0899d7b5182024e70d5c468164a8bec",\n' +
|
||||
' "transactionIndex": "0x57"\n' +
|
||||
' }'
|
||||
|
||||
def receipts = Mock(Reader) {
|
||||
1 * it.read(TxId.from("0xb5e554178a94fd993111f2ae64cb708cb0899d7b5182024e70d5c468164a8bec")) >>
|
||||
Mono.just(new EthereumDirectReader.Result<>(receipt.getBytes(), null))
|
||||
def logs = Mock(Reader) {
|
||||
1 * it.read(BlockId.from("0x668b92d6b8c7db1350fd527fec4885ce5be2159b2b7daf6b126babdcbaa349da")) >>
|
||||
Mono.just(new EthereumDirectReader.Result<>(logs, null))
|
||||
}
|
||||
def producer = new ProduceLogs(receipts, Chain.ETHEREUM__MAINNET)
|
||||
def producer = new ProduceLogs(logs, Chain.ETHEREUM__MAINNET)
|
||||
def update1 = new ConnectBlockUpdates.Update(
|
||||
BlockId.from("0x668b92d6b8c7db1350fd527fec4885ce5be2159b2b7daf6b126babdcbaa349da"),
|
||||
13412871,
|
||||
ConnectBlockUpdates.UpdateType.NEW,
|
||||
TxId.from("0xb5e554178a94fd993111f2ae64cb708cb0899d7b5182024e70d5c468164a8bec"),
|
||||
"upstream"
|
||||
)
|
||||
def update2 = new ConnectBlockUpdates.Update(
|
||||
BlockId.from("0x668b92d6b8c7db1350fd527fec4885ce5be2159b2b7daf6b126babdcbaa349da"),
|
||||
13412871,
|
||||
ConnectBlockUpdates.UpdateType.DROP,
|
||||
TxId.from("0xb5e554178a94fd993111f2ae64cb708cb0899d7b5182024e70d5c468164a8bec"),
|
||||
"upstream"
|
||||
)
|
||||
when:
|
||||
@@ -376,9 +115,9 @@ class ProduceLogsSpec extends Specification {
|
||||
.collectList().block(Duration.ofSeconds(1))
|
||||
|
||||
then:
|
||||
act.size() == 3
|
||||
act.size() == 1
|
||||
act*.transactionHash.every { it.toHex() == "0xb5e554178a94fd993111f2ae64cb708cb0899d7b5182024e70d5c468164a8bec" }
|
||||
act*.logIndex == [180, 181, 182]
|
||||
act*.logIndex == [1]
|
||||
act*.removed.every { it }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user