add base support of polkadot/substrate/vara chain (#332)
This commit is contained in:
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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()
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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"))
|
||||
|
||||
Reference in New Issue
Block a user