Giter Site home page Giter Site logo

dshackle's Introduction

Emerald Dshackle

Unit Tests Coverage Docker License Discord

Emerald Dshackle is a Fault Tolerant Load Balancer for Blockchain API.

Its primary goal is to ensure reliable routing to multiple nodes, executing each request on a suitable provider. This is achieved by evaluating various node characteristics including location, state, current height, and the RPC methods it can offer.

It tries to recover from connection errors, faulty nodes, invalid responses, etc. If an upstream node lags behind, loses peers below the minimum requirement, initiates a resync, or goes offline, Dshackle temporarily removes it from the request pool. Dshackle reinstates the connection to the node once the upstream issue is resolved.

The upstreams may be blockchain nodes such as Bitcoind, Geth, Parity, or public providers like Infura, QuickNode, etc. It continuously checks their availability and the network’s current status, executing commands while ensuring the response is consistent and data is successfully broadcast to the network.

Provides:

  • Standard Bitcoin and Ethereum JSON RPC API over both HTTP and WebSocket

  • An advanced gRPC-based API, featuring upstream selection, asynchronous execution, and more.

  • Secure TLS with optional client authentication

  • Blockchain-aware edge caching, in memory and Redis

  • Intelligent routing based on data availability (peers, height, sync status)

  • Data consistency, always providing the most up-to-date state

  • Automatic failover and retry

  • Separate public blockchain nodes from your internal servers

Blockchains support:

  • Ethereum and Ethereum Classic

  • Various Ethereum testnets

  • Bitcoin

  • Bitcoin testnet

Warning
The project is still under development, please use with caution.

Quick Start

Configuration

Create file dshackle.yaml with the following content:

version: v1
port: 2449
tls:
  enabled: false

proxy:
  host: 0.0.0.0
  port: 8545
  routes:
    - id: eth
      blockchain: ethereum
    - id: kovan
      blockchain: kovan
    - id: btc
      blockchain: bitcoin

cluster:
  upstreams:
    - id: infura-eth
      blockchain: ethereum
      connection:
        ethereum:
          rpc:
            url: "https://mainnet.infura.io/v3/${INFURA_USER}"
          ws:
            url: "wss://mainnet.infura.io/ws/v3/${INFURA_USER}"
    - id: infura-kovan
      blockchain: kovan
      connection:
        ethereum:
          rpc:
            url: "https://kovan.infura.io/v3/${INFURA_USER}"
          ws:
            url: "wss://kovan.infura.io/ws/v3/${INFURA_USER}"
    - id: bitcoin-main
      blockchain: bitcoin
      connection:
        bitcoin:
          rpc:
            url: "http://localhost:8332"
            basic-auth:
              username: bitcoin
              password: mypassword

Which sets the following:

  • gRPC access through 0.0.0.0:2449

    • TLS security is disabled (please don’t use in production!)

  • JSON RPC access through 0.0.0.0:8545 (both HTTP and WebsScket)

    • proxy requests to Ethereum and Kovan upstreams

    • request path for Ethereum Mainnet is /eth, /kovan for Kovan Testnet, and /btc for bitcoin

    • i.e. call Ethereum Mainnet by POST http://127.0.0.0:8545/eth with JSON RPC payload

  • two upstreams, one for Ethereum Mainnet and another for Kovan Testnet (both upstreams are configured to use Infura endpoint)

  • for Ethereum Mainnet it connects using JSON RPC and WebSocket connections,

  • for Bitcoin Mainet only JSON RPC is used

  • ${INFURA_USER} will be provided through environment variable

Please note that you can configure many upstreams for a single blockchains. If there is more than one upstream, then Dshackle routes requests to them as Round Robin. If one of them becomes unavailable, Dshackle continues to use only active nodes.

I.e., you can set up a node in the local network, plus Infura with role: fallback. If anything happened to your local node, you still have access to a consistent state of the Ethereum blockchain via Infura.

Run docker image

Official Docker image you can find at: emeraldpay/dshackle

Setup Infura username
export INFURA_USER=...
Run Dshackle
docker run -p 2449:2449 -p 8545:8545 -v $(pwd):/etc/dshackle -e "INFURA_USER=$INFURA_USER" emeraldpay/dshackle:0.15

