Skip to content

Commit

Permalink
add base support of polkadot/substrate/vara chain (#332)
Browse files Browse the repository at this point in the history
  • Loading branch information
a10zn8 authored Nov 2, 2023
1 parent 08cbffe commit 66b9b00
Show file tree
Hide file tree
Showing 42 changed files with 464 additions and 425 deletions.
24 changes: 21 additions & 3 deletions buildSrc/src/main/kotlin/chainsconfig.codegen.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import com.squareup.kotlinpoet.*
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
import io.emeraldpay.dshackle.BlockchainType
import io.emeraldpay.dshackle.config.ChainsConfig
import io.emeraldpay.dshackle.config.ChainsConfigReader
import io.emeraldpay.dshackle.foundation.ChainOptionsReader
Expand All @@ -18,7 +19,7 @@ open class CodeGen(private val config: ChainsConfig) {
builder.addEnumConstant(
"UNSPECIFIED",
TypeSpec.anonymousClassBuilder()
.addSuperclassConstructorParameter("%L, %S, %S, %S, %L, %L", 0, "UNSPECIFIED", "Unknown", "0x0", "BigInteger.ZERO", "emptyList()")
.addSuperclassConstructorParameter("%L, %S, %S, %S, %L, %L, %L", 0, "UNSPECIFIED", "Unknown", "0x0", "BigInteger.ZERO", "emptyList()", "BlockchainType.UNKNOWN")
.build(),
)
for (chain in config) {
Expand All @@ -27,13 +28,14 @@ open class CodeGen(private val config: ChainsConfig) {
.replace(' ', '_'),
TypeSpec.anonymousClassBuilder()
.addSuperclassConstructorParameter(
"%L, %S, %S, %S, %L, %L",
"%L, %S, %S, %S, %L, %L, %L",
chain.grpcId,
chain.code,
chain.blockchain.replaceFirstChar { it.uppercase() } + " " + chain.id.replaceFirstChar { it.uppercase() },
chain.chainId,
"BigInteger(\"" + chain.netVersion + "\")",
"listOf(" + chain.shortNames.map { "\"${it}\"" }.joinToString() + ")",
type(chain.type)
)
.build(),
)
Expand Down Expand Up @@ -65,6 +67,7 @@ open class CodeGen(private val config: ChainsConfig) {
.addParameter("chainId", String::class)
.addParameter("netVersion", BigInteger::class)
.addParameter("shortNames", List::class.asClassName().parameterizedBy(String::class.asClassName()))
.addParameter("type", BlockchainType::class)
.build(),
)
.addProperty(
Expand Down Expand Up @@ -96,12 +99,27 @@ open class CodeGen(private val config: ChainsConfig) {
PropertySpec.builder("shortNames", List::class.asClassName().parameterizedBy(String::class.asClassName()))
.initializer("shortNames")
.build(),
),
)
.addProperty(
PropertySpec.builder("type", BlockchainType::class)
.initializer("type")
.build(),
)
).build()
return FileSpec.builder("io.emeraldpay.dshackle", "Chain")
.addType(chainType)
.build()
}

private fun type(type: String): String {
return when(type) {
"eth" -> "BlockchainType.ETHEREUM"
"bitcoin" -> "BlockchainType.BITCOIN"
"starknet" -> "BlockchainType.STARKNET"
"polkadot" -> "BlockchainType.POLKADOT"
else -> throw IllegalArgumentException("unknown blockchain type $type")
}
}
}

