problem: full block returns transactions in different order

fix: #82
This commit is contained in:
Igor Artamonov
2021-03-27 18:49:24 -04:00
parent 3ae5203d98
commit 0bbcc728c1
7 changed files with 135 additions and 3 deletions

View File

@@ -70,7 +70,7 @@ class EthereumFullBlocksReader(
val blockSplit = splitByTransactions(block.json!!) val blockSplit = splitByTransactions(block.json!!)
val transactions = Flux.fromIterable(block.transactions) val transactions = Flux.fromIterable(block.transactions)
.flatMap { txes.read(it) } .flatMapSequential { txes.read(it) }
.collectList() .collectList()
return@flatMap transactions.flatMap { transactionsData -> return@flatMap transactions.flatMap { transactionsData ->

View File

@@ -23,6 +23,7 @@ import io.emeraldpay.dshackle.cache.TxMemCache
import io.emeraldpay.dshackle.data.BlockContainer import io.emeraldpay.dshackle.data.BlockContainer
import io.emeraldpay.dshackle.data.BlockId import io.emeraldpay.dshackle.data.BlockId
import io.emeraldpay.dshackle.data.TxContainer import io.emeraldpay.dshackle.data.TxContainer
import io.emeraldpay.dshackle.data.TxId
import io.emeraldpay.dshackle.reader.Reader import io.emeraldpay.dshackle.reader.Reader
import io.infinitape.etherjar.domain.BlockHash import io.infinitape.etherjar.domain.BlockHash
import io.infinitape.etherjar.domain.TransactionId 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.TransactionJson
import io.infinitape.etherjar.rpc.json.TransactionRefJson import io.infinitape.etherjar.rpc.json.TransactionRefJson
import org.apache.commons.codec.binary.Hex import org.apache.commons.codec.binary.Hex
import reactor.core.publisher.Mono
import spock.lang.Specification import spock.lang.Specification
import java.nio.ByteBuffer import java.nio.ByteBuffer
import java.time.Duration
import java.time.Instant import java.time.Instant
class EthereumFullBlocksReaderSpec extends Specification { class EthereumFullBlocksReaderSpec extends Specification {
@@ -111,6 +114,21 @@ class EthereumFullBlocksReaderSpec extends Specification {
it 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"() { def "Read transactions and return full block"() {
setup: 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"() { def "Read block without transactions"() {
setup: setup:
def txes = new TxMemCache() def txes = new TxMemCache()

View File

@@ -3,5 +3,12 @@
.Run from project root directory: .Run from project root directory:
[source,bash] [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"
---- ----

View File

@@ -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

View File

@@ -24,8 +24,20 @@ class ProxyClient {
this.objectMapper = new ObjectMapper() this.objectMapper = new ObjectMapper()
} }
static ProxyClient ethereumMock() {
return forPrefix(18080, "eth")
}
static ProxyClient ethereumReal() {
return forPrefix(18081, "eth")
}
static ProxyClient forPrefix(String prefix) { 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) { static ProxyClient forOriginal(int port) {

View File

@@ -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<String>),
(client.execute("eth_getBlockByNumber", ["0x" + Integer.toString(height, 16), true]).result["transactions"] as List<Map<String, Object>>)
.collect { it.hash }
]
println(results[0])
println(results[1])
results[0] == results[1]
where:
height << (10_000_000..10_000_500)
}
}