Now it listens on port 2449 at the localhost and can be connected from any gRPC compatible client. Tools such as gRPCurl can automatically parse protobuf definitions and connect to it (actual Protobuf sources are located in a separate repository which you can find at https://github.com/emeraldpay/proto)

Alternatively you can connect to port 8545 with traditional JSON RPC requests

Access using JSON RPC over HTTP

Dshackle implements standard JSON RPC interface, providing additional caching layer, upstream readiness/liveness checks, retry and other features for building Fault Tolerant services.

Request using Curl
curl --request POST \
  --url http://localhost:8545/eth \
  --header 'content-type: application/json' \
  --data '{"jsonrpc":"2.0", "method":"eth_getBalance", "id":1, "params":["0x690b2bdf41f33f9f251ae0459e5898b856ed96be", "latest"]}'
Output
{"jsonrpc":"2.0","id":1,"result":"0x72fa5e0181"}

Access using JSON RPC over WebSocket

Or the same Proxy URL can be accessed through WebSocket

websocat ws://localhost:8545/eth

Then make RPC calls or subscriptions:

> | {"jsonrpc":"2.0", "id": 1, "method": "eth_subscribe", "params": ["newHeads"]}

< | {"jsonrpc":"2.0","id":1,"result":"1f8"}
< | {"jsonrpc":"2.0","method":"eth_subscription","params":{"result":{....},"subscription":"1f8"}}

Access using gRPC

Note
It’s not necessary to use gRPC, as Dshackle can provide standard JSON RPC proxy, but Dshackle gRPC interface improves performance and provides additional features.

Dshackle provides a custom gRPC based API, which provides additional methods and other features such as streaming responses. Please refer to the documentation: gRPC Methods The Protobuf definitions could be found in ./proto.

Connect and listen for new blocks on Ethereum Mainnet
grpcurl -import-path ./proto/ -proto blockchain.proto -d '{\"type\": 100}' -plaintext 127.0.0.1:2449 emerald.Blockchain/SubscribeHead

type: 100 specifies the blockchain id, and 100 means Ethereum Mainnet. 1 is for Bitcoin Mainnet. There we use Ethereum because it creates new blocks every 14 seconds, which works better for demo purposes, but the same request applied to Bitcoin as well.

Output would be like
{
  "chain": "CHAIN_ETHEREUM",
  "height": 8396159,
  "blockId": "fc58a258adccc94466ae967b1178eea721349b0667f59d5fe1b0b436460bce75",
  "timestamp": 1566423564000,
  "weight": "AnMcf2VJB5kOSQ=="
}
{
  "chain": "CHAIN_ETHEREUM",
  "height": 8396160,
  "blockId": "787899711b862b77df8d2faa69de664048598265a9f96abf178d341076e200e0",
  "timestamp": 1566423574000,
  "weight": "AnMch35tO6hSGg=="
}
...
...

The output above is for a streaming subscription to all new blocks on the Ethereum Mainnet.

It’s one of the services provided by Dshackle, in addition to standard methods provided by RPC JSON of underlying nodes.

You can also subscribe to balances changes of the balance on an address:
grpcurl -import-path ./proto/ -proto blockchain.proto -d '{\"asset\": {\"chain\": \"100\", \"code\": \"ether\"}, \"address\": {\"address_single\": {\"address\": \"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\"}}}' -plaintext 127.0.0.1:2449 emerald.Blockchain/SubscribeBalance
and see how balance of the contract responsible for Wrapped Ether is changing:
{
  "asset": {
    "chain": "CHAIN_ETHEREUM",
    "code": "ETHER"
  },
  "address": {
    "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
  },
  "balance": "2410941696896999943701015"
}
{
  "asset": {
    "chain": "CHAIN_ETHEREUM",
    "code": "ETHER"
  },
  "address": {
    "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
  },
  "balance": "2410930748488073834320430"
}
...

The balance subscription works with main coin (ether, bitcoin), or with tokens like ERC-20 if configured additionally. See Configuration Reference.

See other enhanced methods in the Documentation for Enhanced Methods.

Documentation

For detailed documentation see:

Client Libraries

JSON RPC

Dshackle should be compatible with all standard libraries that use Ethereum JSON RPC over HTTP.

Java gRPC Client

repositories {
    maven { url  "https://maven.emrld.io" }
}

dependencies {
    implementation 'io.emeraldpay:emerald-api:0.11.0'
}

Javascript gRPC Client

npm (scoped)

"dependencies": {
    "@emeraldpay/api-node": "0.3.2",
}

See more in the documentation for Client Libraries.

Development

Warning
The code in master branch is considered a development version, which may lack proper testing and should not be used in production.

Setting up environment

Dshackle is JVM based project written in Kotlin. To build and run it from sources you’ll need to install Java JDK and Gradle

Build Dshackle

Build everything

gradle build

Make a Zip distribution

gradle distZip

You can find a redistributable zip in build/distributions

Make a Docker distribution

gradle jib -Pdocker=gcr.io/myproject

Gradle will prepare a Docker image and upload it to your custom Docker Registry at gcr.io/myproject (please change to address of your actual registry)

Architecture

Dshackle is built using:

  • Kotlin

  • Spring Framework + Spring Boot

  • Spring Reactor

  • Netty

  • Etherjar

  • gRPC and HTTP2 protocol

  • Groovy and Spock for testing

Community

Development Chat

Join our Discord chat to discuss development and ask questions:

Discord

Commercial Support

Want to support the project, prioritize a specific feature, or get commercial help with using Dshackle in your project? Please contact [email protected] to discuss the possibility.

License

Copyright 2023 EmeraldPay, Inc

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

dshackle's People

Contributors

aldoborrero avatar kanazirsky avatar mysticryuujin avatar parithosh avatar roderik avatar skylenet avatar splix avatar spontaneousoverthrow avatar termina1 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dshackle's Issues

No quorum for eth_chainId

This one seems interesting...

Again, a Nethermind backend, there's only 1 target though so idk why it's talking about quorum?

v0.7.1 built from ef1212f973 on 2020-06-30T02:56:45 UTC

2020-02-07 16:18:19.816 | WARN  |         WriteRpcJson | Failed to convert to JSON
java.lang.IllegalStateException: No quorum for eth_chainId
        at io.emeraldpay.dshackle.upstream.calls.AggregatedCallMethods.getQuorumFor(AggregatedCallMethods.kt:44) ~[classes/:?]
        at io.emeraldpay.dshackle.rpc.NativeCall$prepareCall$1.apply(NativeCall.kt:119) ~[classes/:?]
        at io.emeraldpay.dshackle.rpc.NativeCall$prepareCall$1.apply(NativeCall.kt:45) ~[classes/:?]
        at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:107) [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
        at reactor.core.publisher.FluxIterable$IterableSubscription.slowPath(FluxIterable.java:267) [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
        at reactor.core.publisher.FluxIterable$IterableSubscription.request(FluxIterable.java:225) [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
        at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:162) [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
        at reactor.core.publisher.FluxMap$MapSubscriber.request(FluxMap.java:155) [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
        at reactor.core.publisher.ParallelSource$ParallelSourceMain.onSubscribe(ParallelSource.java:202) [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
        at reactor.core.publisher.FluxMap$MapSubscriber.onSubscribe(FluxMap.java:86) [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
        at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:90) [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
        at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:161) [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
        at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:86) [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
        at reactor.core.publisher.Flux.subscribe(Flux.java:8325) [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
        at reactor.core.publisher.FluxFlatMap.trySubscribeScalarMap(FluxFlatMap.java:199) [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
        at reactor.core.publisher.MonoFlatMapMany.subscribeOrReturn(MonoFlatMapMany.java:49) [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
        at reactor.core.publisher.Flux.subscribe(Flux.java:8311) [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
        at reactor.core.publisher.ParallelSource.subscribe(ParallelSource.java:87) [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
        at reactor.core.publisher.ParallelFlatMap.subscribe(ParallelFlatMap.java:105) [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
        at reactor.core.publisher.ParallelMergeSequential.subscribe(ParallelMergeSequential.java:72) [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
        at reactor.core.publisher.Mono.subscribe(Mono.java:4218) [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
        at reactor.core.publisher.MonoFlatMapMany$FlatMapManyMain.onNext(MonoFlatMapMany.java:188) [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
        at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:114) [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
        at reactor.core.publisher.FluxHandle$HandleSubscriber.onNext(FluxHandle.java:112) [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
        at reactor.core.publisher.FluxMap$MapConditionalSubscriber.onNext(FluxMap.java:213) [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
        at reactor.core.publisher.FluxDoFinally$DoFinallySubscriber.onNext(FluxDoFinally.java:123) [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
        at reactor.core.publisher.FluxHandleFuseable$HandleFuseableSubscriber.onNext(FluxHandleFuseable.java:178) [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
        at reactor.core.publisher.FluxContextStart$ContextStartSubscriber.onNext(FluxContextStart.java:96) [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
        at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1755) [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
        at reactor.core.publisher.MonoCollectList$MonoCollectListSubscriber.onComplete(MonoCollectList.java:121) [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
        at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:252) [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
        at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:136) [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
        at reactor.netty.channel.FluxReceive.onInboundComplete(FluxReceive.java:366) [reactor-netty-0.9.7.RELEASE.jar:0.9.7.RELEASE]
        at reactor.netty.channel.ChannelOperations.onInboundComplete(ChannelOperations.java:367) [reactor-netty-0.9.7.RELEASE.jar:0.9.7.RELEASE]
        at reactor.netty.http.server.HttpServerOperations.onInboundNext(HttpServerOperations.java:489) [reactor-netty-0.9.7.RELEASE.jar:0.9.7.RELEASE]
        at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:96) [reactor-netty-0.9.7.RELEASE.jar:0.9.7.RELEASE]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
        at reactor.netty.http.server.HttpTrafficHandler.channelRead(HttpTrafficHandler.java:214) [reactor-netty-0.9.7.RELEASE.jar:0.9.7.RELEASE]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
        at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
        at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:323) [netty-codec-4.1.34.Final.jar:4.1.34.Final]
        at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:297) [netty-codec-4.1.34.Final.jar:4.1.34.Final]
        at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
        at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
        at io.netty.channel.epoll.AbstractEpollStreamChannel$EpollStreamUnsafe.epollInReady(AbstractEpollStreamChannel.java:796) [netty-transport-native-epoll-4.1.34.Final-linux-x86_64.jar:4.1.34.Final]
        at io.netty.channel.epoll.EpollEventLoop.processReady(EpollEventLoop.java:427) [netty-transport-native-epoll-4.1.34.Final-linux-x86_64.jar:4.1.34.Final]
        at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:328) [netty-transport-native-epoll-4.1.34.Final-linux-x86_64.jar:4.1.34.Final]
        at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989) [netty-common-4.1.49.Final.jar:4.1.49.Final]
        at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) [netty-common-4.1.49.Final.jar:4.1.49.Final]
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) [netty-common-4.1.49.Final.jar:4.1.49.Final]
        at java.lang.Thread.run(Thread.java:834) [?:?]

FR: More Selective Routes

In the config we can create routes e.g.

  routes:
    - id: eth
      blockchain: ethereum

These routes (i.e. /eth) are then sent to the nodes as defined by their chain: ethereum tag.

What I'd like to be able to do is create a route (e.g. /geth) and be able to only send those requests to specific nodes.

Example:

  routes:
    - id: eth
      blockchain: ethereum
    - id: geth
      blockchain: ethereum
    - id: nethermind
      blockchain: ethereum

  upstreams:
    - id: geth01
      chain: ethereum
      routes:
        - eth
        - geth
...
    - id: nethermind01
      chain: ethereum
      routes:
        - eth
        - nethermind

This would allow all nodes to process requests to /eth and only target nodes to /whatever

I THINK you already have something like with with grpc? I know there's a labels tag, but I don't think we can use those at all with the JSON RPC? Maybe we could do something like /eth?provider=Nethermind if we had a lable called provider?

I don't particularly care in what way this would be implemented but it would be nice.

enable/disable upstream

Configuration option to disable connection per upstream. With ability to use environment variables.

- id: some-upstream
  enabled: false
  chain: ethereum
  connection:
    ....

Is eth_syncing required?

From a technical standpoint is eth_syncing required for dshackle to function properly? The reason I ask is because Turbo-Geth currently doesn't support eth_syncing, which I think is why Turbo-Geth nodes are always listed as UNAVAILABLE in the dshackle logs/output?

I think I could add disable-validation: true but I fear that would cause dshackle to not mark it as down if it is actually down.

I've submitted a feature request to the Turbo-Geth team to add eth_syncing but I wanted to get your thoughts on the topic and/or ask if there's a better workaround. I would think that doing eth_blockNumber and comparing it to other configured nodes would be enough, but I'm not sure.

MetaMask Support / HTTP OPTIONS Support

It would appear that MetaMask is not compatible with dshackle either and I believe the root cause for that incompatibility is that dshackle does not support HTTP OPTIONS requests.

Request from the MetaMask Extension:
image

You'll notice it's /eth/ in the screenshot, but /eth doesn't work either (I was just testing)

The reply is a 404

I think the only way around this right now is to place dshackle behind a proxy like haproxy or nginx and force those to handle HTTP OPTIONS requests.

Select enabled chains for grpc upstream

Currently Dshackle uses all available blockchain if connected through gRPC. Make is possible to specify list of allowed blockchain that should be used instead of all.

Use only ethereum blockchain:

  - id: remote-1
    chain: ethereum
    connection:
      grpc: ...

Use only ethereum and kovan blockchains:

  - id: remote-2
    chain: [ethereum, kovan]
    connection:
      grpc: ...

eth_call : error action revert : timeout

Well this one took a while to track down, but the gist of the issue appears to be that dshackle isn't handling eth_call results when the result is an error

Here is what a call directly to the node looks like:

curl http://archive01.archivenode.io:8545 -H "Content-Type: application/json" -d '{"id":1,"jsonrpc":"2.0","method":"eth_call","params":[{"data":"0x9b013aee000000000000000000000000000000000000000000000000000000000000000a","to":"0x542156d51D10Db5acCB99f9Db7e7C91B74E80a2c"},10428451]}'

{"jsonrpc":"2.0","error":{"code":-32015,"message":"VM execution error.","data":"revert: Invalid state"},"id":1}

However, making that same call through dshackle results in a timeout, and dshackle throws the following errors:


dshackle -   2020-15-07 14:01:07.106 \| WARN  \|         WriteRpcJson \| Failed to convert to   JSON
--
dshackle - 	at   io.emeraldpay.dshackle.quorum.QuorumRpcReader$sam$java_util_function_Function$0.apply(QuorumRpcReader.kt)   ~[classes/:?]
dshackle - 	at   reactor.core.publisher.MonoCollectList$MonoCollectListSubscriber.onComplete(MonoCollectList.java:121)   [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
dshackle - 	at   reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1756)   [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
dshackle - 	at   reactor.core.publisher.FluxHandleFuseable$HandleFuseableSubscriber.onComplete(FluxHandleFuseable.java:223)   [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
dshackle - 	at   reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:136)   [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
dshackle - 	at   reactor.netty.channel.ChannelOperations.terminate(ChannelOperations.java:423)   [reactor-netty-0.9.7.RELEASE.jar:0.9.7.RELEASE]
dshackle - 	at   io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436)   [netty-transport-4.1.49.Final.jar:4.1.49.Final]
dshackle - 	at   io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)   [netty-transport-4.1.49.Final.jar:4.1.49.Final]
dshackle - 	at   io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)   [netty-transport-4.1.49.Final.jar:4.1.49.Final]
dshackle - 	at   io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)   [netty-common-4.1.49.Final.jar:4.1.49.Final]
dshackle - 	at   java.lang.Thread.run(Thread.java:834) [?:?]
dshackle - 	at   io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)   [netty-common-4.1.49.Final.jar:4.1.49.Final]
dshackle -   io.infinitape.etherjar.rpc.RpcException: RPC Error -32015: VM execution   error.
dshackle - 	at   io.emeraldpay.dshackle.quorum.QuorumRpcReader$read$1$1.invoke(QuorumRpcReader.kt:31)   ~[classes/:?]
dshackle - 	at   io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse.requireResult(JsonRpcResponse.kt:91)   ~[classes/:?]
dshackle - 	at   reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:121)   [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
dshackle - 	at   reactor.core.publisher.FluxDoFinally$DoFinallySubscriber.onComplete(FluxDoFinally.java:138)   [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
dshackle - 	at   reactor.netty.channel.FluxReceive.onInboundComplete(FluxReceive.java:366)   [reactor-netty-0.9.7.RELEASE.jar:0.9.7.RELEASE]
dshackle - 	at   io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:297)   [netty-codec-4.1.34.Final.jar:4.1.34.Final]
dshackle - 	at   io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)   [netty-transport-4.1.49.Final.jar:4.1.49.Final]
dshackle - 	at   io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)   [netty-transport-4.1.49.Final.jar:4.1.49.Final]
dshackle - 	at   io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)   [netty-common-4.1.49.Final.jar:4.1.49.Final]
dshackle - 	at   io.emeraldpay.dshackle.quorum.QuorumRpcReader$read$1$1.invoke(QuorumRpcReader.kt:60)   ~[classes/:?]
dshackle - 	at   reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:73)   [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
dshackle - 	at   reactor.core.publisher.MonoFlatMap$FlatMapInner.onNext(MonoFlatMap.java:241)   [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
dshackle - 	at   reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1755)   [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
dshackle - 	at   reactor.core.publisher.FluxDoFinally$DoFinallySubscriber.onComplete(FluxDoFinally.java:138)   [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
dshackle - 	at   reactor.core.publisher.MonoFlatMapMany$FlatMapManyInner.onComplete(MonoFlatMapMany.java:252)   [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
dshackle - 	at   reactor.core.publisher.FluxHandle$HandleSubscriber.onComplete(FluxHandle.java:206)   [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
dshackle - 	at   reactor.core.publisher.FluxContextStart$ContextStartSubscriber.onComplete(FluxContextStart.java:115)   [reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
dshackle - 	at   reactor.netty.channel.ChannelOperations.onInboundComplete(ChannelOperations.java:367)   [reactor-netty-0.9.7.RELEASE.jar:0.9.7.RELEASE]
dshackle - 	at   reactor.netty.http.client.HttpClientOperations.onInboundNext(HttpClientOperations.java:607)   [reactor-netty-0.9.7.RELEASE.jar:0.9.7.RELEASE]
dshackle - 	at   io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:323)   [netty-codec-4.1.34.Final.jar:4.1.34.Final]
dshackle - 	at   io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)   [netty-transport-4.1.49.Final.jar:4.1.49.Final]
dshackle - 	at   io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)   [netty-transport-4.1.49.Final.jar:4.1.49.Final]
dshackle - 	at   io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)   [netty-transport-4.1.49.Final.jar:4.1.49.Final]
dshackle - 	at   io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)   [netty-transport-4.1.49.Final.jar:4.1.49.Final]

Sorry for the strange output, I switched to syslog logging for Docker and it does strange things with line breaks.

Allowed smart contracts

Configuration to setup list of addresses that can be used in eth_call on Ethereum.

Example config:

authorized:

  # allows any method call
  - blockchain: ethereum
    address: 0xdac17f958d2ee523a2206206994597c13d831ec7

  # allow only call to the specified methods  
  - blockchain: ethereum
    address: 0x6b175474e89094c44da98b954eedeac495271d0f
    methods: ["0x18160ddd", "0x70a08231", "0xdd62ed3e"]

Fallback upstreams

Special role for upstream that should be used only as a fallback (and to verify head consistency).

- id: local
  chain: ethereum
  connection: ...
- id: infura
  role: fallback
  chain: ethereum
  connection: ...

Unable to enable redis cache

It's not clear to me if the redis cache support comes 'out of the box' and maybe I'm just doing this wrong because I haven't installed/configured anything redis cache before, but the instructions seem to suggest that enabling it as easy as changing the config value to true 😄

When attempting to start the docker image with Redis support enabled:

cache:
  redis:
    enabled: true
   Emerald Dshackle - Smart Load Balancer for Blockchain API
   https://github.com/emeraldpay/dshackle
   v0.6.1 built from 25a872fc9c on 2020-05-18T00:33:58 UTC

01:50:42.947 [main                ] INFO                 StarterKt | Starting StarterKt on 42aa170ec486 with PID 1 (/app/classes started by root in /)
01:50:42.949 [main                ] INFO                 StarterKt | No active profile set, falling back to default profiles: default
01:50:44.159 [main                ] INFO                    Config | Using config: /etc/dshackle/dshackle.yaml
01:50:44.229 [main                ] INFO             CachesFactory | Use Redis cache at: redis://127.0.0.1
01:50:44.733 [main                ] WARN  ConfigApplicationContext | Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'grpcServer' defined in file [/app/classes/io/emeraldpay/dshackle/GrpcServer.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'blockchainRpc' defined in file [/app/classes/io/emeraldpay/dshackle/rpc/BlockchainRpc.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'nativeCall' defined in file [/app/classes/io/emeraldpay/dshackle/rpc/NativeCall.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'currentUpstreams' defined in file [/app/classes/io/emeraldpay/dshackle/upstream/CurrentUpstreams.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cachesFactory': Invocation of init method failed; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to 127.0.0.1:6379
01:50:44.740 [main                ] ERROR        SpringApplication | Application run failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'grpcServer' defined in file [/app/classes/io/emeraldpay/dshackle/GrpcServer.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'blockchainRpc' defined in file [/app/classes/io/emeraldpay/dshackle/rpc/BlockchainRpc.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'nativeCall' defined in file [/app/classes/io/emeraldpay/dshackle/rpc/NativeCall.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'currentUpstreams' defined in file [/app/classes/io/emeraldpay/dshackle/upstream/CurrentUpstreams.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cachesFactory': Invocation of init method failed; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to 127.0.0.1:6379
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:769) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:218) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1341) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1187) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:849) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:863) ~[spring-context-5.1.4.RELEASE.jar:5.1.4.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546) ~[spring-context-5.1.4.RELEASE.jar:5.1.4.RELEASE]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) [spring-boot-2.1.4.RELEASE.jar:2.1.4.RELEASE]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) [spring-boot-2.1.4.RELEASE.jar:2.1.4.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) [spring-boot-2.1.4.RELEASE.jar:2.1.4.RELEASE]
        at io.emeraldpay.dshackle.StarterKt.main(Starter.kt:36) [classes/:?]
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'blockchainRpc' defined in file [/app/classes/io/emeraldpay/dshackle/rpc/BlockchainRpc.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'nativeCall' defined in file [/app/classes/io/emeraldpay/dshackle/rpc/NativeCall.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'currentUpstreams' defined in file [/app/classes/io/emeraldpay/dshackle/upstream/CurrentUpstreams.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cachesFactory': Invocation of init method failed; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to 127.0.0.1:6379
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:769) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:218) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1341) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1187) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1463) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1427) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1318) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1205) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:760) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        ... 16 more
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'nativeCall' defined in file [/app/classes/io/emeraldpay/dshackle/rpc/NativeCall.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'currentUpstreams' defined in file [/app/classes/io/emeraldpay/dshackle/upstream/CurrentUpstreams.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cachesFactory': Invocation of init method failed; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to 127.0.0.1:6379
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:769) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:218) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1341) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1187) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1247) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:760) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:218) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1341) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1187) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1463) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1427) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1318) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1205) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:760) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        ... 16 more
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'currentUpstreams' defined in file [/app/classes/io/emeraldpay/dshackle/upstream/CurrentUpstreams.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cachesFactory': Invocation of init method failed; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to 127.0.0.1:6379
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:769) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:218) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1341) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1187) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1247) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:760) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:218) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1341) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1187) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1247) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:760) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:218) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1341) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1187) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1463) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1427) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1318) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1205) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:760) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        ... 16 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cachesFactory': Invocation of init method failed; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to 127.0.0.1:6379
        at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:139) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:414) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1770) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1247) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:760) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:218) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1341) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1187) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1247) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:760) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:218) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1341) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1187) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1247) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:760) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:218) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1341) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1187) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1463) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1427) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1318) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1205) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:760) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        ... 16 more
