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 transactions = Flux.fromIterable(block.transactions)
.flatMap { txes.read(it) }
.flatMapSequential { txes.read(it) }
.collectList()
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.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()

View File

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

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()
}
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) {

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)
}
}