support evm networks: Arbitrum, Optimism, Binance Smart Chain

This commit is contained in:
Maksim Fomenkov
2022-11-08 19:04:10 +03:00
parent 2a7542e54c
commit 36ac0b84c9
14 changed files with 37 additions and 28 deletions

View File

@@ -44,8 +44,15 @@ class Global {
"ethereum" to Chain.ETHEREUM, "ethereum" to Chain.ETHEREUM,
"ethereum-classic" to Chain.ETHEREUM_CLASSIC, "ethereum-classic" to Chain.ETHEREUM_CLASSIC,
"eth" to Chain.ETHEREUM, "eth" to Chain.ETHEREUM,
"polygon" to Chain.MATIC, "polygon" to Chain.POLYGON,
"matic" to Chain.MATIC, "matic" to Chain.POLYGON,
"arbitrum" to Chain.ARBITRUM,
"arb" to Chain.ARBITRUM,
"optimism" to Chain.OPTIMISM,
"binance" to Chain.BSC,
"bsc" to Chain.BSC,
"bnb-smart-chan" to Chain.BSC,
"etc" to Chain.ETHEREUM_CLASSIC,
"etc" to Chain.ETHEREUM_CLASSIC, "etc" to Chain.ETHEREUM_CLASSIC,
"morden" to Chain.TESTNET_MORDEN, "morden" to Chain.TESTNET_MORDEN,
"kovan" to Chain.TESTNET_KOVAN, "kovan" to Chain.TESTNET_KOVAN,

View File

@@ -41,7 +41,7 @@ class TokensConfig(
type == null -> type type == null -> type
address.isNullOrBlank() -> "address" address.isNullOrBlank() -> "address"
blockchain != null && blockchain != null &&
(BlockchainType.from(blockchain!!) == BlockchainType.ETHEREUM_POS || BlockchainType.from(blockchain!!) == BlockchainType.ETHEREUM) && (BlockchainType.from(blockchain!!) == BlockchainType.EVM_POS || BlockchainType.from(blockchain!!) == BlockchainType.EVM_POW) &&
!Address.isValidAddress(address) -> "address" !Address.isValidAddress(address) -> "address"
else -> null else -> null
} }

View File