Caused by: io.lettuce.core.RedisConnectionException: Unable to connect to 127.0.0.1:6379
        at io.lettuce.core.RedisConnectionException.create(RedisConnectionException.java:78) ~[lettuce-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
        at io.lettuce.core.RedisConnectionException.create(RedisConnectionException.java:56) ~[lettuce-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
        at io.lettuce.core.AbstractRedisClient.getConnection(AbstractRedisClient.java:234) ~[lettuce-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
        at io.lettuce.core.RedisClient.connect(RedisClient.java:207) ~[lettuce-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
        at io.lettuce.core.RedisClient.connect(RedisClient.java:192) ~[lettuce-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
        at io.emeraldpay.dshackle.cache.CachesFactory.init(CachesFactory.kt:55) ~[classes/:?]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_242]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_242]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_242]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_242]
        at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:363) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:307) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:136) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:414) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1770) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1247) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:760) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:218) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1341) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1187) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1247) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:760) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:218) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1341) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1187) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1247) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:760) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:218) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1341) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1187) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1463) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1427) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1318) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1205) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:760) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        ... 16 more
Caused by: io.netty.channel.AbstractChannel$AnnotatedConnectException: syscall:getsockopt(..) failed: Connection refused: /127.0.0.1:6379
        at io.netty.channel.unix.Socket.finishConnect(..)(Unknown Source) ~[netty-transport-native-unix-common-4.1.34.Final.jar:4.1.34.Final]
