problem: doesn't work for private ethereum networks
solution: allow configuring methods with static responses rel: #96
This commit is contained in:
@@ -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
|
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.
|
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
|
=== Authentication
|
||||||
|
|
||||||
==== TLS
|
==== TLS
|
||||||
|
|||||||
@@ -173,6 +173,7 @@ open class UpstreamsConfig {
|
|||||||
|
|
||||||
class Method(
|
class Method(
|
||||||
val name: String,
|
val name: String,
|
||||||
val quorum: String? = null
|
val quorum: String? = null,
|
||||||
|
val static: String? = null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -249,7 +249,8 @@ class UpstreamsConfigReader(
|
|||||||
getValueAsString(m, "name")?.let { name ->
|
getValueAsString(m, "name")?.let { name ->
|
||||||
UpstreamsConfig.Method(
|
UpstreamsConfig.Method(
|
||||||
name = name,
|
name = name,
|
||||||
quorum = getValueAsString(m, "quorum")
|
quorum = getValueAsString(m, "quorum"),
|
||||||
|
static = getValueAsString(m, "static")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}?.filterNotNull()?.toSet() ?: emptySet()
|
}?.filterNotNull()?.toSet() ?: emptySet()
|
||||||
|
|||||||
@@ -123,6 +123,9 @@ open class ConfiguredUpstreams(
|
|||||||
if (m.quorum != null) {
|
if (m.quorum != null) {
|
||||||
it.setQuorum(m.name, m.quorum)
|
it.setQuorum(m.name, m.quorum)
|
||||||
}
|
}
|
||||||
|
if (m.static != null) {
|
||||||
|
it.setStaticResponse(m.name, m.static)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -16,11 +16,13 @@
|
|||||||
*/
|
*/
|
||||||
package io.emeraldpay.dshackle.upstream.calls
|
package io.emeraldpay.dshackle.upstream.calls
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import io.emeraldpay.dshackle.quorum.AlwaysQuorum
|
import io.emeraldpay.dshackle.quorum.AlwaysQuorum
|
||||||
import io.emeraldpay.dshackle.quorum.CallQuorum
|
import io.emeraldpay.dshackle.quorum.CallQuorum
|
||||||
import io.emeraldpay.dshackle.quorum.NonEmptyQuorum
|
import io.emeraldpay.dshackle.quorum.NonEmptyQuorum
|
||||||
import io.emeraldpay.dshackle.quorum.NotLaggingQuorum
|
import io.emeraldpay.dshackle.quorum.NotLaggingQuorum
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
import java.io.IOException
|
||||||
import java.util.Collections
|
import java.util.Collections
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -44,6 +46,7 @@ class ManagedCallMethods(
|
|||||||
enabled + delegated - disabled
|
enabled + delegated - disabled
|
||||||
)
|
)
|
||||||
private val quorum: MutableMap<String, CallQuorum> = HashMap()
|
private val quorum: MutableMap<String, CallQuorum> = HashMap()
|
||||||
|
private val staticResponse: MutableMap<String, String> = HashMap()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
enabled.forEach { m ->
|
enabled.forEach { m ->
|
||||||
@@ -64,6 +67,10 @@ class ManagedCallMethods(
|
|||||||
this.quorum[method] = quorum
|
this.quorum[method] = quorum
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setStaticResponse(method: String, response: String) {
|
||||||
|
this.staticResponse[method] = response
|
||||||
|
}
|
||||||
|
|
||||||
override fun getQuorumFor(method: String): CallQuorum {
|
override fun getQuorumFor(method: String): CallQuorum {
|
||||||
return when {
|
return when {
|
||||||
Collections.binarySearch(delegated, method) >= 0 -> delegate.getQuorumFor(method)
|
Collections.binarySearch(delegated, method) >= 0 -> delegate.getQuorumFor(method)
|
||||||
@@ -84,10 +91,22 @@ class ManagedCallMethods(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun isHardcoded(method: String): Boolean {
|
override fun isHardcoded(method: String): Boolean {
|
||||||
return delegate.isHardcoded(method)
|
return this.staticResponse.containsKey(method) || delegate.isHardcoded(method)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun executeHardcoded(method: String): ByteArray {
|
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)
|
return delegate.executeHardcoded(method)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ class ConfiguredUpstreamsSpec extends Specification {
|
|||||||
)
|
)
|
||||||
def methods = new UpstreamsConfig.Methods(
|
def methods = new UpstreamsConfig.Methods(
|
||||||
[
|
[
|
||||||
new UpstreamsConfig.Method("foo_bar", null),
|
new UpstreamsConfig.Method("foo_bar", null, null),
|
||||||
new UpstreamsConfig.Method("foo_bar", "not_empty")
|
new UpstreamsConfig.Method("foo_bar", "not_empty", null)
|
||||||
] as Set,
|
] as Set,
|
||||||
[] as Set
|
[] as Set
|
||||||
)
|
)
|
||||||
@@ -35,4 +35,27 @@ class ConfiguredUpstreamsSpec extends Specification {
|
|||||||
act instanceof ManagedCallMethods
|
act instanceof ManagedCallMethods
|
||||||
act.getQuorumFor("foo_bar") instanceof NonEmptyQuorum
|
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\""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user