make additional request for blockhash in polkadot (#537)

This commit is contained in:
a10zn8
2024-08-02 15:22:26 +03:00
committed by GitHub
parent 91784fe34a
commit 642e3851f8
10 changed files with 111 additions and 69 deletions

View File

@@ -45,20 +45,22 @@ object BeaconChainSpecific : AbstractPollChainSpecific() {
return ChainRequest("GET#/eth/v1/beacon/headers/head", RestParams.emptyParams()) return ChainRequest("GET#/eth/v1/beacon/headers/head", RestParams.emptyParams())
} }
override fun parseBlock(data: ByteArray, upstreamId: String): BlockContainer { override fun parseBlock(data: ByteArray, upstreamId: String, api: ChainReader): Mono<BlockContainer> {
val blockHeader = Global.objectMapper.readValue<BeaconChainBlockHeader>(data) val blockHeader = Global.objectMapper.readValue<BeaconChainBlockHeader>(data)
return BlockContainer( return Mono.just(
height = blockHeader.height, BlockContainer(
hash = BlockId.from(blockHeader.hash), height = blockHeader.height,
difficulty = BigInteger.ZERO, hash = BlockId.from(blockHeader.hash),
timestamp = Instant.EPOCH, difficulty = BigInteger.ZERO,
full = false, timestamp = Instant.EPOCH,
json = data, full = false,
parsed = blockHeader, json = data,
transactions = emptyList(), parsed = blockHeader,
upstreamId = upstreamId, transactions = emptyList(),
parentHash = BlockId.from(blockHeader.parentHash), upstreamId = upstreamId,
parentHash = BlockId.from(blockHeader.parentHash),
),
) )
} }

View File