Caused by: io.netty.channel.unix.Errors$NativeConnectException: syscall:getsockopt(..) failed: Connection refused
        at io.netty.channel.unix.Socket.finishConnect(..)(Unknown Source) ~[netty-transport-native-unix-common-4.1.34.Final.jar:4.1.34.Final]

Error on `debug_traceTransaction` `Unsupported JSON RPC version`

Command:

curl -H "Content-Type: application/json" -d '{"id": 1, "method": "debug_traceTransaction", "params": ["0xd949bc0fe1a5d16f4522bc47933554dcc4ada0493ff71ee1973b2410257af9fe"]}' http://archive02.archivenode.io:8545

Output from node:
output.zip

Dshackle Error Log:
ErrorLog.txt

Interesting lines from the error log:

ERROR | HttpServerOperations | [id: 0x60d71fcc, L:/172.19.0.2:8545 - R:/172.19.0.3:48624] Error finishing response. Closing connection
    io.infinitape.etherjar.rpc.RpcException: RPC Error -32600: Unsupported JSON   RPC version

Config ignores cache: redis: enabled: false

cache:
  redis:
    enabled: false <---- FALSE
    host: localhost
    port: 6379
    db: 0
    password: "none"
2020-30-05 18:44:19.714 | INFO  |        CachesFactory | Use Redis cache at: redis://localhost
2020-30-05 18:44:20.512 | ERROR |        CachesFactory | Unable to establish connection to the Redis server
2020-30-05 18:44:20.512 | ERROR |        CachesFactory | Redis error: Unable to connect to localhost:6379

NativeCallRouter | Block by number is not implemented

I'm receiving this warning from dshackle and I'm not sure why because the call works just fine? I get the block back when I call it.

2020-06-07 20:01:14.008 | WARN  |     NativeCallRouter | Block by number is not implemented
2020-06-07 20:01:14.015 | WARN  |     NativeCallRouter | Block by number is not implemented
2020-06-07 20:01:14.022 | WARN  |     NativeCallRouter | Block by number is not implemented
2020-06-07 20:01:14.032 | WARN  |     NativeCallRouter | Block by number is not implemented
2020-06-07 20:01:14.039 | WARN  |     NativeCallRouter | Block by number is not implemented

Upstream rate limiting

Allows to setup rate limiting per upstream. If there are more requests that allowed, then Dshackle should wait for finishing one of the existing before making a new request to that upstream.

Access log

Produce a text based access log compatible with Apache Combined Log format:

Apache Combined Log format is:

%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"

See also: https://httpd.apache.org/docs/2.4/logs.html

For example

 127.0.0.1 - frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326 "http://www.example.com/start.html" "Mozilla/4.08 [en] (Win98; I ;Nav)" 

Standard (apache's) fields are:

  • %h The IP address of the client.
  • %l The identity of the client determined by identd on the client's machine. Will return a hyphen (-) if this information is not available.
  • %u The userid of the client if the request was authenticated.
  • %t The time that the request was received.
  • \"%r\" The request line that includes the HTTP method used, the requested resource path, and the HTTP protocol that the client used.
  • %>s The status code that the server sends back to the client.
  • %bThe size of the object requested.

Our changes:

  • %u is an serial number of the remote TLS certificate, if TLS auth was used
  • %r (request line) would contain blockchain + method, and type of the protocol may be HTTP/2+gRPC
  • %{Referer} is a particular request id + response index, i.e. for batched queries and streaming response

Log lines are added on response, and there could be multiple logs per one requests (batches, stream, etc).

Examples:

10.5.0.1 - 53f7446780fa803819da231f4068b25e [10/Jul/2020:13:55:36 +0000] "POST /ethereum/SubscribeBalance HTTP/2+gRPC" 200 2326 "a38ef37e4a53e852748b301370c710d7/5" "MyClient/1.0" 

Which means that:

  • a client from IP 10.5.0.1
  • authenticated with certificate 53:f7:44:67:80:fa:80:38:19:da:23:1f:40:68:b2:5e
  • using software MyClient/1.0
  • made request to subscribe balance on Ethereum blockchain
    • with original id a38ef37e4a53e852748b301370c710d7
    • and current line represent response number 5
  • uses gRPC protocol with HTTP2
  • request was successful and the current response was 2326 bytes

IllegalStateException: No executor delegate for eth_getLogs

Tried dshackle for a load balancer in several ETH2.0 clients (Lighthouse, Teku, Nimbus) and got this error: "IllegalStateException: No executor delegate for eth_getLogs". The host was Ubuntu 20.04.1. In spite of the error, it seems like working but the long java error message in the log (journalctl) is really annoying. I am attaching the yaml conf file and full log below.

Beside the error, it generates too many unnecessary requests and consumes up the free tier allowance of Infura and Alchemy. It would be great if there was an option for "minimal requests". I appreciate this project and it has a very good potential for the load balancer of ETH2.0 clients since this is the only one available at the moment. Thank you.

DshackleYaml.txt
DshackleErrorLog.txt

New Release?

Any chance we can get a release soon? The chainID issue is causing our users some grief with metamask.

Not sure how 0.9 is coming but maybe an interim release?

Actual version in RPC

Answer with actual version for getnetworkinfo/web3_clientVersion request

The actual version is generated on build by Gradle and stored in version.properties in classpath

Prysm Beacon Node Compatability

I was wondering if you could look into why prysm cannot use dshackle as its ETH1 target.

In the prysm config I used:
http-web3provider: "http://dshackle:8545/eth"

For dshackle I'm simply pointing to infrua's goerli endpoint.

dshackle provides no errors or indication of failure and it is working just fine with Infura configured, but prysm throws a single error on startup:

time="2020-08-18 16:29:09" level=error msg="Could not connect to powchain endpoint" error="could not dial eth1 nodes: json: cannot unmarshal number into Go value of type string" prefix=powchain

Not sure if this is a prysm issue or a dshackle issue but I thought I would start here.

If I point prysm at the same infura endpoint, it works just fine.

Fallback when all other nodes are "SYNCING"

I'm not sure if this is the behavior I'm seeing or not, but...

I have 1 local node and 1 fallback node (Infura)

When my local node is restarted, it seems to drop back a few hundred blocks or so...so it's in the "SYCNING" stage for a little while (maybe 10 minutes?)

It seems like dshackle doesn't fallback onto the fallback node in this case. I'm not sure how to validate my suspicion? I was hoping you might know the expected behavior...

On a side note, is there a way to turn on additional logging? To see what requests are sent to what node? Thanks

WebSocket Proxy support

How do I connect to the dshackle by WebSocket? It works fine with http, but I need to connect to the dshackle by ws.

"eth_chainId" call returns 0x0 when actual node responds with 0x1

First, I had to add "eth_chainId" method to dshackle.yaml file. The documentation does not tell how to define multiple methods, so I tried many different ways, like just using multiple lines of "-name:" or something like this:

      methods:
        enabled:
          - name: eth_chainId
      methods:
        enabled:
          - name: eth_getLogs

Dshackle runs fine without error message. But when I test with

curl -X POST --insecure -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_chainId","params":[], "id":64}' http://localhost:8080/eth

the response was

{"jsonrpc":"2.0","id":64,"result":"0x0"}

, which is different from actual node(Infura)'s response to the same query (0x1). This error is preventing me from using dshackle as an eth1 load balance for eth2 client. This never happened before the eth2.0 client's (Teku) mainnet version (which was published today). I assume the previous versions of Teku did not call "eth_chainId" method.

Exception encountered during context initialization

docker tag 0.9.0

2020-01-12 02:50:17.891 | WARN  | igApplicationContext | Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'grpcServer': Invocation of init method failed; nested exception is java.lang.NoSuchMethodError: 'io.grpc.Deadline$Ticker io.grpc.Deadline.getSystemTicker()'

2020-01-12 02:50:17.910 | ERROR |    SpringApplication | Application run failed
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) [spring-boot-2.1.4.RELEASE.jar:2.1.4.RELEASE]
Caused by: java.lang.NoSuchMethodError: 'io.grpc.Deadline$Ticker io.grpc.Deadline.getSystemTicker()'
at io.grpc.netty.NettyServerBuilder.<init>(NettyServerBuilder.java:133) ~[grpc-netty-1.25.0.jar:1.25.0]
at io.emeraldpay.dshackle.GrpcServer.start(GrpcServer.kt:52) ~[classes/:?]
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:307) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'grpcServer': Invocation of init method failed; nested exception is java.lang.NoSuchMethodError: 'io.grpc.Deadline$Ticker io.grpc.Deadline.getSystemTicker()'
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:849) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) [spring-boot-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:307) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
... 15 more

2020-01-12 02:48:08.655 | ERROR |    SpringApplication | Application run failed
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at io.grpc.netty.NettyServerBuilder.forAddress(NettyServerBuilder.java:124) ~[grpc-netty-1.25.0.jar:1.25.0]
at io.emeraldpay.dshackle.GrpcServer.start(GrpcServer.kt:52) ~[classes/:?]
at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:307) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:414) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:139) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) [spring-boot-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at io.grpc.netty.NettyServerBuilder.forAddress(NettyServerBuilder.java:124) ~[grpc-netty-1.25.0.jar:1.25.0]
at java.lang.reflect.Method.invoke(Method.java:567) ~[?:?]
... 15 more
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:136) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]

2020-01-12 02:48:08.373 | INFO  |           GrpcServer | Listening Native gRPC on 127.0.0.1:2449
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'grpcServer': Invocation of init method failed; nested exception is java.lang.NoSuchMethodError: 'io.grpc.Deadline$Ticker io.grpc.Deadline.getSystemTicker()'
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1770) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) [spring-boot-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:849) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at io.grpc.internal.AbstractServerImplBuilder.<init>(AbstractServerImplBuilder.java:82) ~[grpc-core-1.25.0.jar:1.25.0]
at java.lang.reflect.Method.invoke(Method.java:567) ~[?:?]
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:363) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at io.emeraldpay.dshackle.GrpcServer.start(GrpcServer.kt:52) ~[classes/:?]
at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
... 15 more

2020-01-12 02:51:29.499 | ERROR |    SpringApplication | Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'grpcServer': Invocation of init method failed; nested exception is java.lang.NoSuchMethodError: 'io.grpc.Deadline$Ticker io.grpc.Deadline.getSystemTicker()'
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:414) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:849) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at io.grpc.internal.AbstractServerImplBuilder.<init>(AbstractServerImplBuilder.java:82) ~[grpc-core-1.25.0.jar:1.25.0]
Caused by: java.lang.NoSuchMethodError: 'io.grpc.Deadline$Ticker io.grpc.Deadline.getSystemTicker()'
at io.grpc.netty.NettyServerBuilder.forAddress(NettyServerBuilder.java:124) ~[grpc-netty-1.25.0.jar:1.25.0]

Dynamically create and remove upstreams?

Hi,

First of all, this is a super awesome project & exactly what I've been looking for in the last few weeks - it was a difficult one to find!

At the moment, as far as I can see, dshackle has support for a static list of upstreams as defined in a yaml file, but there's no way to remove upstreams or add them depending on application load/etc. Would such a feature be beneficial to the project?

If so, I'd be quite interested in implementing.

eth_getBlockByNumber should accept latest

In Ethereum spec for eth_getBlockByNumber:

Quantity or Tag - integer of a block number, or the string 'earliest', 'latest' or 'pending'

But it fails with

2020-30-06 04:04:50.623 | WARN | WriteRpcJson | Failed to convert to JSON

io.emeraldpay.dshackle.rpc.NativeCall$CallFailure: Failed to call 0: RPC Error -32602: [0] must be block number

Turbo-Geth Websocket error

This one is kind of strange. I have a Turbo-Geth node configured and sync'd but if I use websocket I get the following error:

2020-23-08 20:37:56.518 | INFO  |  ConfiguredUpstreams | Using Ethereum upstream, at http://192.168.15.34:8545, ws://192.168.15.34:8545
2020-23-08 20:37:56.531 | INFO  | WsFactory$EthereumWs | Connecting to WebSocket: ws://192.168.15.34:8545
io.netty.handler.codec.http.websocketx.WebSocketHandshakeException: Invalid handshake response getStatus: 200 OK
	at io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker13.verify(WebSocketClientHandshaker13.java:191)
	at io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker.finishHandshake(WebSocketClientHandshaker.java:216)
	at io.netty.handler.codec.http.websocketx.WebSocketClientProtocolHandshakeHandler.channelRead(WebSocketClientProtocolHandshakeHandler.java:57)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436)
	at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:323)
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:297)
	at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:834)
2020-23-08 20:37:56.606 | INFO  |     EthereumUpstream | Configured for Ethereum
2020-23-08 20:37:56.642 | INFO  | entMultistreamHolder | Upstream turbogeth with chain ETHEREUM has been added

I'm not sure if this is something strange with dshackle or if Turbo-Geth is doing something weird.

The Turbo-Geth team hasn't done extensive WebSocket testing, I know that much. But the error is strange to me.

Maybe you have an idea?

Respond with error on invalid request

If a non-POST request is made to Proxy, then respond with 405 and a text message describing that a POST with application/json should be used instead.

disable / enable method wildcard?

Is it possible to enable or disable methods via wildcard?

e.g. I want to disable:
debug_*

or I want to enable:
trace_*

I'm guessing that if I don't enable the debug_* then they won't be enabled anyway...?

Connection reset by peer

Recently, I've noticed a huge flurry of errors that look like this:

2020-22-09 23:46:34.077 | WARN  |          FluxReceive | [id: 0x228b9b97, L:/172.19.0.3:8545 - R:/172.19.0.5:34856] An exception has been observed post termination, use DEBUG level to see the full stack: io.netty.channel.unix.Errors$NativeIoException: syscall:read(..) failed: Connection reset by peer

Any ideas?

Error creating bean with name 'proxyStarter'

I'm running this on Ubuntu 18.04

sudo docker run -p 2449:2449 -p 8545:8545 -v /etc/dshackle:/etc/dshackle -e "INFURA_USER=$INFURA_USER" emeraldpay/dshackle

Emerald Dshackle - Smart Load Balancer for Blockchain API
   https://github.com/emeraldpay/dshackle
   v0.6.0 built from e3b512ca80 on 2020-04-10T01:30:41 UTC
...
16:14:22.107 [main                ] WARN                  TlsSetup | Using insecure transport for proxy
16:14:22.150 [main                ] WARN  ConfigApplicationContext | Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'proxyStarter': Invocation of init method failed; nested exception is java.lang.NoSuchMethodError: io.netty.channel.SingleThreadEventLoop.<init>(Lio/netty/channel/EventLoopGroup;Ljava/util/concurrent/Executor;ZLjava/util/Queue;Ljava/util/Queue;Lio/netty/util/concurrent/RejectedExecutionHandler;)V
16:14:22.150 [main                ] INFO                GrpcServer | Shutting down GRPC Server...
16:14:22.155 [main                ] INFO                GrpcServer | GRPC Server shot down
16:14:22.165 [main                ] ERROR gFailureAnalysisReporter |

***************************
APPLICATION FAILED TO START
***************************

Description:

An attempt was made to call a method that does not exist. The attempt was made from the following location:

    io.netty.channel.epoll.EpollEventLoop.<init>(EpollEventLoop.java:90)

The following method did not exist:

    io.netty.channel.SingleThreadEventLoop.<init>(Lio/netty/channel/EventLoopGroup;Ljava/util/concurrent/Executor;ZLjava/util/Queue;Ljava/util/Queue;Lio/netty/util/concurrent/RejectedExecutionHandler;)V

The method's class, io.netty.channel.SingleThreadEventLoop, is available from the following locations:

    jar:file:/app/libs/netty-transport-4.1.34.Final.jar!/io/netty/channel/SingleThreadEventLoop.class
    jar:file:/app/libs/netty-all-4.1.48.Final.jar!/io/netty/channel/SingleThreadEventLoop.class

It was loaded from the following location:

    file:/app/libs/netty-transport-4.1.34.Final.jar


Action:

Correct the classpath of your application so that it contains a single, compatible version of io.netty.channel.SingleThreadEventLoop

Fails to parse JSON RPC without params

JSON RPC spec says:

params [...] This member MAY be omitted.

But it fails with:

2020-30-06 03:25:11.752 | ERROR | HttpServerOperations | [id: 0x7d33d59c, L:/172.18.0.3:8080 - R:/172.18.0.1:50322] Error finishing response. Closing connection
io.infinitape.etherjar.rpc.RpcException: RPC Error -32700: null cannot be cast to non-null type kotlin.collections.List<*>
at io.emeraldpay.dshackle.proxy.ReadRpcJson.apply(ReadRpcJson.kt:143) ~[classes/:?]
at io.emeraldpay.dshackle.proxy.ReadRpcJson.apply(ReadRpcJson.kt:39) ~[classes/:?]

io.netty.channel.unix.Errors$NativeIoException

I'm getting a bunch of this:

2020-30-06 18:58:00.549 | INFO  |          Multistream | State of ETH: height=10368870, status=OK/1, lag=[0]
2020-30-06 18:58:02.092 | WARN  |          FluxReceive | [id: 0xc3337b70, L:/172.18.0.2:8545 - R:/172.18.0.3:51916] An exception has been observed post termination, use DEBUG level to see the full stack: io.netty.channel.unix.Errors$NativeIoException: syscall:read(..) failed: Connection reset by peer
2020-30-06 18:58:04.091 | WARN  |          FluxReceive | [id: 0x70fa5ed0, L:/172.18.0.2:8545 - R:/172.18.0.3:51924] An exception has been observed post termination, use DEBUG level to see the full stack: io.netty.channel.unix.Errors$NativeIoException: syscall:read(..) failed: Connection reset by peer
2020-30-06 18:58:06.091 | WARN  |          FluxReceive | [id: 0xe7d27566, L:/172.18.0.2:8545 - R:/172.18.0.3:51932] An exception has been observed post termination, use DEBUG level to see the full stack: io.netty.channel.unix.Errors$NativeIoException: syscall:read(..) failed: Connection reset by peer
2020-30-06 18:58:06.657 | WARN  |          FluxReceive | [id: 0x444b2e83, L:/172.18.0.2:8545 - R:/31.7.187.202:46996] An exception has been observed post termination, use DEBUG level to see the full stack: io.netty.channel.unix.Errors$NativeIoException: syscall:read(..) failed: Connection reset by peer
2020-30-06 18:58:08.095 | WARN  |          FluxReceive | [id: 0x446b1c36, L:/172.18.0.2:8545 - R:/172.18.0.3:51942] An exception has been observed post termination, use DEBUG level to see the full stack: io.netty.channel.unix.Errors$NativeIoException: syscall:read(..) failed: Connection reset by peer
2020-30-06 18:58:08.831 | WARN  |          FluxReceive | [id: 0x8cb459ec, L:/172.18.0.2:8545 - R:/31.7.187.202:47006] An exception has been observed post termination, use DEBUG level to see the full stack: io.netty.channel.unix.Errors$NativeIoException: syscall:read(..) failed: Connection reset by peer

