Add height matcher for methods by block

This commit is contained in:
Кирилл
2023-02-03 18:12:19 +04:00
parent 3a8d5d536a
commit 0792494d90
6 changed files with 155 additions and 26 deletions

View File

@@ -15,19 +15,25 @@
*/
package io.emeraldpay.dshackle.upstream.calls
import io.emeraldpay.dshackle.cache.BlocksMemCache
import io.emeraldpay.dshackle.cache.Caches
import io.emeraldpay.dshackle.data.BlockContainer
import io.emeraldpay.dshackle.data.BlockId
import io.emeraldpay.dshackle.reader.Reader
import io.emeraldpay.dshackle.upstream.Head
import io.emeraldpay.dshackle.upstream.Selector
import reactor.core.publisher.Mono
import reactor.test.StepVerifier
import spock.lang.Specification
import java.time.Duration
import java.time.Instant
class EthereumCallSelectorSpec extends Specification {
def "Get height matcher for latest balance"() {
setup:
EthereumCallSelector callSelector = new EthereumCallSelector(Stub(Reader))
EthereumCallSelector callSelector = new EthereumCallSelector(Stub(Reader), Stub(Caches))
def head = Mock(Head) {
1 * getCurrentHeight() >> 100
}
@@ -39,7 +45,7 @@ class EthereumCallSelectorSpec extends Specification {
def "Get height matcher for latest call"() {
setup:
EthereumCallSelector callSelector = new EthereumCallSelector(Stub(Reader))
EthereumCallSelector callSelector = new EthereumCallSelector(Stub(Reader), Stub(Caches))
def head = Mock(Head) {
1 * getCurrentHeight() >> 100
}
@@ -51,7 +57,7 @@ class EthereumCallSelectorSpec extends Specification {
def "Get height matcher for latest storageAt"() {
setup:
EthereumCallSelector callSelector = new EthereumCallSelector(Stub(Reader))
EthereumCallSelector callSelector = new EthereumCallSelector(Stub(Reader), Stub(Caches))
def head = Mock(Head) {
1 * getCurrentHeight() >> 100
}
@@ -63,7 +69,7 @@ class EthereumCallSelectorSpec extends Specification {
def "Get height matcher for balance on block"() {
setup:
EthereumCallSelector callSelector = new EthereumCallSelector(Stub(Reader))
EthereumCallSelector callSelector = new EthereumCallSelector(Stub(Reader), Stub(Caches))
def head = Mock(Head) {
_ * getCurrentHeight() >> 100
}
@@ -78,7 +84,7 @@ class EthereumCallSelectorSpec extends Specification {
def heights = Mock(Reader) {
1 * it.read(BlockId.from("0xc90f1c8c125a4d5b90742f16947bdb1d10516f173fd7fc51223d10499de2a812")) >> Mono.just(8606722L)
}
EthereumCallSelector callSelector = new EthereumCallSelector(heights)
EthereumCallSelector callSelector = new EthereumCallSelector(heights, Stub(Caches))
def head = Mock(Head) {
_ * getCurrentHeight() >> 9128116
}
@@ -90,7 +96,7 @@ class EthereumCallSelectorSpec extends Specification {
def "No matcher for invalid height"() {
setup:
EthereumCallSelector callSelector = new EthereumCallSelector(Stub(Reader))
EthereumCallSelector callSelector = new EthereumCallSelector(Stub(Reader), Stub(Caches))
def head = Mock(Head) {
_ * getCurrentHeight() >> 100
}
@@ -103,7 +109,7 @@ class EthereumCallSelectorSpec extends Specification {
def "No matcher for negative height"() {
setup:
EthereumCallSelector callSelector = new EthereumCallSelector(Stub(Reader))
EthereumCallSelector callSelector = new EthereumCallSelector(Stub(Reader), Stub(Caches))
def head = Mock(Head) {
_ * getCurrentHeight() >> 100
}
@@ -115,7 +121,7 @@ class EthereumCallSelectorSpec extends Specification {
def "No matcher for negative long"() {
setup:
EthereumCallSelector callSelector = new EthereumCallSelector(Stub(Reader))
EthereumCallSelector callSelector = new EthereumCallSelector(Stub(Reader), Stub(Caches))
def head = Mock(Head) {
_ * getCurrentHeight() >> 100
}
@@ -128,7 +134,7 @@ class EthereumCallSelectorSpec extends Specification {
def "No matcher for pending balance"() {
setup:
EthereumCallSelector callSelector = new EthereumCallSelector(Stub(Reader))
EthereumCallSelector callSelector = new EthereumCallSelector(Stub(Reader), Stub(Caches))
def head = Mock(Head) {
_ * getCurrentHeight() >> 100
}
@@ -140,7 +146,7 @@ class EthereumCallSelectorSpec extends Specification {
def "Get height matcher with EIP-1898"() {
setup:
EthereumCallSelector callSelector = new EthereumCallSelector(Stub(Reader))
EthereumCallSelector callSelector = new EthereumCallSelector(Stub(Reader), Stub(Caches))
def head = Stub(Head)
when:
def act = callSelector.getMatcher("eth_call", '["0x0000", {"blockNumber": "0x100"}]', head, false).block()
@@ -153,7 +159,7 @@ class EthereumCallSelectorSpec extends Specification {
def heights = Mock(Reader) {
1 * it.read(BlockId.from("0xa6af163aab691919c595e2a466f0a7b01f1dff8cfd9631dee811df57064c2d32")) >> Mono.just(12079192L)
}
EthereumCallSelector callSelector = new EthereumCallSelector(heights)
EthereumCallSelector callSelector = new EthereumCallSelector(heights, Stub(Caches))
def head = Stub(Head)
when:
def act = callSelector.getMatcher("eth_call",
@@ -168,7 +174,7 @@ class EthereumCallSelectorSpec extends Specification {
def heights = Mock(Reader) {
0 * it.read(BlockId.from("0xa6af163aab691919c595e2a466f0a7b01f1dff8cfd9631dee811df57064c2d32")) >> Mono.just(12079192L)
}
EthereumCallSelector callSelector = new EthereumCallSelector(heights)
EthereumCallSelector callSelector = new EthereumCallSelector(heights, Stub(Caches))
def head = Stub(Head)
when:
def act = callSelector.getMatcher("eth_call",
@@ -183,7 +189,7 @@ class EthereumCallSelectorSpec extends Specification {
def heights = Mock(Reader) {
1 * it.read(BlockId.from("0xa6af163aab691919c595e2a466f0a7b01f1dff8cfd9631dee811df57064c2d32")) >> Mono.empty()
}
EthereumCallSelector callSelector = new EthereumCallSelector(heights)
EthereumCallSelector callSelector = new EthereumCallSelector(heights, Stub(Caches))
def head = Mock(Head) {
1 * it.getCurrentHeight() >> 100
}
@@ -197,7 +203,7 @@ class EthereumCallSelectorSpec extends Specification {
def "Get same matcher for getFilterChanges method"() {
setup:
def callSelector = new EthereumCallSelector(Mock(Reader))
def callSelector = new EthereumCallSelector(Mock(Reader), Stub(Caches))
def head = Mock(Head)
expect:
@@ -214,7 +220,7 @@ class EthereumCallSelectorSpec extends Specification {
def "Get empty matcher for getFilterChanges method without params"() {
setup:
def callSelector = new EthereumCallSelector(Mock(Reader))
def callSelector = new EthereumCallSelector(Mock(Reader), Stub(Caches))
def head = Mock(Head)
when:
@@ -223,4 +229,82 @@ class EthereumCallSelectorSpec extends Specification {
then:
act == null
}
def "Get height matcher for getByHash and getTransactionByBlockHash methods"() {
setup:
def hash = "0xa6af163aab691919c595e2a466f0a7b01f1dff8cfd9631dee811df57064c2d32"
def block = new BlockContainer(
12079192L, BlockId.from(hash),
BigInteger.ONE, Instant.now(), false, "".bytes, null, [], 0, "upstream"
)
def blockByHashCache = Mock(BlocksMemCache) {
1 * read(BlockId.from(hash)) >> Mono.just(block)
}
def cache = Caches.newBuilder().setBlockByHash(blockByHashCache).build()
def callSelector = new EthereumCallSelector(Stub(Reader), cache)
def head = Stub(Head)
when:
def act = callSelector.getMatcher(
method, '["0xa6af163aab691919c595e2a466f0a7b01f1dff8cfd9631dee811df57064c2d32", false]',
head, false
)
then:
StepVerifier.create(act)
.expectNext(new Selector.HeightMatcher(12079192L))
.expectComplete()
.verify(Duration.ofSeconds(1))
where:
method << ["eth_getTransactionByBlockHashAndIndex", "eth_getBlockByHash"]
}
def "Get height matcher for getByNumber and getTransactionByBlockNumber methods"() {
setup:
def cache = Stub(Caches)
def callSelector = new EthereumCallSelector(Stub(Reader), cache)
def head = Stub(Head)
when:
def act = callSelector.getMatcher(
method, '["0xfbfe3b", false]',
head, false
)
then:
StepVerifier.create(act)
.expectNext(new Selector.HeightMatcher(16514619L))
.expectComplete()
.verify(Duration.ofSeconds(1))
where:
method << ["eth_getTransactionByBlockNumberAndIndex", "eth_getBlockByNumber"]
}
def "No height matcher for getByHash method"() {
setup:
def hash = "0xa6af163aab691919c595e2a466f0a7b01f1dff8cfd9631dee811df57064c2d32"
def blockByHashCache = Mock(BlocksMemCache) {
1 * read(BlockId.from(hash)) >> resultFromCache
}
def cache = Caches.newBuilder().setBlockByHash(blockByHashCache).build()
def callSelector = new EthereumCallSelector(Stub(Reader), cache)
def head = Stub(Head)
when:
def act = callSelector.getMatcher(
"eth_getBlockByHash", '["0xa6af163aab691919c595e2a466f0a7b01f1dff8cfd9631dee811df57064c2d32", false]',
head, false
)
then:
StepVerifier.create(act)
.expectNext()
.expectComplete()
.verify(Duration.ofSeconds(1))
where:
resultFromCache << [Mono.empty(), Mono.error(new RuntimeException())]
}
}

View File

@@ -10,6 +10,7 @@ import io.emeraldpay.dshackle.reader.Reader
import io.emeraldpay.dshackle.upstream.ApiSource
import io.emeraldpay.dshackle.upstream.Head
import io.emeraldpay.dshackle.upstream.Multistream
import io.emeraldpay.dshackle.upstream.Selector
import io.emeraldpay.dshackle.upstream.calls.DefaultEthereumMethods
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
import io.emeraldpay.dshackle.Chain
@@ -108,7 +109,7 @@ class EthereumDirectReaderSpec extends Specification {
transactions = []
}
def up = Mock(Multistream) {
1 * getApiSource(_) >> Stub(ApiSource)
1 * getApiSource(new Selector.HeightMatcher(100)) >> Stub(ApiSource)
}
def calls = Mock(Factory) {
1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM)