From b40b208130468a75047ffb9652122c6429d83583 Mon Sep 17 00:00:00 2001 From: Igor Artamonov Date: Sat, 27 Mar 2021 18:49:24 -0400 Subject: [PATCH] problem: full block returns transactions in different order fix: #82 --- .../ethereum/EthereumFullBlocksReader.kt | 2 +- .../EthereumFullBlocksReaderSpec.groovy | 46 +++++++++++++++++++ testing/dshackle/README.adoc | 9 +++- .../{dshackle.yaml => dshackle-mock.yaml} | 0 testing/dshackle/dshackle-real.yaml | 29 ++++++++++++ .../dshackle/testing/trial/ProxyClient.groovy | 14 +++++- .../trial/proxy/GetBlockRealSpec.groovy | 38 +++++++++++++++ 7 files changed, 135 insertions(+), 3 deletions(-) rename testing/dshackle/{dshackle.yaml => dshackle-mock.yaml} (100%) create mode 100644 testing/dshackle/dshackle-real.yaml create mode 100644 testing/trial/src/test/groovy/io/emeraldpay/dshackle/testing/trial/proxy/GetBlockRealSpec.groovy diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/EthereumFullBlocksReader.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/EthereumFullBlocksReader.kt index 6d3815a62..97843fb4c 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/EthereumFullBlocksReader.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/EthereumFullBlocksReader.kt @@ -70,7 +70,7 @@ class EthereumFullBlocksReader( val blockSplit = splitByTransactions(block.json!!) val transactions = Flux.fromIterable(block.transactions) - .flatMap { txes.read(it) } + .flatMapSequential { txes.read(it) } .collectList() return@flatMap transactions.flatMap { transactionsData -> diff --git a/src/test/groovy/io/emeraldpay/dshackle/upstream/ethereum/EthereumFullBlocksReaderSpec.groovy b/src/test/groovy/io/emeraldpay/dshackle/upstream/ethereum/EthereumFullBlocksReaderSpec.groovy index 34b596a22..45a93cfea 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/upstream/ethereum/EthereumFullBlocksReaderSpec.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/upstream/ethereum/EthereumFullBlocksReaderSpec.groovy @@ -23,6 +23,7 @@ import io.emeraldpay.dshackle.cache.TxMemCache import io.emeraldpay.dshackle.data.BlockContainer import io.emeraldpay.dshackle.data.BlockId import io.emeraldpay.dshackle.data.TxContainer +import io.emeraldpay.dshackle.data.TxId import io.emeraldpay.dshackle.reader.Reader import io.infinitape.etherjar.domain.BlockHash import io.infinitape.etherjar.domain.TransactionId @@ -30,9 +31,11 @@ import io.infinitape.etherjar.rpc.json.BlockJson import io.infinitape.etherjar.rpc.json.TransactionJson import io.infinitape.etherjar.rpc.json.TransactionRefJson import org.apache.commons.codec.binary.Hex +import reactor.core.publisher.Mono import spock.lang.Specification import java.nio.ByteBuffer +import java.time.Duration import java.time.Instant class EthereumFullBlocksReaderSpec extends Specification { @@ -111,6 +114,21 @@ class EthereumFullBlocksReaderSpec extends Specification { it } + // all transaction2 + def block4 = new BlockJson().with { + it.number = 103 + it.hash = BlockHash.from(hash3) + it.totalDifficulty = BigInteger.ONE + it.timestamp = Instant.now() + it.transactions = [ + new TransactionRefJson(tx1.hash), + new TransactionRefJson(tx2.hash), + new TransactionRefJson(tx3.hash), + new TransactionRefJson(tx4.hash) + ] + it + } + def "Read transactions and return full block"() { setup: @@ -178,6 +196,34 @@ class EthereumFullBlocksReaderSpec extends Specification { } } + def "Produce block with original order of transactions"() { + setup: + def txes = Mock(Reader) { + 1 * it.read(TxId.from(tx1.hash)) >> Mono.just(TxContainer.from(tx1)).delayElement(Duration.ofMillis(50)) + 1 * it.read(TxId.from(tx2.hash)) >> Mono.just(TxContainer.from(tx2)).delayElement(Duration.ofMillis(40)) + 1 * it.read(TxId.from(tx3.hash)) >> Mono.just(TxContainer.from(tx3)).delayElement(Duration.ofMillis(30)) + 1 * it.read(TxId.from(tx4.hash)) >> Mono.just(TxContainer.from(tx4)).delayElement(Duration.ofMillis(20)) + } + def blocks = new BlocksMemCache() + blocks.add(BlockContainer.from(block4)) + + def full = new EthereumFullBlocksReader(blocks, txes) + + when: + def act = full.read(BlockId.from(block4.hash)).block() + act = objectMapper.readValue(act.json, BlockJson) + def transactions = act.transactions + + then: + transactions.size() == 4 + transactions[0] instanceof TransactionJson + transactions[1] instanceof TransactionJson + transactions[0].hash == TransactionId.from(hash1) + transactions[1].hash == TransactionId.from(hash2) + transactions[2].hash == TransactionId.from(hash3) + transactions[3].hash == TransactionId.from(hash4) + } + def "Read block without transactions"() { setup: def txes = new TxMemCache() diff --git a/testing/dshackle/README.adoc b/testing/dshackle/README.adoc index b4aca93cb..46dc3bc3a 100644 --- a/testing/dshackle/README.adoc +++ b/testing/dshackle/README.adoc @@ -3,5 +3,12 @@ .Run from project root directory: [source,bash] ---- -./gradlew run --args="--configPath=./testing/dshackle/dshackle.yaml" +./gradlew run --args="--configPath=./testing/dshackle/dshackle-mock.yaml" +---- + +or + +[source,bash] +---- +./gradlew run --args="--configPath=./testing/dshackle/dshackle-real.yaml" ---- diff --git a/testing/dshackle/dshackle.yaml b/testing/dshackle/dshackle-mock.yaml similarity index 100% rename from testing/dshackle/dshackle.yaml rename to testing/dshackle/dshackle-mock.yaml diff --git a/testing/dshackle/dshackle-real.yaml b/testing/dshackle/dshackle-real.yaml new file mode 100644 index 000000000..4860527c5 --- /dev/null +++ b/testing/dshackle/dshackle-real.yaml @@ -0,0 +1,29 @@ +version: v1 +port: 12448 + +tls: + enabled: false + +cluster: + upstreams: + - id: eth-1 + chain: ethereum + connection: + ethereum: + rpc: + url: "${DSHACKLE_TEST_ETH1_RPC}" + ws: + url: "${DSHACKLE_TEST_ETH1_WS}" + origin: "${DSHACKLE_TEST_ETH1_WSORIGIN}" + +cache: + redis: + enabled: false + +proxy: + port: 18081 + tls: + enabled: false + routes: + - id: eth + blockchain: ethereum \ No newline at end of file diff --git a/testing/trial/src/main/groovy/io/emeraldpay/dshackle/testing/trial/ProxyClient.groovy b/testing/trial/src/main/groovy/io/emeraldpay/dshackle/testing/trial/ProxyClient.groovy index 859b9c665..9fdda969e 100644 --- a/testing/trial/src/main/groovy/io/emeraldpay/dshackle/testing/trial/ProxyClient.groovy +++ b/testing/trial/src/main/groovy/io/emeraldpay/dshackle/testing/trial/ProxyClient.groovy @@ -24,8 +24,20 @@ class ProxyClient { this.objectMapper = new ObjectMapper() } + static ProxyClient ethereumMock() { + return forPrefix(18080, "eth") + } + + static ProxyClient ethereumReal() { + return forPrefix(18081, "eth") + } + static ProxyClient forPrefix(String prefix) { - return new ProxyClient("http://127.0.0.1:18080/$prefix") + return forPrefix(18080, prefix) + } + + static ProxyClient forPrefix(int port, String prefix) { + return new ProxyClient("http://127.0.0.1:$port/$prefix") } static ProxyClient forOriginal(int port) { diff --git a/testing/trial/src/test/groovy/io/emeraldpay/dshackle/testing/trial/proxy/GetBlockRealSpec.groovy b/testing/trial/src/test/groovy/io/emeraldpay/dshackle/testing/trial/proxy/GetBlockRealSpec.groovy new file mode 100644 index 000000000..bde184097 --- /dev/null +++ b/testing/trial/src/test/groovy/io/emeraldpay/dshackle/testing/trial/proxy/GetBlockRealSpec.groovy @@ -0,0 +1,38 @@ +package io.emeraldpay.dshackle.testing.trial.proxy + +import io.emeraldpay.dshackle.testing.trial.Debugger +import io.emeraldpay.dshackle.testing.trial.ProxyClient +import spock.lang.Specification +import spock.lang.Timeout + +class GetBlockRealSpec extends Specification { + + def client = ProxyClient.ethereumReal() + + def setup() { + Debugger.enabled = false + } + + def cleanup() { + Debugger.enabled = true + } + + @Timeout(15) + def "Correct order for transactions on #height"() { + expect: + def results = [ + (client.execute("eth_getBlockByNumber", ["0x" + Integer.toString(height, 16), false]).result["transactions"] as List), + (client.execute("eth_getBlockByNumber", ["0x" + Integer.toString(height, 16), true]).result["transactions"] as List>) + .collect { it.hash } + ] + + println(results[0]) + println(results[1]) + + results[0] == results[1] + + where: + height << (10_000_000..10_000_500) + + } +}