solution: caching for eth_getTransactionReceipt

fix: #26
This commit is contained in:
Igor Artamonov
2020-07-12 23:34:23 -04:00
parent 3a93df2e32
commit b10e4800ff
24 changed files with 690 additions and 177 deletions

View File

@@ -21,12 +21,10 @@ import io.emeraldpay.dshackle.data.BlockContainer
import io.emeraldpay.dshackle.data.BlockId
import io.emeraldpay.dshackle.data.TxId
import io.emeraldpay.dshackle.test.IntegrationTestingCommons
import io.emeraldpay.dshackle.test.TestingCommons
import io.emeraldpay.grpc.Chain
import io.infinitape.etherjar.domain.BlockHash
import io.infinitape.etherjar.rpc.json.BlockJson
import io.infinitape.etherjar.rpc.json.TransactionRefJson
import io.lettuce.core.RedisClient
import io.lettuce.core.api.StatefulRedisConnection
import spock.lang.IgnoreIf
import spock.lang.Specification
@@ -69,8 +67,8 @@ class BlocksRedisCacheSpec extends Specification {
)
when:
def enc = cache.toProto(cont)
def dec = cache.fromProto(enc)
def enc = cache.toProto(cont, cont)
def dec = cache.deserializeValue(enc)
then:
dec.height == 100

View File

@@ -0,0 +1,96 @@
package io.emeraldpay.dshackle.cache
import com.fasterxml.jackson.databind.ObjectMapper
import io.emeraldpay.dshackle.Global
import io.emeraldpay.dshackle.data.BlockId
import io.emeraldpay.dshackle.data.DefaultContainer
import io.emeraldpay.dshackle.data.TxId
import io.emeraldpay.dshackle.test.IntegrationTestingCommons
import io.emeraldpay.grpc.Chain
import io.infinitape.etherjar.domain.BlockHash
import io.infinitape.etherjar.domain.TransactionId
import io.infinitape.etherjar.rpc.json.TransactionReceiptJson
import io.lettuce.core.api.StatefulRedisConnection
import spock.lang.IgnoreIf
import spock.lang.Specification
@IgnoreIf({ IntegrationTestingCommons.isDisabled("redis") })
class ReceiptRedisCacheSpec extends Specification {
StatefulRedisConnection<String, byte[]> redis
ReceiptRedisCache cache
ObjectMapper objectMapper = Global.objectMapper
String receiptJson = '''
{
"blockHash": "0x2c3cfd4c7f2b58859371f5795eaf8524caa6e63145ac7e9df23c8d63aab891ae",
"blockNumber": "0x213b8a",
"contractAddress": null,
"cumulativeGasUsed": "0x5208",
"gasUsed": "0x5208",
"logs": [],
"transactionHash": "0x5929b36be4586c57bd87dfb7ea6be3b985c1f527fa3d69d221604b424aeb4197",
"transactionIndex": "0x00"
}
'''
TransactionReceiptJson receipt = new TransactionReceiptJson().tap {
transactionHash = TransactionId.from("0x5929b36be4586c57bd87dfb7ea6be3b985c1f527fa3d69d221604b424aeb4197")
transactionIndex = 0
blockHash = BlockHash.from("0x2c3cfd4c7f2b58859371f5795eaf8524caa6e63145ac7e9df23c8d63aab891ae")
blockNumber = 0x213b8a
cumulativeGasUsed = 0x5208
gasUsed = 0x5208
logs = []
}
def setup() {
redis = IntegrationTestingCommons.redisConnection()
redis.sync().flushdb()
cache = new ReceiptRedisCache(
redis.reactive(), Chain.ETHEREUM
)
}
def "Add and read"() {
setup:
def container = new DefaultContainer(
TxId.from(receipt.transactionHash),
BlockId.from(receipt.blockHash),
receipt.blockNumber,
receiptJson.bytes,
receipt
)
when:
cache.add(container).block()
def act = cache.read(TxId.from(receipt.transactionHash)).block()
then:
act != null
objectMapper.readValue(act, TransactionReceiptJson) == receipt
}
def "Evict value"() {
setup:
def container = new DefaultContainer(
TxId.from(receipt.transactionHash),
BlockId.from(receipt.blockHash),
receipt.blockNumber,
receiptJson.bytes,
receipt
)
when:
cache.add(container).block()
def act = cache.read(TxId.from(receipt.transactionHash)).block()
then:
act != null
when:
cache.evict(TxId.from(receipt.transactionHash)).subscribe()
act = cache.read(TxId.from(receipt.transactionHash)).block()
then:
act == null
}
}

View File

@@ -68,7 +68,7 @@ class TxRedisCacheSpec extends Specification {
null
)
when:
def enc = cache.toProto(cont)
def enc = cache.toProto(cont.hash, cont)
def dec = cache.fromProto(enc)
then:

View File

@@ -0,0 +1,45 @@
package io.emeraldpay.dshackle.upstream.ethereum
import io.emeraldpay.dshackle.cache.Caches
import io.emeraldpay.dshackle.data.DefaultContainer
import spock.lang.Specification
class CacheRequestedSpec extends Specification {
def "Do nothing if unsupported method"() {
setup:
def caches = Mock(Caches)
CacheRequested instance = new CacheRequested(caches)
when:
instance.onReceive("eth_hashrate", [], '"0x38a"'.bytes)
then:
0 * caches._(*_)
}
def "Caches tx receipt"() {
setup:
def caches = Mock(Caches)
CacheRequested instance = new CacheRequested(caches)
def json = '''{
"blockHash": "0x2c3cfd4c7f2b58859371f5795eaf8524caa6e63145ac7e9df23c8d63aab891ae",
"blockNumber": "0x213b8a",
"contractAddress": null,
"cumulativeGasUsed": "0x5208",
"gasUsed": "0x5208",
"logs": [],
"transactionHash": "0x5929b36be4586c57bd87dfb7ea6be3b985c1f527fa3d69d221604b424aeb4197",
"transactionIndex": "0x00"
}'''.bytes
when:
instance.onReceive("eth_getTransactionReceipt", ["0x5929b36be4586c57bd87dfb7ea6be3b985c1f527fa3d69d221604b424aeb4197"], json)
then:
1 * caches.cacheReceipt(Caches.Tag.REQUESTED, { DefaultContainer it ->
it.height == 0x213b8a &&
it.txId.toHex() == "5929b36be4586c57bd87dfb7ea6be3b985c1f527fa3d69d221604b424aeb4197" &&
it.json == json
})
}
}