@@ -31,6 +31,7 @@ import io.emeraldpay.dshackle.upstream.Multistream
import io.emeraldpay.dshackle.upstream.MultistreamHolder import io.emeraldpay.dshackle.upstream.MultistreamHolder
import io.emeraldpay.dshackle.upstream.Selector import io.emeraldpay.dshackle.upstream.Selector
import io.emeraldpay.dshackle.upstream.calls.EthereumCallSelector import io.emeraldpay.dshackle.upstream.calls.EthereumCallSelector
import io.emeraldpay.dshackle.upstream.ethereum.EthereumMultistream
import io.emeraldpay.dshackle.upstream.ethereum.EthereumPosMultiStream import io.emeraldpay.dshackle.upstream.ethereum.EthereumPosMultiStream
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcError import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcError
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcException import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcException
@@ -66,14 +67,16 @@ open class NativeCall(
private val ethereumCallSelectors = EnumMap<Chain, EthereumCallSelector>(Chain::class.java) private val ethereumCallSelectors = EnumMap<Chain, EthereumCallSelector>(Chain::class.java)
init { init {
multistreamHolder.observeChains().subscribe { chain -> val casting = mapOf(
if ((BlockchainType.from(chain) == BlockchainType.ETHEREUM_POS || BlockchainType.from(chain) == BlockchainType.ETHEREUM) && !ethereumCallSelectors.containsKey( BlockchainType.EVM_POS to EthereumPosMultiStream::class.java,
chain BlockchainType.EVM_POW to EthereumMultistream::class.java,
) )
) {
multistreamHolder.observeChains().subscribe { chain ->
casting[BlockchainType.from(chain)]?.let { cast ->
multistreamHolder.getUpstream(chain)?.let { up -> multistreamHolder.getUpstream(chain)?.let { up ->
val reader = up.cast(EthereumPosMultiStream::class.java).getReader() val reader = up.cast(cast).getReader()
ethereumCallSelectors[chain] = EthereumCallSelector(reader.heightByHash()) ethereumCallSelectors.putIfAbsent(chain, EthereumCallSelector(reader.heightByHash()))
} }
} }
} }
@@ -212,7 +215,7 @@ open class NativeCall(
} }
// for ethereum the actual block needed for the call may be specified in the call parameters // for ethereum the actual block needed for the call may be specified in the call parameters
val callSpecificMatcher: Mono<Selector.Matcher> = val callSpecificMatcher: Mono<Selector.Matcher> =
if (BlockchainType.from(upstream.chain) == BlockchainType.ETHEREUM_POS || BlockchainType.from(upstream.chain) == BlockchainType.ETHEREUM) { if (BlockchainType.from(upstream.chain) == BlockchainType.EVM_POS || BlockchainType.from(upstream.chain) == BlockchainType.EVM_POW) {
ethereumCallSelectors[chain]?.getMatcher(method, params, upstream.getHead()) ethereumCallSelectors[chain]?.getMatcher(method, params, upstream.getHead())
} else { } else {
null null

View File

@@ -57,7 +57,7 @@ open class NativeSubscribe(
fun start(request: BlockchainOuterClass.NativeSubscribeRequest): Publisher<ResponseHolder> { fun start(request: BlockchainOuterClass.NativeSubscribeRequest): Publisher<ResponseHolder> {
val chain = Chain.byId(request.chainValue) val chain = Chain.byId(request.chainValue)
if (BlockchainType.from(chain) != BlockchainType.ETHEREUM_POS && BlockchainType.from(chain) != BlockchainType.ETHEREUM) { if (BlockchainType.from(chain) != BlockchainType.EVM_POS && BlockchainType.from(chain) != BlockchainType.EVM_POW) {
return Mono.error(UnsupportedOperationException("Native subscribe is not supported for ${chain.chainCode}")) return Mono.error(UnsupportedOperationException("Native subscribe is not supported for ${chain.chainCode}"))
} }

View File

@@ -70,7 +70,7 @@ class TrackERC20Address(
override fun isSupported(chain: Chain, asset: String): Boolean { override fun isSupported(chain: Chain, asset: String): Boolean {
return tokens.containsKey(TokenId(chain, asset.lowercase(Locale.getDefault()))) && return tokens.containsKey(TokenId(chain, asset.lowercase(Locale.getDefault()))) &&
(BlockchainType.from(chain) == BlockchainType.ETHEREUM_POS || BlockchainType.from(chain) == BlockchainType.ETHEREUM) && multistreamHolder.isAvailable(chain) (BlockchainType.from(chain) == BlockchainType.EVM_POS || BlockchainType.from(chain) == BlockchainType.EVM_POW) && multistreamHolder.isAvailable(chain)
} }
override fun getBalance(request: BlockchainOuterClass.BalanceRequest): Flux<BlockchainOuterClass.AddressBalance> { override fun getBalance(request: BlockchainOuterClass.BalanceRequest): Flux<BlockchainOuterClass.AddressBalance> {

View File

@@ -43,7 +43,7 @@ class TrackEthereumAddress(
override fun isSupported(chain: Chain, asset: String): Boolean { override fun isSupported(chain: Chain, asset: String): Boolean {
return asset == "ether" && return asset == "ether" &&
(BlockchainType.from(chain) == BlockchainType.ETHEREUM_POS || BlockchainType.from(chain) == BlockchainType.ETHEREUM) && multistreamHolder.isAvailable(chain) (BlockchainType.from(chain) == BlockchainType.EVM_POS || BlockchainType.from(chain) == BlockchainType.EVM_POW) && multistreamHolder.isAvailable(chain)
} }
override fun getBalance(request: BlockchainOuterClass.BalanceRequest): Flux<BlockchainOuterClass.AddressBalance> { override fun getBalance(request: BlockchainOuterClass.BalanceRequest): Flux<BlockchainOuterClass.AddressBalance> {

View File

@@ -62,7 +62,7 @@ class TrackEthereumTx(
private val log = LoggerFactory.getLogger(TrackEthereumTx::class.java) private val log = LoggerFactory.getLogger(TrackEthereumTx::class.java)
override fun isSupported(chain: Chain): Boolean { override fun isSupported(chain: Chain): Boolean {
return (BlockchainType.from(chain) == BlockchainType.ETHEREUM_POS || BlockchainType.from(chain) == BlockchainType.ETHEREUM) && multistreamHolder.isAvailable(chain) return (BlockchainType.from(chain) == BlockchainType.EVM_POS || BlockchainType.from(chain) == BlockchainType.EVM_POW) && multistreamHolder.isAvailable(chain)
} }
override fun subscribe(request: BlockchainOuterClass.TxStatusRequest): Flux<BlockchainOuterClass.TxStatus> { override fun subscribe(request: BlockchainOuterClass.TxStatusRequest): Flux<BlockchainOuterClass.TxStatus> {

View File

@@ -87,13 +87,13 @@ open class ConfiguredUpstreams(
val options = (up.options ?: UpstreamsConfig.Options()) val options = (up.options ?: UpstreamsConfig.Options())
.merge(defaultOptions[chain] ?: UpstreamsConfig.Options.getDefaults()) .merge(defaultOptions[chain] ?: UpstreamsConfig.Options.getDefaults())
val upstream = when (BlockchainType.from(chain)) { val upstream = when (BlockchainType.from(chain)) {
BlockchainType.ETHEREUM -> { BlockchainType.EVM_POW -> {
buildEthereumUpstream(up.cast(UpstreamsConfig.EthereumConnection::class.java), chain, options) buildEthereumUpstream(up.cast(UpstreamsConfig.EthereumConnection::class.java), chain, options)
} }
BlockchainType.BITCOIN -> { BlockchainType.BITCOIN -> {
buildBitcoinUpstream(up.cast(UpstreamsConfig.BitcoinConnection::class.java), chain, options) buildBitcoinUpstream(up.cast(UpstreamsConfig.BitcoinConnection::class.java), chain, options)
} }
BlockchainType.ETHEREUM_POS -> { BlockchainType.EVM_POS -> {
buildEthereumPosUpstream(up.cast(UpstreamsConfig.EthereumPosConnection::class.java), chain, options) buildEthereumPosUpstream(up.cast(UpstreamsConfig.EthereumPosConnection::class.java), chain, options)
} }
else -> { else -> {

View File

@@ -62,7 +62,7 @@ open class CurrentMultistreamHolder(
val chain = change.chain val chain = change.chain
try { try {
when (BlockchainType.from(chain)) { when (BlockchainType.from(chain)) {
BlockchainType.ETHEREUM -> { BlockchainType.EVM_POW -> {
val up = change.upstream.cast(EthereumUpstream::class.java) val up = change.upstream.cast(EthereumUpstream::class.java)
val current = chainMapping[chain] val current = chainMapping[chain]
val factory = Callable<Multistream> { val factory = Callable<Multistream> {
@@ -70,7 +70,7 @@ open class CurrentMultistreamHolder(
} }
processUpdate(change, up, current, factory) processUpdate(change, up, current, factory)
} }
BlockchainType.ETHEREUM_POS -> { BlockchainType.EVM_POS -> {
val up = change.upstream.cast(EthereumPosUpstream::class.java) val up = change.upstream.cast(EthereumPosUpstream::class.java)
val current = chainMapping[chain] val current = chainMapping[chain]
val factory = Callable<Multistream> { val factory = Callable<Multistream> {
@@ -145,9 +145,9 @@ open class CurrentMultistreamHolder(
fun setupDefaultMethods(chain: Chain): CallMethods { fun setupDefaultMethods(chain: Chain): CallMethods {
val created = when (BlockchainType.from(chain)) { val created = when (BlockchainType.from(chain)) {
BlockchainType.ETHEREUM -> DefaultEthereumMethods(chain) BlockchainType.EVM_POW -> DefaultEthereumMethods(chain)
BlockchainType.BITCOIN -> DefaultBitcoinMethods() BlockchainType.BITCOIN -> DefaultBitcoinMethods()
BlockchainType.ETHEREUM_POS -> DefaultEthereumMethods(chain) BlockchainType.EVM_POS -> DefaultEthereumMethods(chain)
else -> throw IllegalStateException("Unsupported chain: $chain") else -> throw IllegalStateException("Unsupported chain: $chain")
} }
callTargets[chain] = created callTargets[chain] = created

View File

@@ -125,7 +125,7 @@ class DefaultEthereumMethods(
Chain.ETHEREUM_CLASSIC == chain -> { Chain.ETHEREUM_CLASSIC == chain -> {
"\"1\"" "\"1\""
} }
Chain.MATIC == chain -> { Chain.POLYGON == chain -> {
"\"137\"" "\"137\""
} }
Chain.TESTNET_MORDEN == chain -> { Chain.TESTNET_MORDEN == chain -> {
@@ -151,7 +151,7 @@ class DefaultEthereumMethods(
Chain.ETHEREUM == chain -> { Chain.ETHEREUM == chain -> {
"\"0x1\"" "\"0x1\""
} }
Chain.MATIC == chain -> { Chain.POLYGON == chain -> {
"\"0x89\"" "\"0x89\""
} }
Chain.TESTNET_ROPSTEN == chain -> { Chain.TESTNET_ROPSTEN == chain -> {

View File

@@ -111,7 +111,7 @@ class EthereumBlockValidator : BlockValidator {
) )
} }
val timestampValid = it.timestamp > cur.timestamp val timestampValid = it.timestamp >= cur.timestamp
if (!timestampValid) { if (!timestampValid) {
log.warn( log.warn(
"Block timestamp {} not valid for {}. Must be greater than {}", "Block timestamp {} not valid for {}. Must be greater than {}",

View File

@@ -240,6 +240,7 @@ open class WsConnection(
.aggregateFrames(msgSizeLimit) .aggregateFrames(msgSizeLimit)
.receiveFrames() .receiveFrames()
.map { ByteBufInputStream(it.content()).readAllBytes() } .map { ByteBufInputStream(it.content()).readAllBytes() }
.filter{ it.isNotEmpty() }
.flatMap { .flatMap {
try { try {
val msg = parser.parse(it) val msg = parser.parse(it)

View File

@@ -190,11 +190,11 @@ class GrpcUpstreams(
) )
val blockchainType = BlockchainType.from(chain) val blockchainType = BlockchainType.from(chain)
if (blockchainType == BlockchainType.ETHEREUM) { if (blockchainType == BlockchainType.EVM_POW) {
return getOrCreateEthereum(chain, metrics) return getOrCreateEthereum(chain, metrics)
} else if (blockchainType == BlockchainType.BITCOIN) { } else if (blockchainType == BlockchainType.BITCOIN) {
return getOrCreateBitcoin(chain, metrics) return getOrCreateBitcoin(chain, metrics)
} else if (blockchainType == BlockchainType.ETHEREUM_POS) { } else if (blockchainType == BlockchainType.EVM_POS) {
return getOrCreateEthereumPos(chain, metrics) return getOrCreateEthereumPos(chain, metrics)
} else { } else {
throw IllegalArgumentException("Unsupported blockchain: $chain") throw IllegalArgumentException("Unsupported blockchain: $chain")

View File

@@ -27,11 +27,9 @@ import io.emeraldpay.dshackle.upstream.calls.CallMethods
import io.emeraldpay.dshackle.upstream.calls.DefaultEthereumMethods import io.emeraldpay.dshackle.upstream.calls.DefaultEthereumMethods
import io.emeraldpay.dshackle.upstream.Upstream import io.emeraldpay.dshackle.upstream.Upstream
import io.emeraldpay.dshackle.upstream.MultistreamHolder import io.emeraldpay.dshackle.upstream.MultistreamHolder
import io.emeraldpay.dshackle.upstream.ethereum.EthereumMultistream
import io.emeraldpay.dshackle.upstream.ethereum.EthereumPosMultiStream import io.emeraldpay.dshackle.upstream.ethereum.EthereumPosMultiStream
import io.emeraldpay.dshackle.upstream.ethereum.EthereumPosRpcUpstream import io.emeraldpay.dshackle.upstream.ethereum.EthereumPosRpcUpstream
import io.emeraldpay.dshackle.upstream.ethereum.EthereumReader import io.emeraldpay.dshackle.upstream.ethereum.EthereumReader
import io.emeraldpay.dshackle.upstream.ethereum.EthereumRpcUpstream
import io.emeraldpay.grpc.BlockchainType import io.emeraldpay.grpc.BlockchainType
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain
import org.jetbrains.annotations.NotNull import org.jetbrains.annotations.NotNull
@@ -48,7 +46,7 @@ class MultistreamHolderMock implements MultistreamHolder {
Multistream addUpstream(@NotNull Chain chain, @NotNull Upstream up) { Multistream addUpstream(@NotNull Chain chain, @NotNull Upstream up) {
if (!upstreams.containsKey(chain)) { if (!upstreams.containsKey(chain)) {
if (BlockchainType.from(chain) == BlockchainType.ETHEREUM_POS) { if (BlockchainType.from(chain) == BlockchainType.EVM_POS) {
if (up instanceof EthereumPosMultiStream) { if (up instanceof EthereumPosMultiStream) {
upstreams[chain] = up upstreams[chain] = up
} else if (up instanceof EthereumPosRpcUpstream) { } else if (up instanceof EthereumPosRpcUpstream) {