add base support of polkadot/substrate/vara chain (#332)

This commit is contained in:
a10zn8
2023-11-02 16:18:54 +03:00
committed by GitHub
parent 08cbffe7d1
commit 66b9b00454
42 changed files with 464 additions and 425 deletions

View File

@@ -1,83 +0,0 @@
package io.emeraldpay.dshackle.monitoring.accesslog
import io.emeraldpay.api.proto.BlockchainOuterClass
import io.emeraldpay.api.proto.Common
import io.emeraldpay.dshackle.Chain
import spock.lang.Specification
class EventsBuilderSubscribeBalanceSpec extends Specification {
def "Basic ethereum event"() {
setup:
def request = BlockchainOuterClass.BalanceRequest.newBuilder()
.setAddress(
Common.AnyAddress.newBuilder()
.setAddressSingle(
Common.SingleAddress.newBuilder()
.setAddress("0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D")
)
)
.setAsset(
Common.Asset.newBuilder()
.setChainValue(100)
.setCode("ETHER")
)
.build()
def resp = BlockchainOuterClass.AddressBalance.newBuilder()
.setAddress(Common.SingleAddress.newBuilder()
.setAddress("0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D"))
.setAsset(Common.Asset.newBuilder()
.setChainValue(100)
.setCode("ETHER"))
.setBalance("1234560000000000000")
.build()
when:
def act = new EventsBuilder.SubscribeBalance(true).tap {
it.onRequest(request)
}.onReply(resp)
then:
act.index == 0
act.blockchain == Chain.ETHEREUM__MAINNET
act.balanceRequest.asset == "ETHER"
act.balanceRequest.addressType == "ADDRESS_SINGLE"
act.addressBalance.asset == "ETHER"
act.addressBalance.address == "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D"
}
def "Basic bitcoin event"() {
setup:
def request = BlockchainOuterClass.BalanceRequest.newBuilder()
.setAddress(
Common.AnyAddress.newBuilder()
.setAddressSingle(
Common.SingleAddress.newBuilder()
.setAddress("1NDyJtNTjmwk5xPNhjgAMu4HDHigtobu1s")
)
)
.setAsset(
Common.Asset.newBuilder()
.setChainValue(1)
.setCode("BTC")
)
.build()
def resp = BlockchainOuterClass.AddressBalance.newBuilder()
.setAddress(Common.SingleAddress.newBuilder()
.setAddress("1NDyJtNTjmwk5xPNhjgAMu4HDHigtobu1s"))
.setAsset(Common.Asset.newBuilder()
.setChainValue(1)
.setCode("BTC"))
.setBalance("12345600000000")
.build()
when:
def act = new EventsBuilder.SubscribeBalance(true).tap {
it.onRequest(request)
}.onReply(resp)
then:
act.index == 0
act.blockchain == Chain.BITCOIN__MAINNET
act.balanceRequest.asset == "BTC"
act.balanceRequest.addressType == "ADDRESS_SINGLE"
act.addressBalance.asset == "BTC"
act.addressBalance.address == "1NDyJtNTjmwk5xPNhjgAMu4HDHigtobu1s"
}
}

View File

@@ -23,7 +23,7 @@ class ConnectorFactoryMock implements ConnectorFactory {
return true
}
GenericConnector create(DefaultUpstream upstream, Chain chain, boolean skipEnhance) {
GenericConnector create(DefaultUpstream upstream, Chain chain) {
return new GenericConnectorMock(api, head)
}
}

View File

@@ -42,7 +42,7 @@ class MultistreamHolderMock implements MultistreamHolder {
Multistream addUpstream(@NotNull Chain chain, @NotNull Upstream up) {
if (!upstreams.containsKey(chain)) {
if (BlockchainType.from(chain) == BlockchainType.ETHEREUM) {
if (chain.type == BlockchainType.ETHEREUM) {
if (up instanceof GenericMultistream) {
upstreams[chain] = up
} else if (up instanceof GenericUpstream) {
@@ -57,7 +57,7 @@ class MultistreamHolderMock implements MultistreamHolder {
throw new IllegalArgumentException("Unsupported upstream type ${up.class}")
}
upstreams[chain].start()
} else if (BlockchainType.from(chain) == BlockchainType.BITCOIN) {
} else if (chain.type == BlockchainType.BITCOIN) {
if (up instanceof BitcoinMultistream) {
upstreams[chain] = up
} else if (up instanceof BitcoinRpcUpstream) {

View File

@@ -27,6 +27,7 @@ import io.emeraldpay.dshackle.upstream.forkchoice.AlwaysForkChoice
import io.emeraldpay.etherjar.domain.BlockHash
import io.emeraldpay.etherjar.domain.TransactionId
import io.emeraldpay.etherjar.rpc.json.TransactionRefJson
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
import reactor.core.publisher.Sinks
@@ -38,7 +39,7 @@ import java.time.Duration
import java.time.Instant
import java.time.temporal.ChronoUnit
class EthereumWsHeadSpec extends Specification {
class GenericWsHeadSpec extends Specification {
BlockHash parent = BlockHash.from("0x3ec2ebf5d0ec474d0ac6bc50d2770d8409ad76e119968e7919f85d5ec8915200")
DefaultUpstream upstream = new GenericUpstreamMock(Chain.ETHEREUM__MAINNET, TestingCommons.api())
@@ -50,38 +51,29 @@ class EthereumWsHeadSpec extends Specification {
block.hash = BlockHash.from("0x3ec2ebf5d0ec474d0ac6bc50d2770d8409ad76e119968e7919f85d5ec8915200")
block.parentHash = parent
block.timestamp = Instant.now().truncatedTo(ChronoUnit.SECONDS)
block.transactions = [
new TransactionRefJson(TransactionId.from("0x29229361dc5aa1ec66c323dc7a299e2b61a8c8dd2a3522d41255ec10eca25dd8")),
new TransactionRefJson(TransactionId.from("0xebe8f22a55a9e26892a8545b93cbb2bfa4fd81c3184e50e5cf6276025bb42b93"))
]
block.uncles = []
block.totalDifficulty = BigInteger.ONE
def headBlock = block.copy().tap {
it.transactions = null
}.with {
def headBlock = block.copy().with {
Global.objectMapper.writeValueAsBytes(it)
}
def apiMock = TestingCommons.api()
apiMock.answerOnce("eth_getBlockByHash", ["0x3ec2ebf5d0ec474d0ac6bc50d2770d8409ad76e119968e7919f85d5ec8915200", false], block)
def ws = Mock(WsSubscriptions) {
1 * it.connectionInfoFlux() >> Flux.empty()
}
def head = new EthereumWsHead(new AlwaysForkChoice(), BlockValidator.ALWAYS_VALID, apiMock, ws, false, Schedulers.boundedElastic(), Schedulers.boundedElastic(), upstream, EthereumChainSpecific.INSTANCE)
def head = new GenericWsHead(new AlwaysForkChoice(), BlockValidator.ALWAYS_VALID, apiMock, ws, Schedulers.boundedElastic(), Schedulers.boundedElastic(), upstream, EthereumChainSpecific.INSTANCE)
def res = BlockContainer.from(block)
when:
def act = head.listenNewHeads().blockFirst()
then:
act == BlockContainer.from(block)
act.transactions.size() == 2
act.transactions[0].toHexWithPrefix() == "0x29229361dc5aa1ec66c323dc7a299e2b61a8c8dd2a3522d41255ec10eca25dd8"
act.transactions[1].toHexWithPrefix() == "0xebe8f22a55a9e26892a8545b93cbb2bfa4fd81c3184e50e5cf6276025bb42b93"
act == res
1 * ws.subscribe("newHeads") >> new WsSubscriptions.SubscribeData(
1 * ws.subscribe(_) >> new WsSubscriptions.SubscribeData(
Flux.fromIterable([headBlock]), "id"
)
}
@@ -99,19 +91,17 @@ class EthereumWsHeadSpec extends Specification {
}
def apiMock = TestingCommons.api()
apiMock.answerOnce("eth_getBlockByHash", ["0x29229361dc5aa1ec66c323dc7a299e2b61a8c8dd2a3522d41255ec10eca25dd8", false], null)
apiMock.answerOnce("eth_blockNumber", [], Mono.empty())
def connectionInfoSink = Sinks.many().multicast().directBestEffort()
def ws = Mock(WsSubscriptions) {
1 * it.connectionInfoFlux() >> connectionInfoSink.asFlux()
2 * subscribe("newHeads") >>> [
2 * subscribe(_) >>> [
new WsSubscriptions.SubscribeData(Flux.error(new RuntimeException()), "id"),
new WsSubscriptions.SubscribeData(Flux.fromIterable([secondHeadBlock]), "id")
]
}
def head = new EthereumWsHead(new AlwaysForkChoice(), BlockValidator.ALWAYS_VALID, apiMock, ws, true, Schedulers.boundedElastic(), Schedulers.boundedElastic(), upstream, EthereumChainSpecific.INSTANCE)
def head = new GenericWsHead(new AlwaysForkChoice(), BlockValidator.ALWAYS_VALID, apiMock, ws, Schedulers.boundedElastic(), Schedulers.boundedElastic(), upstream, EthereumChainSpecific.INSTANCE)
when:
def act = head.getFlux()
@@ -159,13 +149,13 @@ class EthereumWsHeadSpec extends Specification {
def ws = Mock(WsSubscriptions) {
1 * it.connectionInfoFlux() >> connectionInfoSink.asFlux()
2 * subscribe("newHeads") >>> [
2 * subscribe(_) >>> [
new WsSubscriptions.SubscribeData(Flux.fromIterable([firstHeadBlock]), "id"),
new WsSubscriptions.SubscribeData(Flux.fromIterable([secondHeadBlock]), "id")
]
}
def head = new EthereumWsHead(new AlwaysForkChoice(), BlockValidator.ALWAYS_VALID, apiMock, ws, true, Schedulers.boundedElastic(), Schedulers.boundedElastic(), upstream, EthereumChainSpecific.INSTANCE)
def head = new GenericWsHead(new AlwaysForkChoice(), BlockValidator.ALWAYS_VALID, apiMock, ws, Schedulers.boundedElastic(), Schedulers.boundedElastic(), upstream, EthereumChainSpecific.INSTANCE)
when:
def act = head.getFlux()
@@ -200,12 +190,12 @@ class EthereumWsHeadSpec extends Specification {
def ws = Mock(WsSubscriptions) {
1 * it.connectionInfoFlux() >> connectionInfoSink.asFlux()
1 * subscribe("newHeads") >>> [
1 * subscribe(_) >>> [
new WsSubscriptions.SubscribeData(Flux.fromIterable([firstHeadBlock]), "id"),
]
}
def head = new EthereumWsHead( new AlwaysForkChoice(), BlockValidator.ALWAYS_VALID, apiMock, ws, true, Schedulers.boundedElastic(), Schedulers.boundedElastic(), upstream, EthereumChainSpecific.INSTANCE)
def head = new GenericWsHead( new AlwaysForkChoice(), BlockValidator.ALWAYS_VALID, apiMock, ws, Schedulers.boundedElastic(), Schedulers.boundedElastic(), upstream, EthereumChainSpecific.INSTANCE)
when:
def act = head.getFlux()
@@ -239,12 +229,12 @@ class EthereumWsHeadSpec extends Specification {
def ws = Mock(WsSubscriptions) {
1 * it.connectionInfoFlux() >> connectionInfoSink.asFlux()
1 * subscribe("newHeads") >>> [
1 * subscribe(_) >>> [
new WsSubscriptions.SubscribeData(Flux.fromIterable([firstHeadBlock]), "id"),
]
}
def head = new EthereumWsHead(new AlwaysForkChoice(), BlockValidator.ALWAYS_VALID, apiMock, ws, true, Schedulers.boundedElastic(), Schedulers.boundedElastic(), upstream, EthereumChainSpecific.INSTANCE)
def head = new GenericWsHead(new AlwaysForkChoice(), BlockValidator.ALWAYS_VALID, apiMock, ws, Schedulers.boundedElastic(), Schedulers.boundedElastic(), upstream, EthereumChainSpecific.INSTANCE)
when:
def act = head.getFlux()
@@ -291,13 +281,13 @@ class EthereumWsHeadSpec extends Specification {
def ws = Mock(WsSubscriptions) {
1 * it.connectionInfoFlux() >> connectionInfoSink.asFlux()
2 * subscribe("newHeads") >>> [
2 * subscribe(_) >>> [
new WsSubscriptions.SubscribeData(Flux.fromIterable([firstHeadBlock]), "id"),
new WsSubscriptions.SubscribeData(Flux.fromIterable([secondHeadBlock]), "id"),
]
}
def head = new EthereumWsHead(new AlwaysForkChoice(), BlockValidator.ALWAYS_VALID, apiMock, ws, true, Schedulers.boundedElastic(), Schedulers.boundedElastic(), upstream, EthereumChainSpecific.INSTANCE)
def head = new GenericWsHead(new AlwaysForkChoice(), BlockValidator.ALWAYS_VALID, apiMock, ws, Schedulers.boundedElastic(), Schedulers.boundedElastic(), upstream, EthereumChainSpecific.INSTANCE)
when:
def act = head.getFlux()

View File

@@ -45,7 +45,7 @@ class WsSubscriptionsImplSpec extends Specification {
def ws = new WsSubscriptionsImpl(pool)
when:
def act = ws.subscribe("foo_bar")
def act = ws.subscribe(new JsonRpcRequest("eth_subscribe", ["foo_bar"]))
.data
.map { new String(it) }
.take(3)
@@ -83,7 +83,7 @@ class WsSubscriptionsImplSpec extends Specification {
def ws = new WsSubscriptionsImpl(pool)
when:
def act = ws.subscribe("foo_bar")
def act = ws.subscribe(new JsonRpcRequest("eth_subscribe", ["foo_bar"]))
.data
.map { new String(it) }
.take(3)

View File

@@ -15,6 +15,7 @@
*/
package io.emeraldpay.dshackle.upstream.ethereum.subscribe
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
import io.emeraldpay.dshackle.upstream.Selector
import io.emeraldpay.dshackle.upstream.ethereum.WsSubscriptions
import reactor.core.publisher.Flux
@@ -40,7 +41,7 @@ class WebsocketPendingTxesSpec extends Specification {
.collectList().block(Duration.ofSeconds(1))
then:
1 * ws.subscribe("newPendingTransactions") >> new WsSubscriptions.SubscribeData(
1 * ws.subscribe(new JsonRpcRequest("eth_subscribe", ["newPendingTransactions"])) >> new WsSubscriptions.SubscribeData(
Flux.fromIterable(responses), "id"
)
txes.collect {it.toHex() } == [

File diff suppressed because one or more lines are too long

View File

@@ -1,7 +1,6 @@
package io.emeraldpay.dshackle.upstream.starknet
import io.emeraldpay.dshackle.data.BlockId
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
import org.assertj.core.api.Assertions
import org.junit.jupiter.api.Test
@@ -23,7 +22,7 @@ val example = """
class StarknetChainSpecificTest {
@Test
fun parseResponse() {
val result = StarknetChainSpecific.parseBlock(JsonRpcResponse.ok(example), "1")
val result = StarknetChainSpecific.parseBlock(example.toByteArray(), "1")
Assertions.assertThat(result.height).isEqualTo(304789)
Assertions.assertThat(result.hash).isEqualTo(BlockId.from("046fa6638dc7fae06cece980ce4195436a79ef314ca49d99e0cef552d6f13c4e"))