= Configuration Reference
:toc:
:toclevels: 2

toc::[]

== Example

.Example configuration with most options configured
[source,yaml]
----
host: 0.0.0.0
port: 2449

tls:
  enabled: true
  server:
    certificate: "/path/127.0.0.1.crt"
    key: "/path/127.0.0.1.p8.key"
  client:
    require: true
    ca: "/path/ca.dshackle.test.crt"

monitoring:
  enabled: true
  jvm: false
  extended: false
  prometheus:
    enabled: true
    bind: 127.0.0.1
    port: 8081
    path: /metrics

health:
  port: 8082
  host: 127.0.0.1
  path: /health
  blockchains:
   - chain: ethereum
     min-availability: 1

cache:
  redis:
    enabled: true
    host: redis-master
    port: 6379
    db: 0
    password: I1y0dGKy01by

auth:
  enabled: false

proxy:
  host: 0.0.0.0
  port: 8080
  websocket: true
  preserve-batch-order: false
  tls:
    enabled: true
    server:
      certificate: "/path/127.0.0.1.crt"
      key: "/path/127.0.0.1.p8.key"
    client:
      require: true
      ca: "/path/ca.dshackle.test.crt"
  routes:
    - id: eth
      blockchain: ethereum
    - id: kovan
      blockchain: kovan

tokens:
  - id: dai
    blockchain: ethereum
    name: DAI
    type: ERC-20
    address: 0x6B175474E89094C44Da98b954EedeAC495271d0F
  - id: tether
    blockchain: ethereum
    name: Tether
    type: ERC-20
    address: 0xdac17f958d2ee523a2206206994597c13d831ec7

accessLog:
  enabled: true
  filename: /var/log/dshackle/access_log.jsonl

cluster:
  defaults:
    - chains:
        - ethereum
      options:
        min-peers: 10
    - chains:
        - kovan
      options:
        min-peers: 3
  include:
    - "upstreams-extra.yaml"
  upstreams:
    - id: local
      chain: ethereum
      labels:
        fullnode: true
      methods:
        enabled:
          - name: "parity_trace"
        disabled:
          - name: "admin_shutdown"
      connection:
        generic:
          rpc:
            url: "http://localhost:8545"
          ws:
            url: "ws://localhost:8546"
            origin: "http://localhost"
            basic-auth:
              username: 9c199ad8f281f20154fc258fe41a6814
              password: 258fe4149c199ad8f2811a68f20154fc
    - id: infura
      chain: ethereum
      options:
        disable-validation: true
      connection:
        generic:
          rpc:
            url: "https://mainnet.infura.io/v3/fa28c968191849c1aff541ad1d8511f2"
            basic-auth:
              username: 4fc258fe41a68149c199ad8f281f2015
              password: 1a68f20154fc258fe4149c199ad8f281
    - id: bitcoin
      chain: bitcoin
      options:
        # use the node to fetch balances
        balance: true
      connection:
        bitcoin:
          rpc:
            url: "http://localhost:8332"
            basic-auth:
              username: bitcoin
              password: e984af45bb888428207c290
          # use Esplora index to fetch balances and utxo for an address
          esplora:
            url: "http://localhost:3001"
          # connect via ZeroMQ to get notifications about new blocks
          zeromq:
            address: "http://localhost:5555"
    - id: remote
      connection:
        grpc:
          host: "10.2.0.15"
          tls:
            ca: /path/ca.dshackle.test.crt
            certificate: /path/client1.dshackle.test.crt
            key: /path/client1.dshackle.test.key
----

== Top level config

[cols="2a,2,5"]
|===
| Option | Default Value | Description

| `host`
| `127.0.0.0`
| Host to bind gRPC server

| `port`
| `2449`
| Port to bind gRPC server

| `tls`
|
| Setup TLS configuration for the gRPC server.
See <<tls>> section

| `monitoring`
|
| Setup Prometheus monitoring.
See <<monitoring>> section