I'm not sure what could be causing it...or how to check / turn on debug?

Filter Requests

I'm wondering how dshackle handles requests for eth filter methods.

I'm not an expert here but my basic understanding of how this works is:

User creates a filter with eth_newFilter or eth_newPendingTransactionFilter etc. and the return value is an index. The user then calls eth_getFilterLogs or something similar and provides the index number.

It is my understanding that this filter index is unique to the ETH1 node.

How does dshackle handle this? Does dshackle track those indexes internally? I don't think it does... Does dshackle sticky the filter requests? I don't know / I don't think it does...?

I've currently stapled the filter commands to a single node using the enabled methods in the config, but if that nodes goes down we loose the ability to run any filter commands.

Documentation of `cluster` and Load Balancing

I'm confused about the use of cluster keyword, as well as how to actually load balance between nodes. The docs only talk about a single Infura connection for the most part...

  • In the README you use cluster: to define upstreams.
  • The README states the following incorrectly (I think?):

two upstreams, one for Ethereum Mainnet and another for Kovan Testnet (both upstreams are configured to use Infura endpoint)

The only part of that config that references kovan is

- chains:
  - kovan

But the infura connections are all mainnet

  • Under Server Config documentation you use:
cluster:
  include: "upstreams.yaml"
  • You then use this under the enable JSON section:
upstreams:
  config: "upstreams.yaml"
  • Under the Upstream Config document you don't make use of the cluster keyword at all.

I also can't find a single example of how you actually handle load balancing

Empty result for eth_call?

I've had a user report that they're having issues with eth_call being reverted again.

I see this in the logs:

WARN  |      QuorumRpcReader | Empty result for eth_call as io.emeraldpay.dshackle.quorum.AlwaysQuorum@84b8c47

I'm wondering if it's related?

We recently started adding Geth and Turbo-Geth into our setup and I noticed that when making eth_call that gets reverted, Nethermind has a "data" field, but Geth and Turbo-Geth do not and I wonder if that has something to do with it?

Just seems weird.

The user is getting back:

"error": {
        "code": -32002,
        "message": "No response or no available upstream for eth_call"
    }

Which I know is a dshackle error message, even though all of our nodes are configured for eth_call and making manual calls works fine.

Example curl used to test with:

curl -s -H 'Content-Type: application/json' --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"data":"0x06fdde03","to":"0x1f0d3048b3d49de0ed6169a443dbb049e6daa6ce"},{"blockHash":"0xa5626dc20d3a0a209b1de85521717a3e859698de8ce98bca1b16822b7501f74b"}],"id":1}'

Geth and Turbo-Geth:

{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "execution reverted"
  }
}

Nethermind:

{
  "jsonrpc": "2.0",
  "error": {
    "code": -32015,
    "message": "VM execution error.",
    "data": "revert"
  },
  "id": 1
}

Everything is 404 Errors

Config:

host: 0.0.0.0
port: 2449
tls:
  enabled: false

proxy:
  host: 0.0.0.0
  port: 8545
  tls:
    enabled: false
  routes:
    - id: eth
      blockchain: ethereum

cluster:
  defaults:
    - chains:
        - ethereum
      options:
        min-peers: 10
  upstreams:
    - id: nethermind01
      chain: ethereum
      labels:
        provider: nethermind
      connection:
        ethereum:
          rpc:
            url: "http://192.168.15.31:8545"
    - id: nethermind02
      chain: ethereum
      labels:
        provider: nethermind
      connection:
        ethereum:
          rpc:
            url: "http://192.168.15.32:8545"

Docker:

CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS                                                      NAMES
73b625113ab7        emeraldpay/dshackle   "java -Xms1024m -cp …"   2 days ago          Up About a minute   0.0.0.0:2449->2449/tcp, 0.0.0.0:8545->8545/tcp, 8090/tcp   stupefied_feistel

Startup:

2020-30-05 18:50:03.175 | INFO  |               Config | Using config: /etc/dshackle/dshackle.yaml
2020-30-05 18:50:03.671 | INFO  |           GrpcServer | Starting gRPC Server...
2020-30-05 18:50:03.672 | INFO  |           GrpcServer | Listening Native gRPC on 0.0.0.0:2449
2020-30-05 18:50:03.726 | WARN  |             TlsSetup | Using insecure transport for Native gRPC
2020-30-05 18:50:04.087 | INFO  |           GrpcServer | GRPC Server started
2020-30-05 18:50:04.106 | INFO  |          ProxyServer | Listening Proxy on 0.0.0.0:8545
2020-30-05 18:50:04.139 | WARN  |             TlsSetup | Using insecure transport for proxy
2020-30-05 18:50:04.412 | INFO  |  ConfiguredUpstreams | Using Ethereum upstream, at http://192.168.15.31:8545
2020-30-05 18:50:04.415 | WARN  |     EthereumUpstream | Setting up upstream nethermind01 with RPC-only access, less effective than WS+RPC
2020-30-05 18:50:04.449 | INFO  |     EthereumUpstream | Configured for Ethereum
2020-30-05 18:50:04.482 | INFO  | entMultistreamHolder | Upstream nethermind01 with chain ETHEREUM has been added
2020-30-05 18:50:04.483 | INFO  |  ConfiguredUpstreams | Using Ethereum upstream, at http://192.168.15.32:8545
2020-30-05 18:50:04.484 | WARN  |     EthereumUpstream | Setting up upstream nethermind02 with RPC-only access, less effective than WS+RPC
2020-30-05 18:50:04.487 | INFO  |     EthereumUpstream | Configured for Ethereum
2020-30-05 18:50:04.506 | INFO  | entMultistreamHolder | Upstream nethermind02 with chain ETHEREUM has been added
2020-30-05 18:50:05.199 | INFO  |            StarterKt | Started StarterKt in 5.503 seconds (JVM running for 6.843)
2020-30-05 18:50:06.193 | INFO  |          Multistream | State of ETH: height=?, status=UNAVAILABLE/2, lag=[0, 9223372036854775807]
2020-30-05 18:50:20.190 | INFO  |          Multistream | State of ETH: height=10168859, status=OK/2, lag=[0, 0]

curl command:

curl --url http://localhost:8545/eth -v
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8545 (#0)
> GET /eth HTTP/1.1
> Host: localhost:8545
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 404 Not Found
< content-length: 0
<
* Connection #0 to host localhost left intact

curl command to actual node:

curl http://192.168.15.32:8545 -v
* Rebuilt URL to: http://192.168.15.32:8545/
*   Trying 192.168.15.32...
* TCP_NODELAY set
* Connected to 192.168.15.32 (192.168.15.32) port 8545 (#0)
> GET / HTTP/1.1
> Host: 192.168.15.32:8545
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Sat, 30 May 2020 18:52:09 GMT
< Server: Kestrel
< Transfer-Encoding: chunked
<
* Connection #0 to host 192.168.15.32 left intact
Nethermind JSON RPC

Out of Memory Errors with large debug_traceTransaction

Sometimes, but not always, dshackle will crash with out of memory errors dealing with large replies.

2021-09-01 16:56:14.243 | WARN  | hannelHandlerContext | An exception 'java.lang.OutOfMemoryError: Cannot reserve 16777216 bytes of direct buffer memory (allocated: 1544208392, limit: 1560281088)' [enable DEBUG level for full stacktrace] was thrown by a user handler's exceptionCaught() method while handling the following exception:
 at io.netty.buffer.PoolArena$DirectArena.allocateDirect(PoolArena.java:768) ~[netty-buffer-4.1.34.Final.jar:4.1.34.Final]
 at io.netty.buffer.PoolArena.allocate(PoolArena.java:227) ~[netty-buffer-4.1.34.Final.jar:4.1.34.Final]
 at io.netty.buffer.CompositeByteBuf.addComponents(CompositeByteBuf.java:444) ~[netty-buffer-4.1.34.Final.jar:4.1.34.Final]
 at reactor.netty.ByteBufFlux.lambda$aggregate$7(ByteBufFlux.java:271) ~[reactor-netty-0.9.7.RELEASE.jar:0.9.7.RELEASE]
 at reactor.netty.channel.ChannelOperations.terminate(ChannelOperations.java:423) ~[reactor-netty-0.9.7.RELEASE.jar:0.9.7.RELEASE]
 at reactor.core.publisher.MonoCollectList$MonoCollectListSubscriber.onComplete(MonoCollectList.java:121) ~[reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
 at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:96) ~[reactor-netty-0.9.7.RELEASE.jar:0.9.7.RELEASE]
 at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
 at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
 at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
 at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989) [netty-common-4.1.49.Final.jar:4.1.49.Final]

2021-09-01 16:56:14.239 | ERROR | nelOperationsHandler | [id: 0xdbe38e68, L:/172.22.0.3:60014 - R:archive01.archivenode.io/104.227.245.82:8545] Error was received while reading the incoming data. The connection will be closed.
 at io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:187) ~[netty-buffer-4.1.34.Final.jar:4.1.34.Final]
 at io.netty.buffer.CompositeByteBuf.allocBuffer(CompositeByteBuf.java:1751) ~[netty-buffer-4.1.34.Final.jar:4.1.34.Final]
 at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
 at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
 at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
 at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
 at io.netty.channel.epoll.AbstractEpollStreamChannel$EpollStreamUnsafe.epollInReady(AbstractEpollStreamChannel.java:796) [netty-transport-native-epoll-4.1.34.Final-linux-x86_64.jar:4.1.34.Final]
 at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:328) [netty-transport-native-epoll-4.1.34.Final-linux-x86_64.jar:4.1.34.Final]
 at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) [netty-common-4.1.49.Final.jar:4.1.49.Final]
