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 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
@@ -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: For JSON RPC and Websockets a Basic Authentication can be used:
- `username` - username - `username` - username
- `password` - password - `password` - password

View File

@@ -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
) )
} }

View File

@@ -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()

View File

@@ -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 {

View File

@@ -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)
} }
} }

View File

@@ -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\""
}
} }