@@ -29,20 +29,22 @@ object CosmosChainSpecific : AbstractPollChainSpecific() {
val log = LoggerFactory.getLogger(this::class.java) val log = LoggerFactory.getLogger(this::class.java)
override fun latestBlockRequest(): ChainRequest = ChainRequest("block", ObjectParams()) override fun latestBlockRequest(): ChainRequest = ChainRequest("block", ObjectParams())
override fun parseBlock(data: ByteArray, upstreamId: String): BlockContainer { override fun parseBlock(data: ByteArray, upstreamId: String, api: ChainReader): Mono<BlockContainer> {
val result = Global.objectMapper.readValue(data, CosmosBlockResult::class.java) val result = Global.objectMapper.readValue(data, CosmosBlockResult::class.java)
return BlockContainer( return Mono.just(
height = result.block.header.height.toLong(), BlockContainer(
hash = BlockId.from(result.blockId.hash), height = result.block.header.height.toLong(),
difficulty = BigInteger.ZERO, hash = BlockId.from(result.blockId.hash),
timestamp = result.block.header.time, difficulty = BigInteger.ZERO,
full = false, timestamp = result.block.header.time,
json = data, full = false,
parsed = result, json = data,
transactions = emptyList(), parsed = result,
upstreamId = upstreamId, transactions = emptyList(),
parentHash = BlockId.from(result.block.header.lastBlockId.hash), upstreamId = upstreamId,
parentHash = BlockId.from(result.block.header.lastBlockId.hash),
),
) )
} }

View File

@@ -46,12 +46,12 @@ object EthereumChainSpecific : AbstractPollChainSpecific() {
private val log: Logger = LoggerFactory.getLogger(EthereumChainSpecific::class.java) private val log: Logger = LoggerFactory.getLogger(EthereumChainSpecific::class.java)
override fun parseBlock(data: ByteArray, upstreamId: String): BlockContainer { override fun parseBlock(data: ByteArray, upstreamId: String, api: ChainReader): Mono<BlockContainer> {
return BlockContainer.fromEthereumJson(data, upstreamId) return Mono.just(BlockContainer.fromEthereumJson(data, upstreamId))
} }
override fun getFromHeader(data: ByteArray, upstreamId: String, api: ChainReader): Mono<BlockContainer> { override fun getFromHeader(data: ByteArray, upstreamId: String, api: ChainReader): Mono<BlockContainer> {
return Mono.just(parseBlock(data, upstreamId)) return parseBlock(data, upstreamId, api)
} }
override fun latestBlockRequest() = override fun latestBlockRequest() =

View File

@@ -121,12 +121,12 @@ abstract class AbstractChainSpecific : ChainSpecific {
abstract class AbstractPollChainSpecific : AbstractChainSpecific() { abstract class AbstractPollChainSpecific : AbstractChainSpecific() {
override fun getLatestBlock(api: ChainReader, upstreamId: String): Mono<BlockContainer> { override fun getLatestBlock(api: ChainReader, upstreamId: String): Mono<BlockContainer> {
return api.read(latestBlockRequest()).map { return api.read(latestBlockRequest()).flatMap {
parseBlock(it.getResult(), upstreamId) parseBlock(it.getResult(), upstreamId, api)
} }
} }
abstract fun latestBlockRequest(): ChainRequest abstract fun latestBlockRequest(): ChainRequest
abstract fun parseBlock(data: ByteArray, upstreamId: String): BlockContainer abstract fun parseBlock(data: ByteArray, upstreamId: String, api: ChainReader): Mono<BlockContainer>
} }

View File

@@ -26,20 +26,22 @@ import java.time.Instant
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
object NearChainSpecific : AbstractPollChainSpecific() { object NearChainSpecific : AbstractPollChainSpecific() {
override fun parseBlock(data: ByteArray, upstreamId: String): BlockContainer { override fun parseBlock(data: ByteArray, upstreamId: String, api: ChainReader): Mono<BlockContainer> {
val block = Global.objectMapper.readValue(data, NearBlock::class.java).header val block = Global.objectMapper.readValue(data, NearBlock::class.java).header
return BlockContainer( return Mono.just(
height = block.height, BlockContainer(
hash = BlockId.fromBase64(block.hash), height = block.height,
difficulty = BigInteger.ZERO, hash = BlockId.fromBase64(block.hash),
timestamp = Instant.ofEpochMilli(TimeUnit.MILLISECONDS.convert(block.timestamp, TimeUnit.NANOSECONDS)), difficulty = BigInteger.ZERO,
full = false, timestamp = Instant.ofEpochMilli(TimeUnit.MILLISECONDS.convert(block.timestamp, TimeUnit.NANOSECONDS)),
json = data, full = false,
parsed = block, json = data,
transactions = emptyList(), parsed = block,
upstreamId = upstreamId, transactions = emptyList(),
parentHash = BlockId.fromBase64(block.prevHash), upstreamId = upstreamId,
parentHash = BlockId.fromBase64(block.prevHash),
),
) )
} }

View File

@@ -39,22 +39,22 @@ import java.time.Instant
object PolkadotChainSpecific : AbstractPollChainSpecific() { object PolkadotChainSpecific : AbstractPollChainSpecific() {
private val log = LoggerFactory.getLogger(PolkadotChainSpecific::class.java) private val log = LoggerFactory.getLogger(PolkadotChainSpecific::class.java)
override fun parseBlock(data: ByteArray, upstreamId: String): BlockContainer { override fun parseBlock(data: ByteArray, upstreamId: String, api: ChainReader): Mono<BlockContainer> {
val response = Global.objectMapper.readValue(data, PolkadotBlockResponse::class.java) val response = Global.objectMapper.readValue(data, PolkadotBlockResponse::class.java)
return api.read(ChainRequest("chain_getBlockHash", ListParams(response.block.header.number)))
return makeBlock(response.block.header, data, upstreamId) .map { makeBlock(it.getResultAsProcessedString(), response.block.header, data, upstreamId) }
} }
override fun getFromHeader(data: ByteArray, upstreamId: String, api: ChainReader): Mono<BlockContainer> { override fun getFromHeader(data: ByteArray, upstreamId: String, api: ChainReader): Mono<BlockContainer> {
val header = Global.objectMapper.readValue(data, PolkadotHeader::class.java) val header = Global.objectMapper.readValue(data, PolkadotHeader::class.java)
return api.read(ChainRequest("chain_getBlockHash", ListParams(header.number)))
return Mono.just(makeBlock(header, data, upstreamId)) .map { makeBlock(it.getResultAsProcessedString(), header, data, upstreamId) }
} }
private fun makeBlock(header: PolkadotHeader, data: ByteArray, upstreamId: String): BlockContainer { private fun makeBlock(id: String, header: PolkadotHeader, data: ByteArray, upstreamId: String): BlockContainer {
return BlockContainer( return BlockContainer(
height = header.number.substring(2).toLong(16), height = header.number.substring(2).toLong(16),
hash = BlockId.from(header.parentHash), // todo hash = BlockId.from(id),
difficulty = BigInteger.ZERO, difficulty = BigInteger.ZERO,
timestamp = Instant.EPOCH, timestamp = Instant.EPOCH,
full = false, full = false,

View File

@@ -27,20 +27,22 @@ object StarknetChainSpecific : AbstractPollChainSpecific() {
private val log = LoggerFactory.getLogger(StarknetChainSpecific::class.java) private val log = LoggerFactory.getLogger(StarknetChainSpecific::class.java)
override fun parseBlock(data: ByteArray, upstreamId: String): BlockContainer { override fun parseBlock(data: ByteArray, upstreamId: String, api: ChainReader): Mono<BlockContainer> {
val block = Global.objectMapper.readValue(data, StarknetBlock::class.java) val block = Global.objectMapper.readValue(data, StarknetBlock::class.java)
return BlockContainer( return Mono.just(
height = block.number, BlockContainer(
hash = BlockId.from(block.hash), height = block.number,
difficulty = BigInteger.ZERO, hash = BlockId.from(block.hash),
timestamp = block.timestamp, difficulty = BigInteger.ZERO,
full = false, timestamp = block.timestamp,
json = data, full = false,
parsed = block, json = data,
transactions = emptyList(), parsed = block,
upstreamId = upstreamId, transactions = emptyList(),
parentHash = BlockId.from(block.parent), upstreamId = upstreamId,
parentHash = BlockId.from(block.parent),
),
) )
} }

View File

@@ -2,8 +2,12 @@ package io.emeraldpay.dshackle.upstream.beaconchain
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.reader.ChainReader
import io.emeraldpay.dshackle.upstream.ChainRequest
import io.emeraldpay.dshackle.upstream.ChainResponse
import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import reactor.core.publisher.Mono
import java.math.BigInteger import java.math.BigInteger
import java.time.Instant import java.time.Instant
@@ -44,7 +48,13 @@ class BeaconChainSpecificTest {
parsed = null, parsed = null,
) )
val block = BeaconChainSpecific.parseBlock(header, "upId") val block = BeaconChainSpecific.parseBlock(
header,
"upId",
object : ChainReader {
override fun read(key: ChainRequest): Mono<ChainResponse> = Mono.empty()
},
).block()!!
assertEquals(expected, block) assertEquals(expected, block)
} }
} }

View File

@@ -1,9 +1,13 @@
package io.emeraldpay.dshackle.upstream.polkadot package io.emeraldpay.dshackle.upstream.polkadot
import io.emeraldpay.dshackle.data.BlockId import io.emeraldpay.dshackle.data.BlockId
import io.emeraldpay.dshackle.reader.ChainReader
import io.emeraldpay.dshackle.upstream.ChainRequest
import io.emeraldpay.dshackle.upstream.ChainResponse
import io.emeraldpay.dshackle.upstream.UpstreamAvailability import io.emeraldpay.dshackle.upstream.UpstreamAvailability
import org.assertj.core.api.Assertions import org.assertj.core.api.Assertions
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import reactor.core.publisher.Mono
val example = """ val example = """
{ {
@@ -63,10 +67,16 @@ val healthBadSyncing = """{
class PolkadotChainSpecificTest { class PolkadotChainSpecificTest {
@Test @Test
fun parseResponse() { fun parseResponse() {
val result = PolkadotChainSpecific.parseBlock(example.toByteArray(), "1") val result = PolkadotChainSpecific.parseBlock(
example.toByteArray(),
"1",
object : ChainReader {
override fun read(key: ChainRequest): Mono<ChainResponse> = Mono.just(ChainResponse("\"0x1\"".toByteArray(), null))
},
).block()!!
Assertions.assertThat(result.height).isEqualTo(17963964) Assertions.assertThat(result.height).isEqualTo(17963964)
Assertions.assertThat(result.hash).isEqualTo(BlockId.from("0xb52a9b51fb698a891cf378b990b0b6a5743e52fa5175b44a8a6d4e0b2cfd0a53")) Assertions.assertThat(result.hash).isEqualTo(BlockId.from("0x1"))
Assertions.assertThat(result.upstreamId).isEqualTo("1") Assertions.assertThat(result.upstreamId).isEqualTo("1")
Assertions.assertThat(result.parentHash).isEqualTo(BlockId.from("0xb52a9b51fb698a891cf378b990b0b6a5743e52fa5175b44a8a6d4e0b2cfd0a53")) Assertions.assertThat(result.parentHash).isEqualTo(BlockId.from("0xb52a9b51fb698a891cf378b990b0b6a5743e52fa5175b44a8a6d4e0b2cfd0a53"))
} }

View File

@@ -1,9 +1,13 @@
package io.emeraldpay.dshackle.upstream.starknet package io.emeraldpay.dshackle.upstream.starknet
import io.emeraldpay.dshackle.data.BlockId import io.emeraldpay.dshackle.data.BlockId
import io.emeraldpay.dshackle.reader.ChainReader
import io.emeraldpay.dshackle.upstream.ChainRequest
import io.emeraldpay.dshackle.upstream.ChainResponse
import io.emeraldpay.dshackle.upstream.UpstreamAvailability import io.emeraldpay.dshackle.upstream.UpstreamAvailability
import org.assertj.core.api.Assertions import org.assertj.core.api.Assertions
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import reactor.core.publisher.Mono
val example = """ val example = """
{ {
@@ -45,21 +49,31 @@ val syncingBad = """
class StarknetChainSpecificTest { class StarknetChainSpecificTest {
@Test @Test
fun parseResponse() { fun parseResponse() {
val result = StarknetChainSpecific.parseBlock(example.toByteArray(), "1") val result = StarknetChainSpecific.parseBlock(
example.toByteArray(),
"1",
object : ChainReader {
override fun read(key: ChainRequest): Mono<ChainResponse> = Mono.empty()
},
).block()!!
Assertions.assertThat(result.height).isEqualTo(304789) Assertions.assertThat(result.height).isEqualTo(304789)
Assertions.assertThat(result.hash).isEqualTo(BlockId.from("046fa6638dc7fae06cece980ce4195436a79ef314ca49d99e0cef552d6f13c4e")) Assertions.assertThat(result.hash)
.isEqualTo(BlockId.from("046fa6638dc7fae06cece980ce4195436a79ef314ca49d99e0cef552d6f13c4e"))
Assertions.assertThat(result.upstreamId).isEqualTo("1") Assertions.assertThat(result.upstreamId).isEqualTo("1")
Assertions.assertThat(result.parentHash).isEqualTo(BlockId.from("07cc1e178c848b0bdfa047a414d9a8bee4f6cb76f25f312f2d42e058ea91d78b")) Assertions.assertThat(result.parentHash)
.isEqualTo(BlockId.from("07cc1e178c848b0bdfa047a414d9a8bee4f6cb76f25f312f2d42e058ea91d78b"))
} }
@Test @Test
fun validateOk() { fun validateOk() {
Assertions.assertThat(StarknetChainSpecific.validate(syncingGood.toByteArray(), 10, "test")).isEqualTo(UpstreamAvailability.OK) Assertions.assertThat(StarknetChainSpecific.validate(syncingGood.toByteArray(), 10, "test"))
.isEqualTo(UpstreamAvailability.OK)
} }
@Test @Test
fun validateSyncing() { fun validateSyncing() {
Assertions.assertThat(StarknetChainSpecific.validate(syncingBad.toByteArray(), 10, "test")).isEqualTo(UpstreamAvailability.SYNCING) Assertions.assertThat(StarknetChainSpecific.validate(syncingBad.toByteArray(), 10, "test"))
.isEqualTo(UpstreamAvailability.SYNCING)
} }
} }