add toncenter (#580)
* add toncenter * upd dep * toncenter->ton * toncenter->ton
This commit is contained in:
@@ -135,6 +135,7 @@ open class CodeGen(private val config: ChainsConfig) {
|
|||||||
"solana" -> "BlockchainType.SOLANA"
|
"solana" -> "BlockchainType.SOLANA"
|
||||||
"near" -> "BlockchainType.NEAR"
|
"near" -> "BlockchainType.NEAR"
|
||||||
"eth-beacon-chain" -> "BlockchainType.ETHEREUM_BEACON_CHAIN"
|
"eth-beacon-chain" -> "BlockchainType.ETHEREUM_BEACON_CHAIN"
|
||||||
|
"ton" -> "BlockchainType.TON"
|
||||||
"cosmos" -> "BlockchainType.COSMOS"
|
"cosmos" -> "BlockchainType.COSMOS"
|
||||||
else -> throw IllegalArgumentException("unknown blockchain type $type")
|
else -> throw IllegalArgumentException("unknown blockchain type $type")
|
||||||
}
|
}
|
||||||
|
|||||||
Submodule emerald-grpc updated: 77ed85be80...6dba9b1a10
@@ -11,7 +11,8 @@ enum class BlockchainType(
|
|||||||
SOLANA(ApiType.JSON_RPC),
|
SOLANA(ApiType.JSON_RPC),
|
||||||
NEAR(ApiType.JSON_RPC),
|
NEAR(ApiType.JSON_RPC),
|
||||||
ETHEREUM_BEACON_CHAIN(ApiType.REST),
|
ETHEREUM_BEACON_CHAIN(ApiType.REST),
|
||||||
COSMOS(ApiType.JSON_RPC);
|
COSMOS(ApiType.JSON_RPC),
|
||||||
|
TON(ApiType.REST);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class ApiType {
|
enum class ApiType {
|
||||||
|
|||||||
Submodule foundation/src/main/resources/public updated: 583c93ae0e...a4e3137cfe
@@ -33,6 +33,8 @@ import io.emeraldpay.dshackle.upstream.bitcoin.data.RpcUnspent
|
|||||||
import io.emeraldpay.dshackle.upstream.bitcoin.data.RpcUnspentDeserializer
|
import io.emeraldpay.dshackle.upstream.bitcoin.data.RpcUnspentDeserializer
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.domain.TransactionId
|
import io.emeraldpay.dshackle.upstream.ethereum.domain.TransactionId
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.subscribe.json.TransactionIdSerializer
|
import io.emeraldpay.dshackle.upstream.ethereum.subscribe.json.TransactionIdSerializer
|
||||||
|
import io.emeraldpay.dshackle.upstream.ton.TonMasterchainInfo
|
||||||
|
import io.emeraldpay.dshackle.upstream.ton.TonMasterchainInfoDeserializer
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import java.util.TimeZone
|
import java.util.TimeZone
|
||||||
@@ -81,6 +83,7 @@ class Global {
|
|||||||
module.addDeserializer(RpcUnspent::class.java, RpcUnspentDeserializer())
|
module.addDeserializer(RpcUnspent::class.java, RpcUnspentDeserializer())
|
||||||
module.addDeserializer(ChainRequest::class.java, ChainRequest.Deserializer())
|
module.addDeserializer(ChainRequest::class.java, ChainRequest.Deserializer())
|
||||||
module.addDeserializer(BeaconChainBlockHeader::class.java, BeaconChainBlockHeaderDeserializer())
|
module.addDeserializer(BeaconChainBlockHeader::class.java, BeaconChainBlockHeaderDeserializer())
|
||||||
|
module.addDeserializer(TonMasterchainInfo::class.java, TonMasterchainInfoDeserializer())
|
||||||
|
|
||||||
val objectMapper = ObjectMapper()
|
val objectMapper = ObjectMapper()
|
||||||
objectMapper.registerModule(module)
|
objectMapper.registerModule(module)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import io.emeraldpay.dshackle.BlockchainType.NEAR
|
|||||||
import io.emeraldpay.dshackle.BlockchainType.POLKADOT
|
import io.emeraldpay.dshackle.BlockchainType.POLKADOT
|
||||||
import io.emeraldpay.dshackle.BlockchainType.SOLANA
|
import io.emeraldpay.dshackle.BlockchainType.SOLANA
|
||||||
import io.emeraldpay.dshackle.BlockchainType.STARKNET
|
import io.emeraldpay.dshackle.BlockchainType.STARKNET
|
||||||
|
import io.emeraldpay.dshackle.BlockchainType.TON
|
||||||
import io.emeraldpay.dshackle.BlockchainType.UNKNOWN
|
import io.emeraldpay.dshackle.BlockchainType.UNKNOWN
|
||||||
import io.emeraldpay.dshackle.Chain
|
import io.emeraldpay.dshackle.Chain
|
||||||
import io.emeraldpay.dshackle.foundation.ChainOptions
|
import io.emeraldpay.dshackle.foundation.ChainOptions
|
||||||
@@ -18,6 +19,7 @@ import io.emeraldpay.dshackle.upstream.calls.DefaultCosmosMethods
|
|||||||
import io.emeraldpay.dshackle.upstream.calls.DefaultEthereumMethods
|
import io.emeraldpay.dshackle.upstream.calls.DefaultEthereumMethods
|
||||||
import io.emeraldpay.dshackle.upstream.calls.DefaultPolkadotMethods
|
import io.emeraldpay.dshackle.upstream.calls.DefaultPolkadotMethods
|
||||||
import io.emeraldpay.dshackle.upstream.calls.DefaultStarknetMethods
|
import io.emeraldpay.dshackle.upstream.calls.DefaultStarknetMethods
|
||||||
|
import io.emeraldpay.dshackle.upstream.calls.DefaultTonHttpMethods
|
||||||
import org.springframework.stereotype.Component
|
import org.springframework.stereotype.Component
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@@ -38,6 +40,7 @@ class CallTargetsHolder {
|
|||||||
NEAR -> DefaultNearMethods()
|
NEAR -> DefaultNearMethods()
|
||||||
ETHEREUM_BEACON_CHAIN -> DefaultBeaconChainMethods()
|
ETHEREUM_BEACON_CHAIN -> DefaultBeaconChainMethods()
|
||||||
COSMOS -> DefaultCosmosMethods()
|
COSMOS -> DefaultCosmosMethods()
|
||||||
|
TON -> DefaultTonHttpMethods()
|
||||||
UNKNOWN -> throw IllegalArgumentException("unknown chain")
|
UNKNOWN -> throw IllegalArgumentException("unknown chain")
|
||||||
}
|
}
|
||||||
callTargets[chain] = created
|
callTargets[chain] = created
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
package io.emeraldpay.dshackle.upstream.calls
|
||||||
|
|
||||||
|
import io.emeraldpay.dshackle.quorum.AlwaysQuorum
|
||||||
|
import io.emeraldpay.dshackle.quorum.CallQuorum
|
||||||
|
import io.emeraldpay.dshackle.upstream.ethereum.rpc.RpcException
|
||||||
|
|
||||||
|
class DefaultTonHttpMethods : CallMethods {
|
||||||
|
|
||||||
|
// HTTP API section
|
||||||
|
private val accountHttpMethods = setOf(
|
||||||
|
getMethod("/getAddressInformation"),
|
||||||
|
getMethod("/getExtendedAddressInformation"),
|
||||||
|
getMethod("/getWalletInformation"),
|
||||||
|
getMethod("/getAddressBalance"),
|
||||||
|
getMethod("/getAddressState"),
|
||||||
|
getMethod("/packAddress"),
|
||||||
|
getMethod("/unpackAddress"),
|
||||||
|
getMethod("/getTokenData"),
|
||||||
|
getMethod("/detectAddress"),
|
||||||
|
)
|
||||||
|
|
||||||
|
private val blockHttpMethods = setOf(
|
||||||
|
getMethod("/getMasterchainInfo"),
|
||||||
|
getMethod("/getMasterchainBlockSignatures"),
|
||||||
|
getMethod("/getShardBlockProof"),
|
||||||
|
getMethod("/getConsensusBlock"),
|
||||||
|
getMethod("/lookupBlock"),
|
||||||
|
getMethod("/shards"),
|
||||||
|
getMethod("/getBlockHeader"),
|
||||||
|
getMethod("/getOutMsgQueueSizes"),
|
||||||
|
)
|
||||||
|
|
||||||
|
private val transactionHttpMethods = setOf(
|
||||||
|
getMethod("/getTransactions"),
|
||||||
|
getMethod("/getBlockTransactions"),
|
||||||
|
getMethod("/getBlockTransactionsExt"),
|
||||||
|
getMethod("/tryLocateTx"),
|
||||||
|
getMethod("/tryLocateResultTx"),
|
||||||
|
getMethod("/tryLocateSourceTx"),
|
||||||
|
)
|
||||||
|
|
||||||
|
private val getConfigHttpMethods = setOf(
|
||||||
|
getMethod("/getConfigParam"),
|
||||||
|
getMethod("/getConfigAll"),
|
||||||
|
)
|
||||||
|
|
||||||
|
private val runMethodHttpMethods = setOf(
|
||||||
|
postMethod("/runGetMethod"),
|
||||||
|
)
|
||||||
|
|
||||||
|
private val sendHttpMethods = setOf(
|
||||||
|
postMethod("/sendBoc"),
|
||||||
|
postMethod("/sendBocReturnHash"),
|
||||||
|
postMethod("/sendQuery"),
|
||||||
|
postMethod("/estimateFee"),
|
||||||
|
)
|
||||||
|
|
||||||
|
private val jsonRpcHttpMethods = setOf(
|
||||||
|
postMethod("/jsonRPC"),
|
||||||
|
)
|
||||||
|
|
||||||
|
private val allowedHttpMethods: Set<String> = accountHttpMethods +
|
||||||
|
blockHttpMethods +
|
||||||
|
transactionHttpMethods +
|
||||||
|
getConfigHttpMethods +
|
||||||
|
runMethodHttpMethods +
|
||||||
|
sendHttpMethods +
|
||||||
|
jsonRpcHttpMethods
|
||||||
|
|
||||||
|
override fun createQuorumFor(method: String): CallQuorum {
|
||||||
|
return AlwaysQuorum()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isCallable(method: String): Boolean {
|
||||||
|
return allowedHttpMethods.contains(method)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSupportedMethods(): Set<String> {
|
||||||
|
return allowedHttpMethods.toSortedSet()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isHardcoded(method: String): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun executeHardcoded(method: String): ByteArray {
|
||||||
|
throw RpcException(-32601, "Method not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getGroupMethods(groupName: String): Set<String> {
|
||||||
|
return when (groupName) {
|
||||||
|
"default" -> allowedHttpMethods
|
||||||
|
else -> emptyList()
|
||||||
|
}.toSet()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getMethod(method: String) = "GET#$method"
|
||||||
|
|
||||||
|
private fun postMethod(method: String) = "POST#$method"
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import io.emeraldpay.dshackle.BlockchainType.NEAR
|
|||||||
import io.emeraldpay.dshackle.BlockchainType.POLKADOT
|
import io.emeraldpay.dshackle.BlockchainType.POLKADOT
|
||||||
import io.emeraldpay.dshackle.BlockchainType.SOLANA
|
import io.emeraldpay.dshackle.BlockchainType.SOLANA
|
||||||
import io.emeraldpay.dshackle.BlockchainType.STARKNET
|
import io.emeraldpay.dshackle.BlockchainType.STARKNET
|
||||||
|
import io.emeraldpay.dshackle.BlockchainType.TON
|
||||||
import io.emeraldpay.dshackle.BlockchainType.UNKNOWN
|
import io.emeraldpay.dshackle.BlockchainType.UNKNOWN
|
||||||
import io.emeraldpay.dshackle.Chain
|
import io.emeraldpay.dshackle.Chain
|
||||||
import io.emeraldpay.dshackle.cache.Caches
|
import io.emeraldpay.dshackle.cache.Caches
|
||||||
@@ -42,6 +43,7 @@ import io.emeraldpay.dshackle.upstream.near.NearChainSpecific
|
|||||||
import io.emeraldpay.dshackle.upstream.polkadot.PolkadotChainSpecific
|
import io.emeraldpay.dshackle.upstream.polkadot.PolkadotChainSpecific
|
||||||
import io.emeraldpay.dshackle.upstream.solana.SolanaChainSpecific
|
import io.emeraldpay.dshackle.upstream.solana.SolanaChainSpecific
|
||||||
import io.emeraldpay.dshackle.upstream.starknet.StarknetChainSpecific
|
import io.emeraldpay.dshackle.upstream.starknet.StarknetChainSpecific
|
||||||
|
import io.emeraldpay.dshackle.upstream.ton.TonHttpSpecific
|
||||||
import org.apache.commons.collections4.Factory
|
import org.apache.commons.collections4.Factory
|
||||||
import org.springframework.cloud.sleuth.Tracer
|
import org.springframework.cloud.sleuth.Tracer
|
||||||
import reactor.core.publisher.Mono
|
import reactor.core.publisher.Mono
|
||||||
@@ -110,6 +112,7 @@ object ChainSpecificRegistry {
|
|||||||
SOLANA -> SolanaChainSpecific
|
SOLANA -> SolanaChainSpecific
|
||||||
NEAR -> NearChainSpecific
|
NEAR -> NearChainSpecific
|
||||||
ETHEREUM_BEACON_CHAIN -> BeaconChainSpecific
|
ETHEREUM_BEACON_CHAIN -> BeaconChainSpecific
|
||||||
|
TON -> TonHttpSpecific
|
||||||
COSMOS -> CosmosChainSpecific
|
COSMOS -> CosmosChainSpecific
|
||||||
BITCOIN -> throw IllegalArgumentException("bitcoin should use custom streams implementation")
|
BITCOIN -> throw IllegalArgumentException("bitcoin should use custom streams implementation")
|
||||||
UNKNOWN -> throw IllegalArgumentException("unknown chain")
|
UNKNOWN -> throw IllegalArgumentException("unknown chain")
|
||||||
|
|||||||
@@ -0,0 +1,134 @@
|
|||||||
|
package io.emeraldpay.dshackle.upstream.ton
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonParser
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationContext
|
||||||
|
import com.fasterxml.jackson.databind.JsonDeserializer
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode
|
||||||
|
import com.fasterxml.jackson.module.kotlin.readValue
|
||||||
|
import io.emeraldpay.dshackle.Chain
|
||||||
|
import io.emeraldpay.dshackle.Global
|
||||||
|
import io.emeraldpay.dshackle.config.ChainsConfig.ChainConfig
|
||||||
|
import io.emeraldpay.dshackle.data.BlockContainer
|
||||||
|
import io.emeraldpay.dshackle.data.BlockId
|
||||||
|
import io.emeraldpay.dshackle.foundation.ChainOptions.Options
|
||||||
|
import io.emeraldpay.dshackle.reader.ChainReader
|
||||||
|
import io.emeraldpay.dshackle.upstream.ChainRequest
|
||||||
|
import io.emeraldpay.dshackle.upstream.SingleValidator
|
||||||
|
import io.emeraldpay.dshackle.upstream.Upstream
|
||||||
|
import io.emeraldpay.dshackle.upstream.UpstreamAvailability
|
||||||
|
import io.emeraldpay.dshackle.upstream.ValidateUpstreamSettingsResult
|
||||||
|
import io.emeraldpay.dshackle.upstream.generic.AbstractPollChainSpecific
|
||||||
|
import io.emeraldpay.dshackle.upstream.lowerbound.LowerBoundService
|
||||||
|
import io.emeraldpay.dshackle.upstream.rpcclient.RestParams
|
||||||
|
import reactor.core.publisher.Mono
|
||||||
|
import java.math.BigInteger
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
|
fun generateRandomString(length: Int): String {
|
||||||
|
val allowedChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||||
|
return (1..length)
|
||||||
|
.map { allowedChars.random() }
|
||||||
|
.joinToString("")
|
||||||
|
}
|
||||||
|
|
||||||
|
object TonHttpSpecific : AbstractPollChainSpecific() {
|
||||||
|
override fun getFromHeader(data: ByteArray, upstreamId: String, api: ChainReader): Mono<BlockContainer> {
|
||||||
|
throw NotImplementedError()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun listenNewHeadsRequest(): ChainRequest {
|
||||||
|
throw NotImplementedError()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun unsubscribeNewHeadsRequest(subId: String): ChainRequest {
|
||||||
|
throw NotImplementedError()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun lowerBoundService(chain: Chain, upstream: Upstream): LowerBoundService {
|
||||||
|
return TonLowerBoundService(chain, upstream)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun latestBlockRequest(): ChainRequest {
|
||||||
|
return ChainRequest("GET#/getMasterchainInfo", RestParams.emptyParams())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun parseBlock(data: ByteArray, upstreamId: String, api: ChainReader): Mono<BlockContainer> {
|
||||||
|
val blockHeader = Global.objectMapper.readValue<TonMasterchainInfo>(data)
|
||||||
|
|
||||||
|
return Mono.just(
|
||||||
|
BlockContainer(
|
||||||
|
height = blockHeader.result.last.seqno,
|
||||||
|
hash = BlockId.fromBase64(blockHeader.result.last.root_hash),
|
||||||
|
difficulty = BigInteger.ZERO,
|
||||||
|
timestamp = Instant.EPOCH,
|
||||||
|
full = false,
|
||||||
|
json = data,
|
||||||
|
parsed = blockHeader,
|
||||||
|
transactions = emptyList(),
|
||||||
|
upstreamId = upstreamId,
|
||||||
|
parentHash = BlockId.fromBase64(generateRandomString(32)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun upstreamValidators(
|
||||||
|
chain: Chain,
|
||||||
|
upstream: Upstream,
|
||||||
|
options: Options,
|
||||||
|
config: ChainConfig,
|
||||||
|
): List<SingleValidator<UpstreamAvailability>> {
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun upstreamSettingsValidators(
|
||||||
|
chain: Chain,
|
||||||
|
upstream: Upstream,
|
||||||
|
options: Options,
|
||||||
|
config: ChainConfig,
|
||||||
|
): List<SingleValidator<ValidateUpstreamSettingsResult>> {
|
||||||
|
// add check generic block
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class TonMasterchainInfoResultLast(
|
||||||
|
val workchain: Int,
|
||||||
|
val shard: String,
|
||||||
|
val seqno: Long,
|
||||||
|
val root_hash: String,
|
||||||
|
val file_hash: String,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class TonMasterchainInfoResult(
|
||||||
|
val last: TonMasterchainInfoResultLast,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class TonMasterchainInfo(
|
||||||
|
val ok: Boolean,
|
||||||
|
val result: TonMasterchainInfoResult,
|
||||||
|
)
|
||||||
|
|
||||||
|
class TonMasterchainInfoDeserializer : JsonDeserializer<TonMasterchainInfo>() {
|
||||||
|
override fun deserialize(p: JsonParser, ctxt: DeserializationContext): TonMasterchainInfo {
|
||||||
|
val node = p.readValueAsTree<JsonNode>()
|
||||||
|
val ok = node["ok"].booleanValue()
|
||||||
|
val workchain = node["result"]["last"]["workchain"].intValue()
|
||||||
|
val shard = node["result"]["last"]["shard"].textValue()
|
||||||
|
val seqno = node["result"]["last"]["seqno"].longValue()
|
||||||
|
val root_hash = node["result"]["last"]["root_hash"].textValue()
|
||||||
|
val file_hash = node["result"]["last"]["file_hash"].textValue()
|
||||||
|
|
||||||
|
return TonMasterchainInfo(
|
||||||
|
ok,
|
||||||
|
TonMasterchainInfoResult(
|
||||||
|
TonMasterchainInfoResultLast(
|
||||||
|
workchain,
|
||||||
|
shard,
|
||||||
|
seqno,
|
||||||
|
root_hash,
|
||||||
|
file_hash,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package io.emeraldpay.dshackle.upstream.ton
|
||||||
|
|
||||||
|
import io.emeraldpay.dshackle.Chain
|
||||||
|
import io.emeraldpay.dshackle.upstream.Upstream
|
||||||
|
import io.emeraldpay.dshackle.upstream.lowerbound.LowerBoundDetector
|
||||||
|
import io.emeraldpay.dshackle.upstream.lowerbound.LowerBoundService
|
||||||
|
|
||||||
|
class TonLowerBoundService(
|
||||||
|
chain: Chain,
|
||||||
|
upstream: Upstream,
|
||||||
|
) : LowerBoundService(chain, upstream) {
|
||||||
|
override fun detectors(): List<LowerBoundDetector> {
|
||||||
|
return listOf()
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user