Use rpcProxy in lc proxy (#1238)

* Use rpcProxy in lc proxy

* Remove nimbus config from cors handler
This commit is contained in:
KonradStaniec 2022-09-24 13:57:27 +02:00 committed by GitHub
parent 8dff89ecad
commit 2b7bc4f2ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 64 additions and 53 deletions

View File

@ -14,31 +14,20 @@ import
std/[os, strutils],
chronicles, chronicles/chronos_tools, chronos,
eth/keys,
json_rpc/[rpcserver, rpcclient],
json_rpc/rpcproxy,
beacon_chain/eth1/eth1_monitor,
beacon_chain/gossip_processing/optimistic_processor,
beacon_chain/networking/topic_params,
beacon_chain/spec/beaconstate,
beacon_chain/spec/datatypes/[phase0, altair, bellatrix],
beacon_chain/[light_client, nimbus_binary_common, version],
../nimbus/rpc/cors,
./rpc/rpc_eth_lc_api,
./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/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 =
if networkMetadata.eth1Network.isSome():
let
@ -105,13 +94,18 @@ proc run() {.raises: [Exception, Defect].} =
forkDigests, getBeaconTime, genesis_validators_root
)
rpcClient = waitFor initRpcClient(config)
# TODO: for now we serve all cross origin requests
authHooks = @[httpCors(@[])]
rpcHttpServer = newRpcHttpServer(
[initTAddress(config.rpcAddress, config.rpcPort)]
clientConfig = config.web3url.asClientConfig()
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):
Future[void] {.async.} =
@ -156,7 +150,7 @@ proc run() {.raises: [Exception, Defect].} =
waitFor network.startListening()
waitFor network.start()
rpcHttpServer.start()
waitFor rpcProxy.start()
waitFor lcProxy.verifyChaindId()
proc onFinalizedHeader(

View File

@ -14,7 +14,8 @@ import
std/os,
json_serialization/std/net,
beacon_chain/light_client,
beacon_chain/conf
beacon_chain/conf,
json_rpc/[rpcproxy]
export net, conf
@ -28,19 +29,17 @@ proc defaultLCPDataDir*(): string =
getHomeDir() / dataDir
type Web3ClientType* = enum
WsClient, HttpClient
type Web3ClientConfig* = object
kind*: Web3ClientType
url*: string
const
defaultWeb3Address* = (static "http://127.0.0.1:8546")
defaultWeb3ClientConfig* = Web3ClientConfig(url: defaultWeb3Address, kind: HttpClient)
defaultDataLCPDirDesc* = defaultLCPDataDir()
type
Web3UrlKind* = enum
HttpUrl, WsUrl
ValidatedWeb3Url* = object
kind*: Web3UrlKind
web3Url*: string
type LcProxyConf* = object
# Config
configFile* {.
@ -164,25 +163,25 @@ type LcProxyConf* = object
defaultValueDesc: $defaultAdminListenAddressDesc
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"
defaultValue: defaultWeb3ClientConfig
name: "web3-url" .}: Web3ClientConfig
name: "web3-url" .}: ValidatedWeb3Url
proc parseCmdArg*(T: type Web3ClientConfig, p: TaintedString): T
proc parseCmdArg*(T: type ValidatedWeb3Url, p: TaintedString): T
{.raises: [Defect, ConfigurationError].} =
let url = parseUri(p)
let normalizedScheme = url.scheme.toLowerAscii()
if (normalizedScheme == "http" or normalizedScheme == "https"):
Web3ClientConfig(kind: HttpClient, url: p)
ValidatedWeb3Url(kind: HttpUrl, web3Url: p)
elif (normalizedScheme == "ws" or normalizedScheme == "wss"):
Web3ClientConfig(kind: WsClient, url: p)
ValidatedWeb3Url(kind: WsUrl, web3Url: p)
else:
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 @[]
func asLightClientConf*(pc: LcProxyConf): LightClientConf =
@ -210,3 +209,13 @@ func asLightClientConf*(pc: LcProxyConf): LightClientConf =
jwtSecret: none(string),
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 = {})

View File

@ -11,7 +11,7 @@ import
stint,
stew/byteutils,
chronicles,
json_rpc/[rpcserver, rpcclient],
json_rpc/[rpcproxy, rpcserver, rpcclient],
web3,
web3/[ethhexstrings, ethtypes],
beacon_chain/eth1/eth1_monitor,
@ -36,8 +36,7 @@ template encodeQuantity(value: Quantity): HexQuantityStr =
hexQuantityStr(encodeQuantity(value.uint64))
type LightClientRpcProxy* = ref object
client*: RpcClient
server*: RpcServer
proxy: RpcProxy
executionPayload*: Opt[ExecutionPayloadV1]
chainId: Quantity
@ -54,13 +53,15 @@ template checkPreconditions(payload: Opt[ExecutionPayloadV1], quantityTag: strin
# fetched on demand.
raise newException(ValueError, "Only latest block is supported")
template rpcClient(lcProxy: LightClientRpcProxy): RpcClient = lcProxy.proxy.getClient()
proc installEthApiHandlers*(lcProxy: LightClientRpcProxy) =
template payload(): Opt[ExecutionPayloadV1] = lcProxy.executionPayload
lcProxy.server.rpc("eth_chainId") do() -> HexQuantityStr:
lcProxy.proxy.rpc("eth_chainId") do() -> HexQuantityStr:
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.
if payload.isNone:
raise newException(ValueError, "Syncing")
@ -68,7 +69,7 @@ proc installEthApiHandlers*(lcProxy: LightClientRpcProxy) =
return encodeQuantity(payload.get.blockNumber)
# 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)
# 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
let proof = await lcProxy.client.eth_getProof(address, @[], blockId(blockNumber))
let proof = await lcProxy.rpcClient.eth_getProof(address, @[], blockId(blockNumber))
let accountResult = getAccountFromProof(
executionPayload.stateRoot,
@ -98,7 +99,7 @@ proc installEthApiHandlers*(lcProxy: LightClientRpcProxy) =
else:
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)
let
@ -108,7 +109,7 @@ proc installEthApiHandlers*(lcProxy: LightClientRpcProxy) =
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)
@ -118,15 +119,23 @@ proc installEthApiHandlers*(lcProxy: LightClientRpcProxy) =
else:
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*(
T: type LightClientRpcProxy,
server: RpcServer,
client: RpcClient,
proxy: RpcProxy,
chainId: Quantity): T =
return LightClientRpcProxy(
client: client,
server: server,
proxy: proxy,
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
# exception to the caller.
let providerId = awaitWithRetries(
p.client.eth_chainId(),
p.rpcClient.eth_chainId(),
retries = 2,
timeout = seconds(30)
)

View File

@ -14,8 +14,7 @@ import
chronos/apps/http/[httptable, httpserver],
json_rpc/rpcserver,
httputils,
websock/websock as ws,
../config
websock/websock as ws
proc sameOrigin(a, b: Uri): bool =
a.hostname == b.hostname and