java.lang.OutOfMemoryError: Cannot reserve 16777216 bytes of direct buffer memory (allocated: 1544208392, limit: 1560281088)
 at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) [netty-common-4.1.49.Final.jar:4.1.49.Final]
 at java.nio.Bits.reserveMemory(Bits.java:178) ~[?:?]
 at io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:187) ~[netty-buffer-4.1.34.Final.jar:4.1.34.Final]
 at io.netty.buffer.PooledByteBufAllocator.newDirectBuffer(PooledByteBufAllocator.java:327) ~[netty-buffer-4.1.34.Final.jar:4.1.34.Final]
 at io.netty.buffer.PoolArena.allocate(PoolArena.java:147) ~[netty-buffer-4.1.34.Final.jar:4.1.34.Final]
 at io.netty.buffer.CompositeByteBuf.consolidateIfNeeded(CompositeByteBuf.java:459) ~[netty-buffer-4.1.34.Final.jar:4.1.34.Final]
 at io.netty.buffer.CompositeByteBuf.allocBuffer(CompositeByteBuf.java:1751) ~[netty-buffer-4.1.34.Final.jar:4.1.34.Final]
 at reactor.core.publisher.FluxHandleFuseable$HandleFuseableSubscriber.onNext(FluxHandleFuseable.java:163) ~[reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
 at io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:178) ~[netty-buffer-4.1.34.Final.jar:4.1.34.Final]
 at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1755) ~[reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
 at reactor.netty.channel.ChannelOperations.onInboundComplete(ChannelOperations.java:367) ~[reactor-netty-0.9.7.RELEASE.jar:0.9.7.RELEASE]
 at reactor.netty.http.client.HttpClientOperations.onInboundNext(HttpClientOperations.java:607) ~[reactor-netty-0.9.7.RELEASE.jar:0.9.7.RELEASE]
 at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
 at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:297) [netty-codec-4.1.34.Final.jar:4.1.34.Final]
 at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
 at io.netty.channel.epoll.EpollEventLoop.processReady(EpollEventLoop.java:427) [netty-transport-native-epoll-4.1.34.Final-linux-x86_64.jar:4.1.34.Final]
 at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:328) [netty-transport-native-epoll-4.1.34.Final-linux-x86_64.jar:4.1.34.Final]
 at java.lang.Thread.run(Thread.java:830) [?:?]
 at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) [netty-common-4.1.49.Final.jar:4.1.49.Final]
 at java.nio.Bits.reserveMemory(Bits.java:178) ~[?:?]
 at io.netty.buffer.PoolArena.allocate(PoolArena.java:227) ~[netty-buffer-4.1.34.Final.jar:4.1.34.Final]
 at io.netty.buffer.PoolArena.allocate(PoolArena.java:147) ~[netty-buffer-4.1.34.Final.jar:4.1.34.Final]
 at reactor.core.publisher.MonoCollectList$MonoCollectListSubscriber.onComplete(MonoCollectList.java:121) ~[reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
 at reactor.netty.channel.FluxReceive.onInboundComplete(FluxReceive.java:366) ~[reactor-netty-0.9.7.RELEASE.jar:0.9.7.RELEASE]
 at reactor.netty.http.client.HttpClientOperations.onInboundNext(HttpClientOperations.java:607) ~[reactor-netty-0.9.7.RELEASE.jar:0.9.7.RELEASE]
 at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:297) [netty-codec-4.1.34.Final.jar:4.1.34.Final]
 at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
 at java.lang.Thread.run(Thread.java:830) [?:?]
 at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:119) ~[?:?]
 at io.netty.buffer.PoolArena.allocateNormal(PoolArena.java:245) ~[netty-buffer-4.1.34.Final.jar:4.1.34.Final]
 at io.netty.buffer.PoolArena$DirectArena.newChunk(PoolArena.java:744) ~[netty-buffer-4.1.34.Final.jar:4.1.34.Final]
 at reactor.core.publisher.FluxContextStart$ContextStartSubscriber.onNext(FluxContextStart.java:96) ~[reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
 at reactor.netty.channel.FluxReceive.onInboundComplete(FluxReceive.java:366) ~[reactor-netty-0.9.7.RELEASE.jar:0.9.7.RELEASE]
 at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:136) ~[reactor-core-3.3.5.RELEASE.jar:3.3.5.RELEASE]
 at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
 at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
 at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:323) [netty-codec-4.1.34.Final.jar:4.1.34.Final]
 at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
 at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
 at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) [netty-transport-4.1.49.Final.jar:4.1.49.Final]

The output from the node is just under 4MB in size

curl -H 'Content-Type: application/json' --data '{"jsonrpc":"2.0","method":"debug_traceTransaction","params": ["0x391aa8c844664ea4ab596ee1ce83fb0b7053ecfad138386073d72304aa6c8cec"],"id":73}'

The docker host itself seems to have plenty of RAM...

mysticryuujin@docker01:~$ free -h
              total        used        free      shared  buff/cache   available
Mem:          5.8Gi       4.2Gi       354Mi       7.0Mi       1.2Gi       1.3Gi
Swap:         2.0Gi       3.0Mi       2.0Gi

Unexpected end-of-input

Got another interesting error. This time, while using 2 Nethermind nodes, and 1 Geth node...

Config:

host: 0.0.0.0
port: 2449
tls:
  enabled: true
  server:
   certificate: "/etc/dshackle/dshackle.crt"
   key: "/etc/dshackle/dshackle.key"
  client:
    require: false

cache:
  redis:
    enabled: true
    host: 192.168.10.50
    port: 6379
    db: 0
    password: "redacted"

proxy:
  host: 0.0.0.0
  port: 8545
  tls:
    enabled: true
    server:
      certificate: "/etc/dshackle/dshackle.crt"
      key: "/etc/dshackle/dshackle.key"
    client:
      require: false
  routes:
    - id: eth
      blockchain: ethereum

cluster:
  defaults:
    - chains:
        - ethereum
      options:
        min-peers: 10
  upstreams:
    - id: nethermind01
      chain: ethereum
      labels:
        provider: nethermind
        nodetype: full
      methods:
        enabled:
          - name: admin_nodeInfo
          - name: admin_peers
          - name: trace_block
          - name: trace_rawTransaction
          - name: trace_replayBlockTransactions
          - name: trace_replayTransaction
          - name: trace_transaction
      connection:
        ethereum:
          rpc:
            url: "http://192.168.15.31:8545"
          ws:
            url: "ws://192.168.15.31:8545/ws/json-rpc"
    - id: nethermind02
      chain: ethereum
      labels:
        provider: nethermind
        nodetype: full
      methods:
        enabled:
          - name: admin_nodeInfo
          - name: admin_peers
          - name: trace_block
          - name: trace_rawTransaction
          - name: trace_replayBlockTransactions
          - name: trace_replayTransaction
          - name: trace_transaction
      connection:
        ethereum:
          rpc:
            url: "http://192.168.15.32:8545"
          ws:
            url: "ws://192.168.15.32:8545/ws/json-rpc"
    - id: geth03
      chain: ethereum
      labels:
        provider: geth
        nodetype: full
      methods:
        enabled:
          - name: admin_nodeInfo
          - name: admin_peers
      connection:
        ethereum:
          rpc:
            url: "http://192.168.10.50:8545"
          ws:
            url: "ws://192.168.10.50:8545"

Errors:

v0.7.2 built from 881c8c66d7 on 2020-07-03T02:53:12 UTC