| `health`
|
| Setup Health Check endpoint See <<health>> section

| `proxy`
|
| Setup HTTP proxy that emulates all standard JSON RPC requests.
See <<proxy>> section

| `accessLog`
|
| Configure access logging.
See <<accessLog>> section


| `tokens`
|
| Configure tokens for tracking balance.
See <<tokens>> section

| `cache`
|
| Caching configuration.
See <<cache>> section.

| `auth`
|
| Authorization and response signing.
See <<auth>> section.

| `cluster`
|
| Setup connection to remote nodes.See <<cluster>> section

|===

[#tls]
== TLS server config

[source,yaml]
----
tls:
  enabled: true
  server:
    certificate: "/path/127.0.0.1.crt"
    key: "/path/127.0.0.1.p8.key"
  client:
    require: true
    ca: "/path/ca.dshackle.test.crt"
----

[cols="2a,2,5"]
|===
| Option | Default Value | Description

| `enabled`
a| `true` if any value is set
| Enable/Disable TLS

| `server.certificate`
|
| Path to x509 certificate

| `server.key`
|
| Path to a private key to the certificate.The key _MUST BE_ in PKCS 8 format

| `client.require`
|
| If true then the server will required certificate from a client, otherwise client authentication is optional

| `client.ca`
|
| Certificate to validate client authentication

|===

[#monitoring]
== Monitoring

Configure Prometheus monitoring

[source,yaml]
----
monitoring:
  enabled: true
  jvm: false
  extended: false
  prometheus:
    enabled: true
    bind: 127.0.0.1
    port: 8081
    path: /metrics
----

[cols="2a,2a,5"]
|===
| Option | Default Value | Description

| `enabled`
| `true`
| Enable/Disable monitoring endpoint

| `jvm`
| `false`
| Enable/Disable JVM metrics (threads, GC, memory, etc)

| `extended`
| `false`
| Enable/Disable additional metrics (query selectors, etc)

| `prometheus.enabled`
| `true`
| Enable/Disable monitoring endpoint.
_Reserved for future use_, in case of multiple different types of endpoints.

| `prometheus.bind`
| `127.0.0.1`
| Host to bind the server

| `prometheus.port`
| `8081`
| Port to bind the server

| `prometheus.path`
| `/metrics`
| HTTP path to bind the server

|===

[#health]
== Health Check endpoint

[source,yaml]
----
health:
  port: 8082
  host: 127.0.0.1
  path: /health
  blockchains:
    - chain: ethereum
      min-available: 2
    - chain: bitcoin
      min-available: 1
----

[cols="2a,2a,5"]
|===
| Option | Default Value | Description

| `port`
| `8082`
| HTTP port to bind the server

| `host`
| `127.0.0.1`
| HTTP host to bind the server

| `path`
| `/health`
| HTTP path to respond on requests

| `blockchains`
|
| List of blockchains that must be available to consider the server _healthy_

| `[blockchain].chain`
|
| Blockchain id

| `[blockchain].min-available`
| 1
| How many _available_ upstreams for the blockchain is required to pass

|===

[#proxy]
== Proxy config

[source,yaml]
----
proxy:
  host: 0.0.0.0
  port: 8080
  preserve-batch-order: false
  tls:
    enabled: true
    server:
      certificate: "/path/127.0.0.1.crt"
      key: "/path/127.0.0.1.p8.key"
    client:
      require: true
      ca: "/path/ca.dshackle.test.crt"
  routes:
    - id: eth
      blockchain: ethereum
    - id: kovan
      blockchain: kovan
----

.Top config
[cols="2a,2,5"]
|===
| Option | Default Value | Description

| `host`
| `127.0.0.0`
| Host to bind HTTP server

| `port`
| `8080`
| Port to bind HTT server

| `port`
| `false`
| Should proxy preserve request-response correspondence when sending batch request via http

| `websocket`
| `true`
| Enable WebSocket Proxy

| `tls`
|
| Setup TLS configuration for the Proxy server.
See <<tls>> section

| `preserve-batch-order`
| false
| If `false` Dshackle may produce _batch_ response in different order, which is correct as per JSON RPC Spec.
If set to `true` then Dshackle preserves _batch_ order based on request order.
Note that latter is ineffective and use this option only when a client cannot reference responses by their IDs.

| `cors-origin`
|
| Access-Control-Allow-Origin contents. If empty the header will be omitted in response

| `cors-allowed-headers`
| `Content-Type`
| Access-Control-Allow-Headers contents. Takes effect only if сors-origi is present in config

| `routes`
|
a| Routing paths for Proxy.
The proxy will handle requests as `https://${HOST}:${PORT}/${ROUTE_ID}` (or `http://` if TLS is not enabled).
For WebSocket it's `wss` / `ws`, accordingly.
|===

.Route config
[cols="2a,2,5"]
|===
| Option | Default Value | Description

| `id`
|
| Internal _alphanumeric_ id, and a path of binding url - `https://${HOST}:${PORT}/${ROUTE_ID}`.

| `blockchain`
|
| A blockchain that must be used to handle that route.

|===

[#accessLog]
== Access Log config

[source,yaml]
----
accessLog:
  enabled: true
  filename: /var/log/dshackle/access_log.jsonl
----

.Access Log config
[cols="2a,3a,7"]
|===
| Option | Default | Description

| `enabled`
| `false`
| Enable/Disable Access logging

| `include-messages`
| `false`
| Include request params and response result/error (i.e., a JSON) in access log.
It's an expensive operation, use it for debugging only.
Note that for errors it provides only error message, not the error response itself.

| `filename`
| `access_log.jsonl`
| Path to the access log file

|===

[#tokens]
== Tokens config

[source,yaml]
----
tokens:
  - id: dai
    blockchain: ethereum
    name: DAI
    type: ERC-20
    address: 0x6B175474E89094C44Da98b954EedeAC495271d0F
  - id: tether
    blockchain: ethereum
    name: Tether
    type: ERC-20
    address: 0xdac17f958d2ee523a2206206994597c13d831ec7
----

Tokens config enables tracking of a balance amount in the configured tokens.
After making the configuration above you can request balance (`GetBalance`), or subscribe to balance changes (`SubscribeBalance`), using xref:07-methods.adoc[enhanced protocol]

.Token config
[cols="2a,7"]
|===
| Option | Description

| `id`
| Internal id for reference (used in logging, etc)

| `blockchain`
| An ethereum-based blockchain where the contract is deployed

| `name`
| Name of the token, used for balance response as asset code (as converted to UPPERCASE)

| `type`
| Type of token.Only `ERC-20` is supported at this moment

| `address`
| Address of the deployed contract

|===

[#cache]
== Cache config

[source,yaml]
----
cache:
  redis:
    enabled: true
    host: redis-master
    port: 6379
    db: 0
    password: I1y0dGKy01by
----

.Redis Config
[cols="2a,2,5"]
|===
| Option | Default Value | Description

| `enabled`
| `false`
| Enable/disable Redis cache

| `host`
| `127.0.0.1`
| Redis host address

| `port`
| `6379`
| Redis port

| `db`
| `0`
| Redis DB to select

| `password`
|
| Password for connection, if required

|===

[#auth]
== Authorization

dshackle supports optional client authentication via signed JWT tokens (RS256). When
`auth.enabled` is `true`, dshackle validates tokens issued by a trusted provider and
rejects unauthenticated requests.

[source,yaml]
----
auth:
  enabled: true
  publicKeyOwner: "token-issuer-name"
  server:
    keys:
      provider-private-key: "/etc/dshackle/auth/jwt-rsa.pem"
      external-public-key: "/etc/dshackle/auth/jwt-rsa.pub"
----

|===
| Name | Default | Description

| `enabled`
| `false`
| Enables authorization and response signing.

| `publicKeyOwner`
|
| Expected value of the `iss` claim on inbound JWT tokens.

| `server.keys.provider-private-key`
|
| Path to a PKCS#8 PEM RSA private key. Used both to sign session JWTs issued by
  dshackle and to sign `NativeCall` response payloads (see <<response-signing>>).

| `server.keys.external-public-key`
|
| Path to a PEM-encoded RSA public key (X.509 SubjectPublicKeyInfo) used to verify
  the JWTs clients present to `emerald.Auth/Authenticate`.
|===

[#response-signing]
==== Response Signing

When `auth.enabled` is `true` and `auth.server.keys.provider-private-key` points to a
valid PKCS#8 RSA private key, dshackle automatically signs gRPC responses with
`SHA256withRSA` for any `NativeCall` request that provides a non-zero `nonce`. The same
key used for issuing JWT tokens (RS256) is reused for response signatures — no separate
configuration is required.

The signed blob is `DSHACKLESIG/<nonce>/<upstream_id>/<hex-sha256(payload)>`. The
returned `NativeCallReplySignature` carries the original `nonce`, the signature bytes
and a `key_id` (first 8 bytes of the SHA-256 of the public key). Clients verify with
the public half of `provider-private-key`.

If a client sends a nonce but the signing key is not configured (auth disabled or the
path is empty), dshackle returns an error with code `-32603` and message
"Response signing requested via nonce but signing key is not configured".

A runnable end-to-end example (dshackle config, demo RSA keys and a Go client) lives
in `demo/response-signing/` in the repository.

[#cluster]
== Cluster

The cluster config is the main part, that defines all connection to nodes and other servers

[source,yaml]
----
cluster:
  defaults:
    - chains:
        - ethereum
      options:
        min-peers: 10
  upstreams:
    - id: local
      chain: ethereum
      connection:
        generic:
          rpc:
            url: "http://localhost:8545"
          ws:
            url: "ws://localhost:8546"
            origin: "http://localhost"
  include:
    - "upstreams-extra.yaml"
----

=== Main Cluster Configuration

.Top Level Config
[cols="2a,5"]
|===
| Option | Description

| `defaults`
| Default options applied to all upstreams within the specified blockchain. It's an optional
configuration, and may be omitted for most of the situations.

| `upstreams`
| List of upstream servers. The main part of the config. There are two types of upstream: <<upstream-json>> and <<upstream-dshackle>>.

| `include`
| Path(s) to include configurations for upstream servers. Same as `upstreams`, but load it from an external file.

|===

[#upstream-json]
=== JSON RPC Upstream

[source,yaml]
----
- id: local
  chain: ethereum
  role: standard
  labels:
    fullnode: true
  methods:
    enabled:
      - name: "parity_trace"
        quorum: "not_empty"
    disabled:
      - name: "admin_shutdown"
  connection:
    generic:
      rpc:
        url: "http://localhost:8545"
      ws:
        url: "ws://localhost:8546"
        origin: "http://localhost"
        basic-auth:
          username: 9c199ad8f281f20154fc258fe41a6814
          password: 258fe4149c199ad8f2811a68f20154fc
        frameSize: 5mb
        msgSize: 15mb
----

.Main Config
[cols="2a,1a,5"]
|===
| Option | Required | Description

| `id`
| yes
| Per-cluster identifier of an upstream

| `role`
| no
| `primary` (default), `secondary` or `fallback`.
First it makes the requests to the upstreams with role `primary`, then if none are available to upstreams with role `secondary`.
Fallback role mean that the upstream is used only after other upstreams failed or didn't return quorum

| `chain`
| yes
| Blockchain which is the provided by the upstream.
Cluster may have multiple upstreams for a single blockchain.
Accepted types: `bitcoin`, `bitcoin-testnet`, `ethereum`, `ethereum-classic`, `kovan-testnet`, `rinkeby-testnet` or `ropsten-testnet`

| `enabled`
| no
| `true` (default) or `false`.
Enable/disable the upstream.

| `labels`
| no
| Key-Value pairs that are assigned to the upstream.
Used to select an upstream per-request.
See xref:09-quorum-and-selectors.adoc[Quorum and Selectors]

| `options`
|
| Other configuration options. See <<general-options>>

| `methods`
| no
| Enable (`enabled`) or disable (`disabled`) additional JSON RPC methods that are provided by that particular upstream

| `methods.enabled.name`, `methods.disabled.name`
| yes
| Name of the RPC method to enable/disable.

| `methods.enabled.quorum`
| no
| Set quorum criteria to accept a response.
`always` (default) - accept any response;
`not_empty` - accept not _null_ value, otherwise retry another upstream;
`not_lagging` - accept response only from a fully synced upstream.

| `connection.generic`
| yes
| Generic connection configuration for most of networks e.g. Ethereum

| `connection.bitcoin`
| yes
| Connection configuration for Bitcoin API

|===

[#general-options]
=== General Upstream Options

[cols="2a,1,1a,5"]
|===
| Option | Type | Default | Description

| `disable-validation`
| boolean
| `false`
| Disables all the validations of the upstream. I.e., it turns off `validate-peers` and `validate-syncing` checks if set to `true`.

| `validate-chain`
| boolean
| `true`
| Disables validation of the chain settings of the upstream. Prevent of creating an upstream with incorrect chain if it relates to a node with another chain.

| `validation-interval`
| number
| `30`
| Period in seconds to re-validate the upstream.

| `validate-peers`
| boolean
| `true`
| Disables validation of the peers connected to the upstream (as `net_peerCount` method).
Dshackle assumes that if there are too few peers then the Upstream is just started and may produce invalid/outdated responses

| `min-peers`
| number
| `1`
| The minimum number of connected peer to consider the upstream valid if `validate-peers` is enabled.
If it's set to `0` it essentially disables the peer validation.

| `validate-syncing`
| boolean
| `true`
| Disables checking for the state of syncing on the upstream (as `eth_syncing` method).
If the Upstream is in _syncing_ state then the Dshackle doesn't use it for call until it reaches the blockchain head.

| `validate-call-limit`
| boolean
| `true`
| Enable/Disable the call limit validation. Size of call limit is defined by `call-limit` option.
If it's enabled configuration parameter for chain `call-limit-contract` is required.

| `validate-gas-price`
| boolean
| `true`
| Enable/Disable the gas price validation. If it's enabled, the Dshackle will check the gas price of the upstream and compare it with the gas price conditions in chain.yaml
Check conditions can contain multiple values presented as a list of pair operator and value. The operator can be `eq`, `ne`, `gt`, `ge`, `lt`, `le`. Value is a Long number.

| `call-limit-size`
| number
| `1000000`
| For all eth-like chains (except zkSync). The maximum size of the call limit. If the upstream exceeds this limit, it will be considered as failed.

| `timeout`
| number
| `60`
| Timeout in seconds to wait for an answer from the upstream before considering it as failed.

| `balance`
| boolean
|
| Suitable for Bitcoin upstream.
Tells if the Upstream can be used to call balance methods, which requires that the node has the indexing as turned on.

|===

==== Ethereum Connection Options

.Connection Config for Ethereum Upstream
[cols="2a,5"]
|===
| Option | Description

| `rpc.url`
a| HTTP URL to connect to.This is required for a connection. +
URL can be configured with Environment Variable placeholders `${ENV_VAR_NAME}`. +
Example: `https://kovan.infura.io/v3/${INFURA_USER}`

| `rpc.basic-auth` + `rpc.basic-auth.username`, `rpc.basic-auth.password`
a| HTTP Basic Auth configuration, if required by the remote server. +
Values can also reference env variables, for example:
[source,yaml]
----
rpc:
  url: "https://ethereum.com:8545"
  basic-auth:
    username: "${ETH_USERNAME}"
    password: "${ETH_PASSWORD}"
----

| `ws.url`
| WebSocket URL to connect to.
Optional, but optimizes performance if it's available.

| `ws.origin`
| HTTP `Origin` if required by WebSocket remote server.

| `ws.basic-auth` + ...
| WebSocket Basic Auth configuration, if required by the remote server

| `ws.frameSize`
| WebSocket frame size limit.
Ex `1kb`, `1024` (same as `1kb), `2mb`, etc.
Default is 5Mb

| `ws.msgSize`
| Total limit for a message size consisting from multiple frames.
Ex `1kb`, `1024` (same as `1kb), `2mb`, etc.
Default is 15Mb

| `ws.connections`
| How many concurrent connection to make. If more than one, each used in a robin-round fashion.
Defaults is `1`
|===

==== PoS Ethereum Connection Options
.Connection Config for PoS Ethereum Upstream
[cols="2a,5"]
|===
| Option | Description

| `execution`
a| Here you can specify any option from plain ethereum connection options listed above +
This is your connection to an execution layer of PoS Ethereum

| `upstream-rating`
a| Rating for this upstream. We will always consider the head of the chain to be +
the latest block we saw from the upstream with the highest rating.

|===

==== Bitcoin Connection Options

.Connection Config for Bitcoin Upstream
[cols="2a,5"]
|===
| Option | Description

| `rpc.url`
a| HTTP URL to connect to. This is required for a connection. +
URL can be configured with Environment Variable placeholders `${ENV_VAR_NAME}`. +
Example: `http://${NODE_HOST}:${NODE_PORT}`

| `rpc.basic-auth` + `rpc.basic-auth.username`, `rpc.basic-auth.password`
a| HTTP Basic Auth configuration, which is required by the Bitcoind server. +
Values can also reference env variables, for example:
[source,yaml]
----
rpc:
  url: "http://127.0.0.1:8332"
  basic-auth:
    username: "${NODE_USERNAME}"
    password: "${NODE_PASSWORD}"
----

| `zeromq.address`
a| Set up an additional connection via ZeroMQ protocol to subscribe to the new blocks.
The node must be launched with the same address specified as `-zmqpubhashblock="tcp://${HOST}:${POST}"` or in `bitcoin.conf`
[source,yaml]
----
zeromq:
  address: "127.0.0.1:5555"
----

|===

[#upstream-dshackle]
=== Dshackle Upstream

Another option is using another Dshackle server as an upstream.
It's more effective, easier to secure connection, and allows to build a distributed network of servers.

[source,yaml]
----
- id: test1
  labels:
    provider: some
  connection:
    grpc:
      host: eu-api.mycompany.com
      port: 2449
      tls:
        ca: ca.api.mycompany.crt
        certificate: client-1.api.mycompany.crt
        key: client-1.api.mycompany.p8.key
----

.Main Config
[cols="2a,1a,5"]
|===
| Option | Required | Description

| `id`
| yes
| Per-cluster identifier of an upstream

| `labels`
| no
| Defines the labels can be used for the proper upstream instance selection. Overrides the labels retrieved by the `describe` method

| `connection.grpc`
| yes
| Connection configuration for Dshackle gRPC
|===

.Connection Config
[cols="2a,5"]
|===
| Option | Description

| `host` and `port`
| Address to connect to

| `tls`
a| TLC configuration for the connection.
In general it's an optional configuration, but it's strongly recommended.
Also HTTP2 + gRPC is designed to be used with TLS, and some of the related software is unable to use it without TLS. +
See xref:08-authentication.adoc[Authentication] docs and <<tls>>.

| `tls.ca`
| Path to x509 certificate to verify remote server

| `tls.certificate` + `tls.key`
| Client certificate (x509) and its private key (PKCS 8) used for authentication on the remote server.

|===
