problem: doesn't work for private ethereum networks

solution: allow configuring methods with static responses
rel: #96
This commit is contained in:
Rafael Matias
2021-11-12 18:55:41 +01:00
committed by GitHub
parent b6a05d67df
commit ee5b14b300
6 changed files with 74 additions and 6 deletions

View File

@@ -218,6 +218,27 @@ NOTE: It's especially useful when used together with upstream labels.If an archi
possible to specify that the client wants to execute method `trace_transaction` only on an archive node(s), which has
complete historical data for tracing.
=== Static Methods
You can overwrite existing methods or add new ones using a static response:
[source, yaml]
----
upstreams:
- id: my-node
chain: ethereum
methods:
enabled:
- name: net_version
static: "\"100000\""
- name: eth_chainId
static: "0x186a0"
- name: eth_custom_array
static: '["custom_array_response"]'
- name: eth_custom_bool
static: "false"
----
=== Authentication
==== TLS
@@ -234,4 +255,4 @@ NOTE: Please note that `key` must be encoded with _PKCS 8_
For JSON RPC and Websockets a Basic Authentication can be used:
- `username` - username
- `password` - password
- `password` - password

View File

@@ -173,6 +173,7 @@ open class UpstreamsConfig {
class Method(
val name: String,
val quorum: String? = null
val quorum: String? = null,
val static: String? = null
)
}

View File

@@ -249,7 +249,8 @@ class UpstreamsConfigReader(
getValueAsString(m, "name")?.let { name ->
UpstreamsConfig.Method(
name = name,
quorum = getValueAsString(m, "quorum")
quorum = getValueAsString(m, "quorum"),
static = getValueAsString(m, "static")
)
}
}?.filterNotNull()?.toSet() ?: emptySet()

View File

@@ -123,6 +123,9 @@ open class ConfiguredUpstreams(
if (m.quorum != null) {
it.setQuorum(m.name, m.quorum)
}
if (m.static != null) {
it.setStaticResponse(m.name, m.static)
}
}
}
} else {

View File

@@ -16,11 +16,13 @@
*/
package io.emeraldpay.dshackle.upstream.calls
import com.fasterxml.jackson.databind.ObjectMapper
import io.emeraldpay.dshackle.quorum.AlwaysQuorum
import io.emeraldpay.dshackle.quorum.CallQuorum
import io.emeraldpay.dshackle.quorum.NonEmptyQuorum
import io.emeraldpay.dshackle.quorum.NotLaggingQuorum
import org.slf4j.LoggerFactory
import java.io.IOException
import java.util.Collections
/**
@@ -44,6 +46,7 @@ class ManagedCallMethods(
enabled + delegated - disabled
)
private val quorum: MutableMap<String, CallQuorum> = HashMap()
private val staticResponse: MutableMap<String, String> = HashMap()
init {
enabled.forEach { m ->
@@ -64,6 +67,10 @@ class ManagedCallMethods(
this.quorum[method] = quorum
}
fun setStaticResponse(method: String, response: String) {
this.staticResponse[method] = response
}
override fun getQuorumFor(method: String): CallQuorum {
return when {
Collections.binarySearch(delegated, method) >= 0 -> delegate.getQuorumFor(method)
@@ -84,10 +91,22 @@ class ManagedCallMethods(
}
override fun isHardcoded(method: String): Boolean {
return delegate.isHardcoded(method)
return this.staticResponse.containsKey(method) || delegate.isHardcoded(method)
}
override fun executeHardcoded(method: String): ByteArray {
if (this.staticResponse.containsKey(method)) {
var json: String = this.staticResponse[method].orEmpty()
// Check if it's valid JSON
val mapper = ObjectMapper()
try {
mapper.readTree(json)
} catch (e: IOException) {
// Encode and default to string
json = mapper.writeValueAsString(json)
}
return json.toByteArray()
}
return delegate.executeHardcoded(method)
}
}

View File

@@ -22,8 +22,8 @@ class ConfiguredUpstreamsSpec extends Specification {
)
def methods = new UpstreamsConfig.Methods(
[
new UpstreamsConfig.Method("foo_bar", null),
new UpstreamsConfig.Method("foo_bar", "not_empty")
new UpstreamsConfig.Method("foo_bar", null, null),
new UpstreamsConfig.Method("foo_bar", "not_empty", null)
] as Set,
[] as Set
)
@@ -35,4 +35,27 @@ class ConfiguredUpstreamsSpec extends Specification {
act instanceof ManagedCallMethods
act.getQuorumFor("foo_bar") instanceof NonEmptyQuorum
}
def "Got static response from extra methods"() {
setup:
def currentUpstreams = Mock(CurrentMultistreamHolder) {
_ * getDefaultMethods(Chain.ETHEREUM) >> new DefaultEthereumMethods(Chain.ETHEREUM)
}
def configurer = new ConfiguredUpstreams(
currentUpstreams, Stub(FileResolver), Stub(UpstreamsConfig), Stub(CachesFactory)
)
def methods = new UpstreamsConfig.Methods(
[
new UpstreamsConfig.Method("foo_bar", null, "static_response")
] as Set,
[] as Set
)
def upstream = new UpstreamsConfig.Upstream()
upstream.methods = methods
when:
def act = configurer.buildMethods(upstream, Chain.ETHEREUM)
then:
act instanceof ManagedCallMethods
new String(act.executeHardcoded("foo_bar")) == "\"static_response\""
}
}