2020-06-07 23:58:13.954 | INFO  |            StarterKt | Starting StarterKt on a9b0c2779aa8 with PID 1 (/app/classes started by root in /)
2020-06-07 23:58:13.958 | INFO  |            StarterKt | No active profile set, falling back to default profiles: default
2020-06-07 23:58:15.962 | INFO  |               Config | Using config: /etc/dshackle/dshackle.yaml
2020-06-07 23:58:16.097 | INFO  |        CachesFactory | Use Redis cache at: redis://192.168.10.50
2020-06-07 23:58:16.914 | INFO  |        CachesFactory | Connection to Redis established
2020-06-07 23:58:17.098 | INFO  |           GrpcServer | Starting gRPC Server...
2020-06-07 23:58:17.098 | INFO  |           GrpcServer | Listening Native gRPC on 0.0.0.0:2449
2020-06-07 23:58:17.146 | INFO  |             TlsSetup | Using TLS for Native gRPC
2020-06-07 23:58:17.268 | WARN  |             TlsSetup | Trust all clients for Native gRPC
2020-06-07 23:58:17.977 | INFO  |           GrpcServer | GRPC Server started
2020-06-07 23:58:17.993 | INFO  |          ProxyServer | Listening Proxy on 0.0.0.0:8545
2020-06-07 23:58:18.012 | INFO  |             TlsSetup | Using TLS for proxy
2020-06-07 23:58:18.016 | WARN  |             TlsSetup | Trust all clients for proxy
2020-06-07 23:58:18.301 | INFO  |  ConfiguredUpstreams | Using Ethereum upstream, at http://192.168.15.31:8545, ws://192.168.15.31:8545/ws/json-rpc
2020-06-07 23:58:18.305 | INFO  | WsFactory$EthereumWs | Connecting to WebSocket: ws://192.168.15.31:8545/ws/json-rpc
2020-06-07 23:58:18.406 | INFO  |     EthereumUpstream | Configured for Ethereum
2020-06-07 23:58:18.519 | INFO  | entMultistreamHolder | Upstream nethermind01 with chain ETHEREUM has been added
2020-06-07 23:58:18.519 | INFO  |  ConfiguredUpstreams | Using Ethereum upstream, at http://192.168.15.32:8545, ws://192.168.15.32:8545/ws/json-rpc
2020-06-07 23:58:18.520 | INFO  | WsFactory$EthereumWs | Connecting to WebSocket: ws://192.168.15.32:8545/ws/json-rpc
2020-06-07 23:58:18.600 | INFO  |     EthereumUpstream | Configured for Ethereum
2020-06-07 23:58:18.701 | INFO  | entMultistreamHolder | Upstream nethermind02 with chain ETHEREUM has been added
2020-06-07 23:58:18.702 | INFO  |  ConfiguredUpstreams | Using Ethereum upstream, at http://192.168.10.50:8545, ws://192.168.10.50:8545
2020-06-07 23:58:18.703 | INFO  | WsFactory$EthereumWs | Connecting to WebSocket: ws://192.168.10.50:8545
Socket closed with Method eth_subscribe is not supported
Socket closed with Method eth_subscribe is not supported
2020-06-07 23:58:18.878 | INFO  |     EthereumUpstream | Configured for Ethereum
2020-06-07 23:58:18.898 | INFO  | entMultistreamHolder | Upstream geth03 with chain ETHEREUM has been added
2020-06-07 23:58:19.447 | INFO  |            StarterKt | Started StarterKt in 6.0 seconds (JVM running for 7.107)
2020-06-07 23:58:20.447 | INFO  |          Multistream | State of ETH: height=?, status=UNAVAILABLE/3, lag=[0, 9223372036854775807, 9223372036854775807]
com.fasterxml.jackson.core.io.JsonEOFException: Unexpected end-of-input: was expecting closing quote for a string value
 at [Source: (String)"{"jsonrpc":"2.0","method":"eth_subscription","params":{"subscription":"0x86bb7eb8c90ebc5a084f3d8438f0f561","result":{"parentHash":"0x08772ca73c76a47a2df83ea8de1d25fe6dbab6e21727c0fdb3a2e15991d55669","sha3Uncles":"0x824b0642ab3bf875a3a72317e46ab640bd04188321609a38d00dc64c547bd01a","miner":"0x005e288d713a5fb3d7c9cf1b43810a98688c7223","stateRoot":"0x60ef429cff1253cc7b2177852edd1fc672c1b1b683c9c8f14741119bc79458eb","transactionsRoot":"0x46f4623816019a3b7a521a3575ab95856e7b82315599ba39dd974f40647be98"[truncated 524 chars]; line: 1, column: 2049]
        at com.fasterxml.jackson.core.base.ParserMinimalBase._reportInvalidEOF(ParserMinimalBase.java:618)
        at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._finishString2(ReaderBasedJsonParser.java:2037)
        at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._finishString(ReaderBasedJsonParser.java:2024)
        at com.fasterxml.jackson.core.json.ReaderBasedJsonParser.getText(ReaderBasedJsonParser.java:278)
        at com.fasterxml.jackson.databind.deser.std.BaseNodeDeserializer.deserializeObject(JsonNodeDeserializer.java:264)
        at com.fasterxml.jackson.databind.deser.std.BaseNodeDeserializer.deserializeObject(JsonNodeDeserializer.java:255)
        at com.fasterxml.jackson.databind.deser.std.BaseNodeDeserializer.deserializeObject(JsonNodeDeserializer.java:255)
        at com.fasterxml.jackson.databind.deser.std.JsonNodeDeserializer.deserialize(JsonNodeDeserializer.java:68)
        at com.fasterxml.jackson.databind.deser.std.JsonNodeDeserializer.deserialize(JsonNodeDeserializer.java:15)
        at com.fasterxml.jackson.databind.ObjectMapper._readValue(ObjectMapper.java:3984)
        at com.fasterxml.jackson.databind.ObjectMapper.readTree(ObjectMapper.java:2384)
        at com.fasterxml.jackson.core.JsonParser.readValueAsTree(JsonParser.java:1782)
        at io.infinitape.etherjar.rpc.ws.SubscriptionJsonDeserializer.deserialize(SubscriptionJsonDeserializer.java:33)
        at io.infinitape.etherjar.rpc.ws.SubscriptionJsonDeserializer.deserialize(SubscriptionJsonDeserializer.java:29)
        at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:1611)
        at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1219)
        at io.infinitape.etherjar.rpc.ws.JacksonWsConverter.readSubscription(JacksonWsConverter.java:35)
        at io.infinitape.etherjar.rpc.ws.SocketApiHandler.channelRead0(SocketApiHandler.java:80)
        at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:99)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
        at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
        at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:93)
        at io.netty.handler.codec.http.websocketx.Utf8FrameValidator.channelRead(Utf8FrameValidator.java:77)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
        at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:323)
        at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:310)
        at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:426)
        at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:278)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
        at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
        at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
        at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:834)
io.infinitape.etherjar.rpc.RpcResponseException: Invalid response from RPC endpoint
        at io.infinitape.etherjar.rpc.ws.JacksonWsConverter.readSubscription(JacksonWsConverter.java:38)
        at io.infinitape.etherjar.rpc.ws.SocketApiHandler.channelRead0(SocketApiHandler.java:80)
        at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:99)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
        at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
        at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:93)
        at io.netty.handler.codec.http.websocketx.Utf8FrameValidator.channelRead(Utf8FrameValidator.java:77)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
        at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:323)
        at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:310)
        at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:426)
        at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:278)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
        at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
        at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
        at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: com.fasterxml.jackson.core.io.JsonEOFException: Unexpected end-of-input: was expecting closing quote for a string value
 at [Source: (String)"{"jsonrpc":"2.0","method":"eth_subscription","params":{"subscription":"0x86bb7eb8c90ebc5a084f3d8438f0f561","result":{"parentHash":"0x08772ca73c76a47a2df83ea8de1d25fe6dbab6e21727c0fdb3a2e15991d55669","sha3Uncles":"0x824b0642ab3bf875a3a72317e46ab640bd04188321609a38d00dc64c547bd01a","miner":"0x005e288d713a5fb3d7c9cf1b43810a98688c7223","stateRoot":"0x60ef429cff1253cc7b2177852edd1fc672c1b1b683c9c8f14741119bc79458eb","transactionsRoot":"0x46f4623816019a3b7a521a3575ab95856e7b82315599ba39dd974f40647be98"[truncated 524 chars]; line: 1, column: 2049]
        at com.fasterxml.jackson.core.base.ParserMinimalBase._reportInvalidEOF(ParserMinimalBase.java:618)
        at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._finishString2(ReaderBasedJsonParser.java:2037)
        at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._finishString(ReaderBasedJsonParser.java:2024)
        at com.fasterxml.jackson.core.json.ReaderBasedJsonParser.getText(ReaderBasedJsonParser.java:278)
        at com.fasterxml.jackson.databind.deser.std.BaseNodeDeserializer.deserializeObject(JsonNodeDeserializer.java:264)
        at com.fasterxml.jackson.databind.deser.std.BaseNodeDeserializer.deserializeObject(JsonNodeDeserializer.java:255)
        at com.fasterxml.jackson.databind.deser.std.BaseNodeDeserializer.deserializeObject(JsonNodeDeserializer.java:255)
        at com.fasterxml.jackson.databind.deser.std.JsonNodeDeserializer.deserialize(JsonNodeDeserializer.java:68)
        at com.fasterxml.jackson.databind.deser.std.JsonNodeDeserializer.deserialize(JsonNodeDeserializer.java:15)
        at com.fasterxml.jackson.databind.ObjectMapper._readValue(ObjectMapper.java:3984)
        at com.fasterxml.jackson.databind.ObjectMapper.readTree(ObjectMapper.java:2384)
        at com.fasterxml.jackson.core.JsonParser.readValueAsTree(JsonParser.java:1782)
        at io.infinitape.etherjar.rpc.ws.SubscriptionJsonDeserializer.deserialize(SubscriptionJsonDeserializer.java:33)
        at io.infinitape.etherjar.rpc.ws.SubscriptionJsonDeserializer.deserialize(SubscriptionJsonDeserializer.java:29)
        at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:1611)
        at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1219)
        at io.infinitape.etherjar.rpc.ws.JacksonWsConverter.readSubscription(JacksonWsConverter.java:35)
        ... 34 more
2020-06-07 23:58:35.443 | INFO  |          Multistream | State of ETH: height=?, status=OK/1,SYNCING/2, lag=[0, 9223372036854775807, 9223372036854775807]
2020-06-07 23:58:50.442 | INFO  |          Multistream | State of ETH: height=?, status=OK/1,SYNCING/2, lag=[0, 9223372036854775807, 9223372036854775807]
2020-06-07 23:59:05.442 | INFO  |          Multistream | State of ETH: height=?, status=OK/1,SYNCING/2, lag=[0, 9223372036854775807, 9223372036854775807]
2020-06-07 23:59:19.442 | INFO  |          Multistream | State of ETH: height=10408971, status=OK/3, lag=[0, 0, 0]

dshackle_error.txt

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.