open class ChainsCodeGenTask : DefaultTask() {
Expand Down
2 changes: 1 addition & 1 deletion emerald-grpc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package io.emeraldpay.dshackle

enum class BlockchainType {
UNKNOWN, BITCOIN, ETHEREUM, STARKNET, POLKADOT;
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ data class ChainsConfig(private val chains: List<ChainConfig>) : Iterable<Chains
val callLimitContract: String?,
val id: String,
val blockchain: String,
val type: String
) {
companion object {
@JvmStatic
Expand All @@ -49,6 +50,7 @@ data class ChainsConfig(private val chains: List<ChainConfig>) : Iterable<Chains
callLimitContract,
"undefined",
"undefined",
"unknown"
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ class ChainsConfigReader(
protocols.value.fold(emptyMap()) { acc, protocol ->
val blockchain = getValueAsString(protocol, "id")
?: throw IllegalArgumentException("Blockchain id is not defined")
val type = getValueAsString(protocol, "type")
?: throw IllegalArgumentException("undefined type for $blockchain")
val settings = mergeMappingNode(default, getMapping(protocol, "settings"))
acc.plus(
getList<MappingNode>(protocol, "chains")?.let { chains ->
Expand All @@ -38,6 +40,10 @@ class ChainsConfigReader(
ScalarNode(Tag.STR, "blockchain", null, null, DumperOptions.ScalarStyle.LITERAL),
ScalarNode(Tag.STR, blockchain, null, null, DumperOptions.ScalarStyle.LITERAL),
),
NodeTuple(
ScalarNode(Tag.STR, "type", null, null, DumperOptions.ScalarStyle.LITERAL),
ScalarNode(Tag.STR, type, null, null, DumperOptions.ScalarStyle.LITERAL),
),
),
chain.flowStyle,
),
Expand Down Expand Up @@ -78,6 +84,8 @@ class ChainsConfigReader(
val netVersion = getValueAsLong(node, "net-version")?.toBigInteger() ?: BigInteger(chainId.drop(2), 16)
val shortNames = getListOfString(node, "short-names")
?: throw IllegalArgumentException("undefined shortnames for $blockchain")
val type = getValueAsString(node, "type")
?: throw IllegalArgumentException("undefined type for $blockchain")
return ChainsConfig.ChainConfig(
expectedBlockTime = expectedBlockTime,
syncingLagSize = lags.first,
Expand All @@ -91,6 +99,7 @@ class ChainsConfigReader(
shortNames = shortNames,
id = id,
blockchain = blockchain,
type = type
)
}

Expand Down
23 changes: 23 additions & 0 deletions foundation/src/main/resources/chains.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -641,3 +641,26 @@ chain-settings:
short-names: [ astar-zkatana ]
chain-id: 0x133e40
grpcId: 10035
- id: vara
label: varanet
type: polkadot
settings:
expected-block-time: 3s
options:
validate-peers: false
lags:
syncing: 10
lagging: 5
chains:
- id: Mainnet
priority: 1
code: VARA_MAINNET
short-names: [ vara ]
chain-id: 0x0
grpcId: 1027
- id: Testnet
priority: 1
code: VARA_TESTMET
short-names: [ vara-testnet ]
chain-id: 0x0
grpcId: 10036
1 change: 1 addition & 0 deletions foundation/src/test/resources/configs/chains-basic.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ version: v1
chain-settings:
protocols:
- id: fantom
type: eth
settings:
expected-block-time: 10s
options:
Expand Down
22 changes: 0 additions & 22 deletions src/main/kotlin/io/emeraldpay/dshackle/BlockchainType.kt

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class TokensConfig(
type == null -> type
address.isNullOrBlank() -> "address"
blockchain != null &&
(BlockchainType.from(blockchain!!) == BlockchainType.ETHEREUM) &&
(blockchain!!.type == BlockchainType.ETHEREUM) &&
!Address.isValidAddress(address) -> "address"
else -> null
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package io.emeraldpay.dshackle.config.context

import io.emeraldpay.dshackle.BlockchainType
import io.emeraldpay.dshackle.BlockchainType.BITCOIN
import io.emeraldpay.dshackle.Chain
import io.emeraldpay.dshackle.cache.CachesFactory
Expand Down Expand Up @@ -30,7 +29,7 @@ open class MultistreamsConfig(val beanFactory: ConfigurableListableBeanFactory)
return Chain.entries
.filterNot { it == Chain.UNSPECIFIED }
.map { chain ->
if (BlockchainType.from(chain) == BITCOIN) {
if (chain.type == BITCOIN) {
bitcoinMultistream(chain, cachesFactory, headScheduler)
} else {
genericMultistream(chain, cachesFactory, headScheduler, tracer)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,10 @@ class AccessHandlerGrpc(
): ServerCall.Listener<ReqT> {
return when (val method = call.methodDescriptor.bareMethodName) {
"SubscribeHead" -> processSubscribeHead(call, headers, next)
"SubscribeBalance" -> processSubscribeBalance(call, headers, next, true)
"SubscribeTxStatus" -> processSubscribeTxStatus(call, headers, next)
"GetBalance" -> processSubscribeBalance(call, headers, next, false)
"NativeCall" -> processNativeCall(call, headers, next)
"NativeSubscribe" -> processNativeSubscribe(call, headers, next)
"Describe" -> processDescribe(call, headers, next)
"SubscribeStatus" -> processStatus(call, headers, next)
"EstimateFee" -> processEstimateFee(call, headers, next)
else -> {
log.warn("unsupported method `{}`", method)
next.startCall(call, headers)
Expand Down Expand Up @@ -90,35 +86,6 @@ class AccessHandlerGrpc(
)
}

@Suppress("UNCHECKED_CAST")
private fun <ReqT : Any, RespT : Any> processSubscribeBalance(
call: ServerCall<ReqT, RespT>,
headers: Metadata,
next: ServerCallHandler<ReqT, RespT>,
subscribe: Boolean,
): ServerCall.Listener<ReqT> {
return process(
call,
headers,
next,
EventsBuilder.SubscribeBalance(subscribe) as EventsBuilder.RequestReply<*, ReqT, RespT>,
)
}

@Suppress("UNCHECKED_CAST")
private fun <ReqT : Any, RespT : Any> processSubscribeTxStatus(
call: ServerCall<ReqT, RespT>,
headers: Metadata,
next: ServerCallHandler<ReqT, RespT>,
): ServerCall.Listener<ReqT> {
return process(
call,
headers,
next,
EventsBuilder.TxStatus() as EventsBuilder.RequestReply<*, ReqT, RespT>,
)
}

@Suppress("UNCHECKED_CAST")
private fun <ReqT : Any, RespT : Any> processNativeCall(
call: ServerCall<ReqT, RespT>,
Expand Down Expand Up @@ -175,20 +142,6 @@ class AccessHandlerGrpc(
)
}

@Suppress("UNCHECKED_CAST")
private fun <ReqT : Any, RespT : Any> processEstimateFee(
call: ServerCall<ReqT, RespT>,
headers: Metadata,
next: ServerCallHandler<ReqT, RespT>,
): ServerCall.Listener<ReqT> {
return process(
call,
headers,
next,
EventsBuilder.EstimateFee() as EventsBuilder.RequestReply<*, ReqT, RespT>,
)
}

open class StdCallListener<Req, EB : EventsBuilder.RequestReply<*, Req, *>>(
val next: ServerCall.Listener<Req>,
val builder: EB,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import java.net.InetAddress
import java.net.InetSocketAddress
import java.time.Duration
import java.time.Instant
import java.util.Locale
import java.util.UUID

class EventsBuilder {
Expand Down Expand Up @@ -244,69 +243,6 @@ class EventsBuilder {
}
}

class SubscribeBalance(val subscribe: Boolean) :
Base<SubscribeBalance>(),
RequestReply<Events.SubscribeBalance, BlockchainOuterClass.BalanceRequest, BlockchainOuterClass.AddressBalance> {

private var index = 0
private var balanceRequest: Events.BalanceRequest? = null

override fun getT(): SubscribeBalance {
return this
}

override fun onRequest(msg: BlockchainOuterClass.BalanceRequest) {
balanceRequest = Events.BalanceRequest(
msg.asset.code.uppercase(Locale.getDefault()),
msg.address.addrTypeCase.name,
)
}

override fun onReply(msg: BlockchainOuterClass.AddressBalance): Events.SubscribeBalance {
if (balanceRequest == null) {
throw IllegalStateException("Request is not initialized")
}
val addressBalance = Events.AddressBalance(msg.asset.code, msg.address.address)
val chain = Chain.byId(msg.asset.chain.number)
return Events.SubscribeBalance(
chain,
UUID.randomUUID(),
subscribe,
requestDetails,
balanceRequest!!,
addressBalance,
index++,
)
}
}

class TxStatus :
Base<TxStatus>(),
RequestReply<Events.TxStatus, BlockchainOuterClass.TxStatusRequest, BlockchainOuterClass.TxStatus> {
private var index = 0
private var txStatusRequest: Events.TxStatusRequest? = null

override fun onRequest(msg: BlockchainOuterClass.TxStatusRequest) {
this.txStatusRequest = Events.TxStatusRequest(msg.txId)
withChain(msg.chainValue)
}

override fun onReply(msg: BlockchainOuterClass.TxStatus): Events.TxStatus {
return Events.TxStatus(
chain,
UUID.randomUUID(),
requestDetails,
txStatusRequest!!,
Events.TxStatusResponse(msg.confirmations),
index++,
)
}

override fun getT(): TxStatus {
return this
}
}

class NativeCall(private val startTs: Instant) :
Base<NativeCall>(),
RequestReply<Events.NativeCall, BlockchainOuterClass.NativeCallRequest, BlockchainOuterClass.NativeCallReplyItem> {
Expand Down Expand Up @@ -496,34 +432,4 @@ class EventsBuilder {
)
}
}

class EstimateFee :
Base<EstimateFee>(),
RequestReply<Events.EstimateFee, BlockchainOuterClass.EstimateFeeRequest, BlockchainOuterClass.EstimateFeeResponse> {

private var mode: String = "UNKNOWN"
private var blocks: Int = 0

override fun getT(): EstimateFee {
return this
}

override fun onRequest(msg: BlockchainOuterClass.EstimateFeeRequest) {
this.chain = Chain.byId(msg.chain.number)
this.mode = msg.mode.name
this.blocks = msg.blocks
}

override fun onReply(msg: BlockchainOuterClass.EstimateFeeResponse): Events.EstimateFee {
return Events.EstimateFee(
blockchain = chain,
request = requestDetails,
id = UUID.randomUUID(),
estimateFee = Events.EstimateFeeDetails(
mode = mode,
blocks = blocks,
),
)
}
}
}
Loading

0 comments on commit 66b9b00

Please sign in to comment.