Use rpcProxy in lc proxy (#1238)
* Use rpcProxy in lc proxy * Remove nimbus config from cors handler
This commit is contained in:
parent
8dff89ecad
commit
2b7bc4f2ef
|
@ -14,31 +14,20 @@ import
|
||||||
std/[os, strutils],
|
std/[os, strutils],
|
||||||
chronicles, chronicles/chronos_tools, chronos,
|
chronicles, chronicles/chronos_tools, chronos,
|
||||||
eth/keys,
|
eth/keys,
|
||||||
json_rpc/[rpcserver, rpcclient],
|
json_rpc/rpcproxy,
|
||||||
beacon_chain/eth1/eth1_monitor,
|
beacon_chain/eth1/eth1_monitor,
|
||||||
beacon_chain/gossip_processing/optimistic_processor,
|
beacon_chain/gossip_processing/optimistic_processor,
|
||||||
beacon_chain/networking/topic_params,
|
beacon_chain/networking/topic_params,
|
||||||
beacon_chain/spec/beaconstate,
|
beacon_chain/spec/beaconstate,
|
||||||
beacon_chain/spec/datatypes/[phase0, altair, bellatrix],
|
beacon_chain/spec/datatypes/[phase0, altair, bellatrix],
|
||||||
beacon_chain/[light_client, nimbus_binary_common, version],
|
beacon_chain/[light_client, nimbus_binary_common, version],
|
||||||
|
../nimbus/rpc/cors,
|
||||||
./rpc/rpc_eth_lc_api,
|
./rpc/rpc_eth_lc_api,
|
||||||
./lc_proxy_conf
|
./lc_proxy_conf
|
||||||
|
|
||||||
from beacon_chain/consensus_object_pools/consensus_manager import runForkchoiceUpdated
|
|
||||||
from beacon_chain/gossip_processing/block_processor import newExecutionPayload
|
from beacon_chain/gossip_processing/block_processor import newExecutionPayload
|
||||||
from beacon_chain/gossip_processing/eth2_processor import toValidationResult
|
from beacon_chain/gossip_processing/eth2_processor import toValidationResult
|
||||||
|
|
||||||
proc initRpcClient(config: LcProxyConf): Future[RpcClient] {.async.} =
|
|
||||||
case config.web3ClientConfig.kind
|
|
||||||
of WsClient:
|
|
||||||
let wssClient = newRpcWebSocketClient()
|
|
||||||
await wssClient.connect(config.web3ClientConfig.url)
|
|
||||||
return wssClient
|
|
||||||
of HttpClient:
|
|
||||||
let httpClient = newRpcHttpClient()
|
|
||||||
await httpClient.connect(config.web3ClientConfig.url)
|
|
||||||
return httpClient
|
|
||||||
|
|
||||||
func getConfiguredChainId(networkMetadata: Eth2NetworkMetadata): Quantity =
|
func getConfiguredChainId(networkMetadata: Eth2NetworkMetadata): Quantity =
|
||||||
if networkMetadata.eth1Network.isSome():
|
if networkMetadata.eth1Network.isSome():
|
||||||
let
|
let
|
||||||
|
@ -105,13 +94,18 @@ proc run() {.raises: [Exception, Defect].} =
|
||||||
forkDigests, getBeaconTime, genesis_validators_root
|
forkDigests, getBeaconTime, genesis_validators_root
|
||||||
)
|
)
|
||||||
|
|
||||||
rpcClient = waitFor initRpcClient(config)
|
# TODO: for now we serve all cross origin requests
|
||||||
|
authHooks = @[httpCors(@[])]
|
||||||
|
|
||||||
rpcHttpServer = newRpcHttpServer(
|
clientConfig = config.web3url.asClientConfig()
|
||||||
[initTAddress(config.rpcAddress, config.rpcPort)]
|
|
||||||
|
rpcProxy = RpcProxy.new(
|
||||||
|
[initTAddress(config.rpcAddress, config.rpcPort)],
|
||||||
|
clientConfig,
|
||||||
|
authHooks
|
||||||
)
|
)
|
||||||
|
|
||||||
lcProxy = LightClientRpcProxy.new(rpcHttpServer, rpcClient, chainId)
|
lcProxy = LightClientRpcProxy.new(rpcProxy, chainId)
|
||||||
|
|
||||||
optimisticHandler = proc(signedBlock: ForkedMsgTrustedSignedBeaconBlock):
|
optimisticHandler = proc(signedBlock: ForkedMsgTrustedSignedBeaconBlock):
|
||||||
Future[void] {.async.} =
|
Future[void] {.async.} =
|
||||||
|
@ -156,7 +150,7 @@ proc run() {.raises: [Exception, Defect].} =
|
||||||
|
|
||||||
waitFor network.startListening()
|
waitFor network.startListening()
|
||||||
waitFor network.start()
|
waitFor network.start()
|
||||||
rpcHttpServer.start()
|
waitFor rpcProxy.start()
|
||||||
waitFor lcProxy.verifyChaindId()
|
waitFor lcProxy.verifyChaindId()
|
||||||
|
|
||||||
proc onFinalizedHeader(
|
proc onFinalizedHeader(
|
||||||
|
|
|
@ -14,7 +14,8 @@ import
|
||||||
std/os,
|
std/os,
|
||||||
json_serialization/std/net,
|
json_serialization/std/net,
|
||||||
beacon_chain/light_client,
|
beacon_chain/light_client,
|
||||||
beacon_chain/conf
|
beacon_chain/conf,
|
||||||
|
json_rpc/[rpcproxy]
|
||||||
|
|
||||||
export net, conf
|
export net, conf
|
||||||
|
|
||||||
|
@ -28,19 +29,17 @@ proc defaultLCPDataDir*(): string =
|
||||||
|
|
||||||
getHomeDir() / dataDir
|
getHomeDir() / dataDir
|
||||||
|
|
||||||
|
|
||||||
type Web3ClientType* = enum
|
|
||||||
WsClient, HttpClient
|
|
||||||
|
|
||||||
type Web3ClientConfig* = object
|
|
||||||
kind*: Web3ClientType
|
|
||||||
url*: string
|
|
||||||
|
|
||||||
const
|
const
|
||||||
defaultWeb3Address* = (static "http://127.0.0.1:8546")
|
|
||||||
defaultWeb3ClientConfig* = Web3ClientConfig(url: defaultWeb3Address, kind: HttpClient)
|
|
||||||
defaultDataLCPDirDesc* = defaultLCPDataDir()
|
defaultDataLCPDirDesc* = defaultLCPDataDir()
|
||||||
|
|
||||||
|
type
|
||||||
|
Web3UrlKind* = enum
|
||||||
|
HttpUrl, WsUrl
|
||||||
|
|
||||||
|
ValidatedWeb3Url* = object
|
||||||
|
kind*: Web3UrlKind
|
||||||
|
web3Url*: string
|
||||||
|
|
||||||
type LcProxyConf* = object
|
type LcProxyConf* = object
|
||||||
# Config
|
# Config
|
||||||
configFile* {.
|
configFile* {.
|
||||||
|
@ -164,25 +163,25 @@ type LcProxyConf* = object
|
||||||
defaultValueDesc: $defaultAdminListenAddressDesc
|
defaultValueDesc: $defaultAdminListenAddressDesc
|
||||||
name: "rpc-address" .}: ValidIpAddress
|
name: "rpc-address" .}: ValidIpAddress
|
||||||
|
|
||||||
web3ClientConfig* {.
|
# There is no default as its need to be provided by the user
|
||||||
|
web3url* {.
|
||||||
desc: "url of web3 data provider"
|
desc: "url of web3 data provider"
|
||||||
defaultValue: defaultWeb3ClientConfig
|
name: "web3-url" .}: ValidatedWeb3Url
|
||||||
name: "web3-url" .}: Web3ClientConfig
|
|
||||||
|
|
||||||
proc parseCmdArg*(T: type Web3ClientConfig, p: TaintedString): T
|
proc parseCmdArg*(T: type ValidatedWeb3Url, p: TaintedString): T
|
||||||
{.raises: [Defect, ConfigurationError].} =
|
{.raises: [Defect, ConfigurationError].} =
|
||||||
let url = parseUri(p)
|
let url = parseUri(p)
|
||||||
let normalizedScheme = url.scheme.toLowerAscii()
|
let normalizedScheme = url.scheme.toLowerAscii()
|
||||||
if (normalizedScheme == "http" or normalizedScheme == "https"):
|
if (normalizedScheme == "http" or normalizedScheme == "https"):
|
||||||
Web3ClientConfig(kind: HttpClient, url: p)
|
ValidatedWeb3Url(kind: HttpUrl, web3Url: p)
|
||||||
elif (normalizedScheme == "ws" or normalizedScheme == "wss"):
|
elif (normalizedScheme == "ws" or normalizedScheme == "wss"):
|
||||||
Web3ClientConfig(kind: WsClient, url: p)
|
ValidatedWeb3Url(kind: WsUrl, web3Url: p)
|
||||||
else:
|
else:
|
||||||
raise newException(
|
raise newException(
|
||||||
ConfigurationError, "Web3 client uri should have defined scheme (http/https/ws/wss)"
|
ConfigurationError, "Web3 url should have defined scheme (http/https/ws/wss)"
|
||||||
)
|
)
|
||||||
|
|
||||||
proc completeCmdArg*(T: type Web3ClientConfig, val: TaintedString): seq[string] =
|
proc completeCmdArg*(T: type ValidatedWeb3Url, val: TaintedString): seq[string] =
|
||||||
return @[]
|
return @[]
|
||||||
|
|
||||||
func asLightClientConf*(pc: LcProxyConf): LightClientConf =
|
func asLightClientConf*(pc: LcProxyConf): LightClientConf =
|
||||||
|
@ -210,3 +209,13 @@ func asLightClientConf*(pc: LcProxyConf): LightClientConf =
|
||||||
jwtSecret: none(string),
|
jwtSecret: none(string),
|
||||||
stopAtEpoch: 0
|
stopAtEpoch: 0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# TODO: Cannot use ClientConfig in LcProxyConf due to the fact that
|
||||||
|
# it contain `set[TLSFlags]` which does not have proper toml serialization
|
||||||
|
func asClientConfig*(url: ValidatedWeb3Url): ClientConfig =
|
||||||
|
case url.kind
|
||||||
|
of HttpUrl:
|
||||||
|
getHttpClientConfig(url.web3Url)
|
||||||
|
of WsUrl:
|
||||||
|
getWebSocketClientConfig(url.web3Url, flags = {})
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ import
|
||||||
stint,
|
stint,
|
||||||
stew/byteutils,
|
stew/byteutils,
|
||||||
chronicles,
|
chronicles,
|
||||||
json_rpc/[rpcserver, rpcclient],
|
json_rpc/[rpcproxy, rpcserver, rpcclient],
|
||||||
web3,
|
web3,
|
||||||
web3/[ethhexstrings, ethtypes],
|
web3/[ethhexstrings, ethtypes],
|
||||||
beacon_chain/eth1/eth1_monitor,
|
beacon_chain/eth1/eth1_monitor,
|
||||||
|
@ -36,8 +36,7 @@ template encodeQuantity(value: Quantity): HexQuantityStr =
|
||||||
hexQuantityStr(encodeQuantity(value.uint64))
|
hexQuantityStr(encodeQuantity(value.uint64))
|
||||||
|
|
||||||
type LightClientRpcProxy* = ref object
|
type LightClientRpcProxy* = ref object
|
||||||
client*: RpcClient
|
proxy: RpcProxy
|
||||||
server*: RpcServer
|
|
||||||
executionPayload*: Opt[ExecutionPayloadV1]
|
executionPayload*: Opt[ExecutionPayloadV1]
|
||||||
chainId: Quantity
|
chainId: Quantity
|
||||||
|
|
||||||
|
@ -54,13 +53,15 @@ template checkPreconditions(payload: Opt[ExecutionPayloadV1], quantityTag: strin
|
||||||
# fetched on demand.
|
# fetched on demand.
|
||||||
raise newException(ValueError, "Only latest block is supported")
|
raise newException(ValueError, "Only latest block is supported")
|
||||||
|
|
||||||
|
template rpcClient(lcProxy: LightClientRpcProxy): RpcClient = lcProxy.proxy.getClient()
|
||||||
|
|
||||||
proc installEthApiHandlers*(lcProxy: LightClientRpcProxy) =
|
proc installEthApiHandlers*(lcProxy: LightClientRpcProxy) =
|
||||||
template payload(): Opt[ExecutionPayloadV1] = lcProxy.executionPayload
|
template payload(): Opt[ExecutionPayloadV1] = lcProxy.executionPayload
|
||||||
|
|
||||||
lcProxy.server.rpc("eth_chainId") do() -> HexQuantityStr:
|
lcProxy.proxy.rpc("eth_chainId") do() -> HexQuantityStr:
|
||||||
return encodeQuantity(lcProxy.chainId)
|
return encodeQuantity(lcProxy.chainId)
|
||||||
|
|
||||||
lcProxy.server.rpc("eth_blockNumber") do() -> HexQuantityStr:
|
lcProxy.proxy.rpc("eth_blockNumber") do() -> HexQuantityStr:
|
||||||
## Returns the number of most recent block.
|
## Returns the number of most recent block.
|
||||||
if payload.isNone:
|
if payload.isNone:
|
||||||
raise newException(ValueError, "Syncing")
|
raise newException(ValueError, "Syncing")
|
||||||
|
@ -68,7 +69,7 @@ proc installEthApiHandlers*(lcProxy: LightClientRpcProxy) =
|
||||||
return encodeQuantity(payload.get.blockNumber)
|
return encodeQuantity(payload.get.blockNumber)
|
||||||
|
|
||||||
# TODO quantity tag should be better typed
|
# TODO quantity tag should be better typed
|
||||||
lcProxy.server.rpc("eth_getBalance") do(address: Address, quantityTag: string) -> HexQuantityStr:
|
lcProxy.proxy.rpc("eth_getBalance") do(address: Address, quantityTag: string) -> HexQuantityStr:
|
||||||
checkPreconditions(payload, quantityTag)
|
checkPreconditions(payload, quantityTag)
|
||||||
|
|
||||||
# When requesting state for `latest` block number, we need to translate
|
# When requesting state for `latest` block number, we need to translate
|
||||||
|
@ -81,7 +82,7 @@ proc installEthApiHandlers*(lcProxy: LightClientRpcProxy) =
|
||||||
|
|
||||||
info "Forwarding get_Balance", executionBn = blockNumber
|
info "Forwarding get_Balance", executionBn = blockNumber
|
||||||
|
|
||||||
let proof = await lcProxy.client.eth_getProof(address, @[], blockId(blockNumber))
|
let proof = await lcProxy.rpcClient.eth_getProof(address, @[], blockId(blockNumber))
|
||||||
|
|
||||||
let accountResult = getAccountFromProof(
|
let accountResult = getAccountFromProof(
|
||||||
executionPayload.stateRoot,
|
executionPayload.stateRoot,
|
||||||
|
@ -98,7 +99,7 @@ proc installEthApiHandlers*(lcProxy: LightClientRpcProxy) =
|
||||||
else:
|
else:
|
||||||
raise newException(ValueError, accountResult.error)
|
raise newException(ValueError, accountResult.error)
|
||||||
|
|
||||||
lcProxy.server.rpc("eth_getStorageAt") do(address: Address, slot: HexDataStr, quantityTag: string) -> HexDataStr:
|
lcProxy.proxy.rpc("eth_getStorageAt") do(address: Address, slot: HexDataStr, quantityTag: string) -> HexDataStr:
|
||||||
checkPreconditions(payload, quantityTag)
|
checkPreconditions(payload, quantityTag)
|
||||||
|
|
||||||
let
|
let
|
||||||
|
@ -108,7 +109,7 @@ proc installEthApiHandlers*(lcProxy: LightClientRpcProxy) =
|
||||||
|
|
||||||
info "Forwarding eth_getStorageAt", executionBn = blockNumber
|
info "Forwarding eth_getStorageAt", executionBn = blockNumber
|
||||||
|
|
||||||
let proof = await lcProxy.client.eth_getProof(address, @[uslot], blockId(blockNumber))
|
let proof = await lcProxy.rpcClient.eth_getProof(address, @[uslot], blockId(blockNumber))
|
||||||
|
|
||||||
let dataResult = getStorageData(executionPayload.stateRoot, uslot, proof)
|
let dataResult = getStorageData(executionPayload.stateRoot, uslot, proof)
|
||||||
|
|
||||||
|
@ -118,15 +119,23 @@ proc installEthApiHandlers*(lcProxy: LightClientRpcProxy) =
|
||||||
else:
|
else:
|
||||||
raise newException(ValueError, dataResult.error)
|
raise newException(ValueError, dataResult.error)
|
||||||
|
|
||||||
|
# TODO This methods are forwarded directly to provider therefore thay are not
|
||||||
|
# validated in any way
|
||||||
|
lcProxy.proxy.registerProxyMethod("net_version")
|
||||||
|
lcProxy.proxy.registerProxyMethod("eth_call")
|
||||||
|
|
||||||
|
# TODO cache blocks received from light client, and respond using them in this
|
||||||
|
# call. It would also enable handling of numerical `quantityTag` for the
|
||||||
|
# set of cached blocks
|
||||||
|
lcProxy.proxy.registerProxyMethod("eth_getBlockByNumber")
|
||||||
|
|
||||||
proc new*(
|
proc new*(
|
||||||
T: type LightClientRpcProxy,
|
T: type LightClientRpcProxy,
|
||||||
server: RpcServer,
|
proxy: RpcProxy,
|
||||||
client: RpcClient,
|
|
||||||
chainId: Quantity): T =
|
chainId: Quantity): T =
|
||||||
|
|
||||||
return LightClientRpcProxy(
|
return LightClientRpcProxy(
|
||||||
client: client,
|
proxy: proxy,
|
||||||
server: server,
|
|
||||||
chainId: chainId
|
chainId: chainId
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -136,7 +145,7 @@ proc verifyChaindId*(p: LightClientRpcProxy): Future[void] {.async.} =
|
||||||
# retry 2 times, if the data provider will fail despite re-tries, propagate
|
# retry 2 times, if the data provider will fail despite re-tries, propagate
|
||||||
# exception to the caller.
|
# exception to the caller.
|
||||||
let providerId = awaitWithRetries(
|
let providerId = awaitWithRetries(
|
||||||
p.client.eth_chainId(),
|
p.rpcClient.eth_chainId(),
|
||||||
retries = 2,
|
retries = 2,
|
||||||
timeout = seconds(30)
|
timeout = seconds(30)
|
||||||
)
|
)
|
||||||
|
|
|
@ -14,8 +14,7 @@ import
|
||||||
chronos/apps/http/[httptable, httpserver],
|
chronos/apps/http/[httptable, httpserver],
|
||||||
json_rpc/rpcserver,
|
json_rpc/rpcserver,
|
||||||
httputils,
|
httputils,
|
||||||
websock/websock as ws,
|
websock/websock as ws
|
||||||
../config
|
|
||||||
|
|
||||||
proc sameOrigin(a, b: Uri): bool =
|
proc sameOrigin(a, b: Uri): bool =
|
||||||
a.hostname == b.hostname and
|
a.hostname == b.hostname and
|
||||||
|
|
Loading…
Reference in New Issue