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())
}
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)
return BlockContainer(
height = blockHeader.height,
hash = BlockId.from(blockHeader.hash),
difficulty = BigInteger.ZERO,
timestamp = Instant.EPOCH,
full = false,
json = data,
parsed = blockHeader,
transactions = emptyList(),
upstreamId = upstreamId,
parentHash = BlockId.from(blockHeader.parentHash),
return Mono.just(
BlockContainer(
height = blockHeader.height,
hash = BlockId.from(blockHeader.hash),
difficulty = BigInteger.ZERO,
timestamp = Instant.EPOCH,
full = false,
json = data,
parsed = blockHeader,
transactions = emptyList(),
upstreamId = upstreamId,
parentHash = BlockId.from(blockHeader.parentHash),
),
)
}

View File

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

View File

@@ -121,12 +121,12 @@ abstract class AbstractChainSpecific : ChainSpecific {
abstract class AbstractPollChainSpecific : AbstractChainSpecific() {
override fun getLatestBlock(api: ChainReader, upstreamId: String): Mono<BlockContainer> {
return api.read(latestBlockRequest()).map {
parseBlock(it.getResult(), upstreamId)
return api.read(latestBlockRequest()).flatMap {
parseBlock(it.getResult(), upstreamId, api)
}
}
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
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
return BlockContainer(
height = block.height,
hash = BlockId.fromBase64(block.hash),
difficulty = BigInteger.ZERO,
timestamp = Instant.ofEpochMilli(TimeUnit.MILLISECONDS.convert(block.timestamp, TimeUnit.NANOSECONDS)),
full = false,
json = data,
parsed = block,
transactions = emptyList(),
upstreamId = upstreamId,
parentHash = BlockId.fromBase64(block.prevHash),
return Mono.just(
BlockContainer(
height = block.height,
hash = BlockId.fromBase64(block.hash),
difficulty = BigInteger.ZERO,
timestamp = Instant.ofEpochMilli(TimeUnit.MILLISECONDS.convert(block.timestamp, TimeUnit.NANOSECONDS)),
full = false,
json = data,
parsed = block,
transactions = emptyList(),
upstreamId = upstreamId,
parentHash = BlockId.fromBase64(block.prevHash),
),
)
}

View File

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

View File

@@ -27,20 +27,22 @@ object StarknetChainSpecific : AbstractPollChainSpecific() {
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)
return BlockContainer(
height = block.number,
hash = BlockId.from(block.hash),
difficulty = BigInteger.ZERO,
timestamp = block.timestamp,
full = false,
json = data,
parsed = block,
transactions = emptyList(),
upstreamId = upstreamId,
parentHash = BlockId.from(block.parent),
return Mono.just(
BlockContainer(
height = block.number,
hash = BlockId.from(block.hash),
difficulty = BigInteger.ZERO,
timestamp = block.timestamp,
full = false,
json = data,
parsed = block,
transactions = emptyList(),
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.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.Test
import reactor.core.publisher.Mono
import java.math.BigInteger
import java.time.Instant
@@ -44,7 +48,13 @@ class BeaconChainSpecificTest {
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)
}
}

View File

@@ -1,9 +1,13 @@
package io.emeraldpay.dshackle.upstream.polkadot
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 org.assertj.core.api.Assertions
import org.junit.jupiter.api.Test
import reactor.core.publisher.Mono
val example = """
{
@@ -63,10 +67,16 @@ val healthBadSyncing = """{
class PolkadotChainSpecificTest {
@Test
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.hash).isEqualTo(BlockId.from("0xb52a9b51fb698a891cf378b990b0b6a5743e52fa5175b44a8a6d4e0b2cfd0a53"))
Assertions.assertThat(result.hash).isEqualTo(BlockId.from("0x1"))
Assertions.assertThat(result.upstreamId).isEqualTo("1")
Assertions.assertThat(result.parentHash).isEqualTo(BlockId.from("0xb52a9b51fb698a891cf378b990b0b6a5743e52fa5175b44a8a6d4e0b2cfd0a53"))
}

View File

@@ -1,9 +1,13 @@
package io.emeraldpay.dshackle.upstream.starknet
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 org.assertj.core.api.Assertions
import org.junit.jupiter.api.Test
import reactor.core.publisher.Mono
val example = """
{
@@ -45,21 +49,31 @@ val syncingBad = """
class StarknetChainSpecificTest {
@Test
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.hash).isEqualTo(BlockId.from("046fa6638dc7fae06cece980ce4195436a79ef314ca49d99e0cef552d6f13c4e"))
Assertions.assertThat(result.hash)
.isEqualTo(BlockId.from("046fa6638dc7fae06cece980ce4195436a79ef314ca49d99e0cef552d6f13c4e"))
Assertions.assertThat(result.upstreamId).isEqualTo("1")
Assertions.assertThat(result.parentHash).isEqualTo(BlockId.from("07cc1e178c848b0bdfa047a414d9a8bee4f6cb76f25f312f2d42e058ea91d78b"))
Assertions.assertThat(result.parentHash)
.isEqualTo(BlockId.from("07cc1e178c848b0bdfa047a414d9a8bee4f6cb76f25f312f2d42e058ea91d78b"))
}
@Test
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
fun validateSyncing() {
Assertions.assertThat(StarknetChainSpecific.validate(syncingBad.toByteArray(), 10, "test")).isEqualTo(UpstreamAvailability.SYNCING)
Assertions.assertThat(StarknetChainSpecific.validate(syncingBad.toByteArray(), 10, "test"))
.isEqualTo(UpstreamAvailability.SYNCING)
}
}