Formatting nimbus_verified_proxy code with nph v0.4.1 + CI check (#2019)

* Add nph check to nimbus_verified_proxy CI lint

* Formatting nimbus_verified_proxy code with nph v0.4.1

* Update copyright years

* Change order of nph check vs copyright check
This commit is contained in:
Kim De Mey 2024-02-15 14:50:25 +01:00 committed by GitHub
parent 966adcb124
commit 5642662850
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 449 additions and 393 deletions

View File

@ -233,6 +233,18 @@ jobs:
with: with:
fetch-depth: 2 # In PR, has extra merge commit: ^1 = PR, ^2 = base fetch-depth: 2 # In PR, has extra merge commit: ^1 = PR, ^2 = base
- name: Check nph formatting
# Pin nph to a specific version to avoid sudden style differences.
# Updating nph version should be accompanied with running the new
# version on the fluffy directory.
run: |
VERSION="v0.4.1"
ARCHIVE="nph-linux_x64.tar.gz"
curl -L "https://github.com/arnetheduck/nph/releases/download/${VERSION}/${ARCHIVE}" -o ${ARCHIVE}
tar -xzf ${ARCHIVE}
./nph nimbus_verified_proxy/
git diff --exit-code
- name: Check copyright year - name: Check copyright year
if: ${{ !cancelled() }} && github.event_name == 'pull_request' if: ${{ !cancelled() }} && github.event_name == 'pull_request'
run: | run: |

View File

@ -1,5 +1,5 @@
# nimbus_verified_proxy # nimbus_verified_proxy
# Copyright (c) 2022-2023 Status Research & Development GmbH # Copyright (c) 2022-2024 Status Research & Development GmbH
# Licensed and distributed under either of # Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). # * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). # * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
@ -7,12 +7,7 @@
{.push raises: [].} {.push raises: [].}
import import std/tables, web3/primitives, stew/[results, keyed_queue], ./rpc/rpc_utils
std/tables,
web3/primitives,
stew/[results, keyed_queue],
./rpc/rpc_utils
## Cache for payloads received through block gossip and validated by the ## Cache for payloads received through block gossip and validated by the
## consensus light client. ## consensus light client.
@ -27,8 +22,7 @@ proc `==`(x, y: Quantity): bool {.borrow, noSideEffect.}
proc new*(T: type BlockCache, max: uint32): T = proc new*(T: type BlockCache, max: uint32): T =
let maxAsInt = int(max) let maxAsInt = int(max)
return BlockCache( return BlockCache(
max: maxAsInt, max: maxAsInt, blocks: KeyedQueue[BlockHash, ExecutionData].init(maxAsInt)
blocks: KeyedQueue[BlockHash, ExecutionData].init(maxAsInt)
) )
func len*(self: BlockCache): int = func len*(self: BlockCache): int =
@ -42,18 +36,15 @@ proc add*(self: BlockCache, payload: ExecutionData) =
return return
if len(self.blocks) >= self.max: if len(self.blocks) >= self.max:
discard self.blocks.shift() discard self.blocks.shift()
discard self.blocks.append(payload.blockHash, payload) discard self.blocks.append(payload.blockHash, payload)
proc latest*(self: BlockCache): results.Opt[ExecutionData] = proc latest*(self: BlockCache): results.Opt[ExecutionData] =
let latestPair = ? self.blocks.last() let latestPair = ?self.blocks.last()
return Opt.some(latestPair.data) return Opt.some(latestPair.data)
proc getByNumber*( proc getByNumber*(self: BlockCache, number: Quantity): Opt[ExecutionData] =
self: BlockCache,
number: Quantity): Opt[ExecutionData] =
var payloadResult: Opt[ExecutionData] var payloadResult: Opt[ExecutionData]
for payload in self.blocks.prevValues: for payload in self.blocks.prevValues:
@ -63,7 +54,5 @@ proc getByNumber*(
return payloadResult return payloadResult
proc getPayloadByHash*( proc getPayloadByHash*(self: BlockCache, hash: BlockHash): Opt[ExecutionData] =
self: BlockCache,
hash: BlockHash): Opt[ExecutionData] =
return self.blocks.eq(hash) return self.blocks.eq(hash)

View File

@ -18,14 +18,14 @@ proc NimMain() {.importc, exportc, dynlib.}
var initialized: Atomic[bool] var initialized: Atomic[bool]
proc initLib() = proc initLib() =
if not initialized.exchange(true): if not initialized.exchange(true):
NimMain() # Every Nim library needs to call `NimMain` once exactly NimMain() # Every Nim library needs to call `NimMain` once exactly
when declared(setupForeignThreadGc): setupForeignThreadGc() when declared(setupForeignThreadGc):
when declared(nimGC_setStackBottom): setupForeignThreadGc()
var locals {.volatile, noinit.}: pointer when declared(nimGC_setStackBottom):
locals = addr(locals) var locals {.volatile, noinit.}: pointer
nimGC_setStackBottom(locals) locals = addr(locals)
nimGC_setStackBottom(locals)
proc runContext(ctx: ptr Context) {.thread.} = proc runContext(ctx: ptr Context) {.thread.} =
let str = $ctx.configJson let str = $ctx.configJson
@ -57,7 +57,6 @@ proc runContext(ctx: ptr Context) {.thread.} =
ctx.onHeader(getCurrentExceptionMsg(), 3) ctx.onHeader(getCurrentExceptionMsg(), 3)
ctx.cleanup() ctx.cleanup()
#[let node = parseConfigAndRun(ctx.configJson) #[let node = parseConfigAndRun(ctx.configJson)
while not ctx[].stop: # and node.running: while not ctx[].stop: # and node.running:
@ -67,7 +66,9 @@ proc runContext(ctx: ptr Context) {.thread.} =
# do cleanup # do cleanup
node.stop()]# node.stop()]#
proc startVerifProxy*(configJson: cstring, onHeader: OnHeaderCallback): ptr Context {.exportc, dynlib.} = proc startVerifProxy*(
configJson: cstring, onHeader: OnHeaderCallback
): ptr Context {.exportc, dynlib.} =
initLib() initLib()
let ctx = createShared(Context, 1) let ctx = createShared(Context, 1)
@ -78,12 +79,11 @@ proc startVerifProxy*(configJson: cstring, onHeader: OnHeaderCallback): ptr Cont
try: try:
createThread(ctx.thread, runContext, ctx) createThread(ctx.thread, runContext, ctx)
except Exception as err: except Exception as err:
echo "Exception when attempting to invoke createThread ", getCurrentExceptionMsg(), err.getStackTrace() echo "Exception when attempting to invoke createThread ",
getCurrentExceptionMsg(), err.getStackTrace()
ctx.onHeader(getCurrentExceptionMsg(), 3) ctx.onHeader(getCurrentExceptionMsg(), 3)
ctx.cleanup() ctx.cleanup()
return ctx return ctx
proc stopVerifProxy*(ctx: ptr Context) {.exportc, dynlib.} = proc stopVerifProxy*(ctx: ptr Context) {.exportc, dynlib.} =
ctx.stop = true ctx.stop = true

View File

@ -9,7 +9,9 @@
import import
std/[atomics, json, os, strutils], std/[atomics, json, os, strutils],
chronicles, chronos, confutils, chronicles,
chronos,
confutils,
eth/keys, eth/keys,
json_rpc/rpcproxy, json_rpc/rpcproxy,
beacon_chain/el/el_manager, beacon_chain/el/el_manager,
@ -17,7 +19,7 @@ import
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, ../nimbus/rpc/cors,
"."/rpc/[rpc_eth_api, rpc_utils], "."/rpc/[rpc_eth_api, rpc_utils],
./nimbus_verified_proxy_conf, ./nimbus_verified_proxy_conf,
@ -26,7 +28,7 @@ import
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
type OnHeaderCallback* = proc (s: cstring, t: int) {.cdecl, raises: [], gcsafe.} type OnHeaderCallback* = proc(s: cstring, t: int) {.cdecl, raises: [], gcsafe.}
type Context* = object type Context* = object
thread*: Thread[ptr Context] thread*: Thread[ptr Context]
configJson*: cstring configJson*: cstring
@ -37,21 +39,23 @@ proc cleanup*(ctx: ptr Context) =
dealloc(ctx.configJson) dealloc(ctx.configJson)
freeShared(ctx) freeShared(ctx)
func getConfiguredChainId(networkMetadata: Eth2NetworkMetadata): Quantity = func getConfiguredChainId(networkMetadata: Eth2NetworkMetadata): Quantity =
if networkMetadata.eth1Network.isSome(): if networkMetadata.eth1Network.isSome():
let let
net = networkMetadata.eth1Network.get() net = networkMetadata.eth1Network.get()
chainId = case net chainId =
case net
of mainnet: 1.Quantity of mainnet: 1.Quantity
of goerli: 5.Quantity of goerli: 5.Quantity
of sepolia: 11155111.Quantity of sepolia: 11155111.Quantity
of holesky: 17000.Quantity of holesky: 17000.Quantity
return chainId return chainId
else: else:
return networkMetadata.cfg.DEPOSIT_CHAIN_ID.Quantity return networkMetadata.cfg.DEPOSIT_CHAIN_ID.Quantity
proc run*(config: VerifiedProxyConf, ctx: ptr Context) {.raises: [CatchableError], gcsafe.} = proc run*(
config: VerifiedProxyConf, ctx: ptr Context
) {.raises: [CatchableError], gcsafe.} =
var headerCallback: OnHeaderCallback var headerCallback: OnHeaderCallback
if ctx != nil: if ctx != nil:
headerCallback = ctx.onHeader headerCallback = ctx.onHeader
@ -75,26 +79,32 @@ proc run*(config: VerifiedProxyConf, ctx: ptr Context) {.raises: [CatchableError
for node in metadata.bootstrapNodes: for node in metadata.bootstrapNodes:
lcConfig.bootstrapNodes.add node lcConfig.bootstrapNodes.add node
template cfg(): auto = metadata.cfg template cfg(): auto =
metadata.cfg
let let
genesisState = genesisState =
try: try:
template genesisData(): auto = metadata.genesis.bakedBytes template genesisData(): auto =
newClone(readSszForkedHashedBeaconState( metadata.genesis.bakedBytes
cfg, genesisData.toOpenArray(genesisData.low, genesisData.high)))
newClone(
readSszForkedHashedBeaconState(
cfg, genesisData.toOpenArray(genesisData.low, genesisData.high)
)
)
except CatchableError as err: except CatchableError as err:
raiseAssert "Invalid baked-in state: " & err.msg raiseAssert "Invalid baked-in state: " & err.msg
genesisTime = getStateField(genesisState[], genesis_time) genesisTime = getStateField(genesisState[], genesis_time)
beaconClock = BeaconClock.init(genesisTime).valueOr: beaconClock =
error "Invalid genesis time in state", genesisTime BeaconClock.init(genesisTime).valueOr:
quit QuitFailure error "Invalid genesis time in state", genesisTime
quit QuitFailure
getBeaconTime = beaconClock.getBeaconTimeFn() getBeaconTime = beaconClock.getBeaconTimeFn()
genesis_validators_root = genesis_validators_root = getStateField(genesisState[], genesis_validators_root)
getStateField(genesisState[], genesis_validators_root)
forkDigests = newClone ForkDigests.init(cfg, genesis_validators_root) forkDigests = newClone ForkDigests.init(cfg, genesis_validators_root)
genesisBlockRoot = get_initial_beacon_block(genesisState[]).root genesisBlockRoot = get_initial_beacon_block(genesisState[]).root
@ -104,8 +114,7 @@ proc run*(config: VerifiedProxyConf, ctx: ptr Context) {.raises: [CatchableError
netKeys = getRandomNetKeys(rng[]) netKeys = getRandomNetKeys(rng[])
network = createEth2Node( network = createEth2Node(
rng, lcConfig, netKeys, cfg, rng, lcConfig, netKeys, cfg, forkDigests, getBeaconTime, genesis_validators_root
forkDigests, getBeaconTime, genesis_validators_root
) )
blockCache = BlockCache.new(uint32(64)) blockCache = BlockCache.new(uint32(64))
@ -116,64 +125,71 @@ proc run*(config: VerifiedProxyConf, ctx: ptr Context) {.raises: [CatchableError
clientConfig = config.web3url.asClientConfig() clientConfig = config.web3url.asClientConfig()
rpcProxy = RpcProxy.new( rpcProxy = RpcProxy.new(
[initTAddress(config.rpcAddress, config.rpcPort)], [initTAddress(config.rpcAddress, config.rpcPort)], clientConfig, authHooks
clientConfig,
authHooks
) )
verifiedProxy = VerifiedRpcProxy.new(rpcProxy, blockCache, chainId) verifiedProxy = VerifiedRpcProxy.new(rpcProxy, blockCache, chainId)
optimisticHandler = proc(signedBlock: ForkedMsgTrustedSignedBeaconBlock): optimisticHandler = proc(
Future[void] {.async: (raises: [CancelledError]).} = signedBlock: ForkedMsgTrustedSignedBeaconBlock
): Future[void] {.async: (raises: [CancelledError]).} =
notice "New LC optimistic block", notice "New LC optimistic block",
opt = signedBlock.toBlockId(), opt = signedBlock.toBlockId(), wallSlot = getBeaconTime().slotOrZero
wallSlot = getBeaconTime().slotOrZero
withBlck(signedBlock): withBlck(signedBlock):
when consensusFork >= ConsensusFork.Bellatrix: when consensusFork >= ConsensusFork.Bellatrix:
if forkyBlck.message.is_execution_block: if forkyBlck.message.is_execution_block:
template payload(): auto = forkyBlck.message.body.execution_payload template payload(): auto =
forkyBlck.message.body.execution_payload
blockCache.add(asExecutionData(payload.asEngineExecutionPayload())) blockCache.add(asExecutionData(payload.asEngineExecutionPayload()))
else: discard else:
discard
return return
optimisticProcessor = initOptimisticProcessor( optimisticProcessor = initOptimisticProcessor(getBeaconTime, optimisticHandler)
getBeaconTime, optimisticHandler)
lightClient = createLightClient( lightClient = createLightClient(
network, rng, lcConfig, cfg, forkDigests, getBeaconTime, network, rng, lcConfig, cfg, forkDigests, getBeaconTime, genesis_validators_root,
genesis_validators_root, LightClientFinalizationMode.Optimistic) LightClientFinalizationMode.Optimistic
)
verifiedProxy.installEthApiHandlers() verifiedProxy.installEthApiHandlers()
info "Listening to incoming network requests" info "Listening to incoming network requests"
network.registerProtocol( network.registerProtocol(
PeerSync, PeerSync.NetworkState.init( PeerSync,
cfg, forkDigests, genesisBlockRoot, getBeaconTime)) PeerSync.NetworkState.init(cfg, forkDigests, genesisBlockRoot, getBeaconTime),
)
network.addValidator( network.addValidator(
getBeaconBlocksTopic(forkDigests.phase0), getBeaconBlocksTopic(forkDigests.phase0),
proc (signedBlock: phase0.SignedBeaconBlock): ValidationResult = proc(signedBlock: phase0.SignedBeaconBlock): ValidationResult =
toValidationResult( toValidationResult(optimisticProcessor.processSignedBeaconBlock(signedBlock))
optimisticProcessor.processSignedBeaconBlock(signedBlock))) ,
)
network.addValidator( network.addValidator(
getBeaconBlocksTopic(forkDigests.altair), getBeaconBlocksTopic(forkDigests.altair),
proc (signedBlock: altair.SignedBeaconBlock): ValidationResult = proc(signedBlock: altair.SignedBeaconBlock): ValidationResult =
toValidationResult( toValidationResult(optimisticProcessor.processSignedBeaconBlock(signedBlock))
optimisticProcessor.processSignedBeaconBlock(signedBlock))) ,
)
network.addValidator( network.addValidator(
getBeaconBlocksTopic(forkDigests.bellatrix), getBeaconBlocksTopic(forkDigests.bellatrix),
proc (signedBlock: bellatrix.SignedBeaconBlock): ValidationResult = proc(signedBlock: bellatrix.SignedBeaconBlock): ValidationResult =
toValidationResult( toValidationResult(optimisticProcessor.processSignedBeaconBlock(signedBlock))
optimisticProcessor.processSignedBeaconBlock(signedBlock))) ,
)
network.addValidator( network.addValidator(
getBeaconBlocksTopic(forkDigests.capella), getBeaconBlocksTopic(forkDigests.capella),
proc (signedBlock: capella.SignedBeaconBlock): ValidationResult = proc(signedBlock: capella.SignedBeaconBlock): ValidationResult =
toValidationResult( toValidationResult(optimisticProcessor.processSignedBeaconBlock(signedBlock))
optimisticProcessor.processSignedBeaconBlock(signedBlock))) ,
)
network.addValidator( network.addValidator(
getBeaconBlocksTopic(forkDigests.deneb), getBeaconBlocksTopic(forkDigests.deneb),
proc (signedBlock: deneb.SignedBeaconBlock): ValidationResult = proc(signedBlock: deneb.SignedBeaconBlock): ValidationResult =
toValidationResult( toValidationResult(optimisticProcessor.processSignedBeaconBlock(signedBlock))
optimisticProcessor.processSignedBeaconBlock(signedBlock))) ,
)
lightClient.installMessageValidators() lightClient.installMessageValidators()
waitFor network.startListening() waitFor network.startListening()
@ -182,31 +198,29 @@ proc run*(config: VerifiedProxyConf, ctx: ptr Context) {.raises: [CatchableError
waitFor verifiedProxy.verifyChaindId() waitFor verifiedProxy.verifyChaindId()
proc onFinalizedHeader( proc onFinalizedHeader(
lightClient: LightClient, finalizedHeader: ForkedLightClientHeader) = lightClient: LightClient, finalizedHeader: ForkedLightClientHeader
) =
withForkyHeader(finalizedHeader): withForkyHeader(finalizedHeader):
when lcDataFork > LightClientDataFork.None: when lcDataFork > LightClientDataFork.None:
info "New LC finalized header", info "New LC finalized header", finalized_header = shortLog(forkyHeader)
finalized_header = shortLog(forkyHeader)
if headerCallback != nil: if headerCallback != nil:
try: try:
headerCallback(Json.encode(forkyHeader), 0) headerCallback(Json.encode(forkyHeader), 0)
except SerializationError as e: except SerializationError as e:
notice "finalizedHeaderCallback exception" notice "finalizedHeaderCallback exception"
proc onOptimisticHeader( proc onOptimisticHeader(
lightClient: LightClient, optimisticHeader: ForkedLightClientHeader) = lightClient: LightClient, optimisticHeader: ForkedLightClientHeader
) =
withForkyHeader(optimisticHeader): withForkyHeader(optimisticHeader):
when lcDataFork > LightClientDataFork.None: when lcDataFork > LightClientDataFork.None:
info "New LC optimistic header", info "New LC optimistic header", optimistic_header = shortLog(forkyHeader)
optimistic_header = shortLog(forkyHeader)
optimisticProcessor.setOptimisticHeader(forkyHeader.beacon) optimisticProcessor.setOptimisticHeader(forkyHeader.beacon)
if headerCallback != nil: if headerCallback != nil:
try: try:
headerCallback(Json.encode(forkyHeader), 1) headerCallback(Json.encode(forkyHeader), 1)
except SerializationError as e: except SerializationError as e:
notice "optimisticHeaderCallback exception" notice "optimisticHeaderCallback exception"
lightClient.onFinalizedHeader = onFinalizedHeader lightClient.onFinalizedHeader = onFinalizedHeader
lightClient.onOptimisticHeader = onOptimisticHeader lightClient.onOptimisticHeader = onOptimisticHeader
@ -229,18 +243,19 @@ proc run*(config: VerifiedProxyConf, ctx: ptr Context) {.raises: [CatchableError
targetGossipState = getTargetGossipState( targetGossipState = getTargetGossipState(
slot.epoch, cfg.ALTAIR_FORK_EPOCH, cfg.BELLATRIX_FORK_EPOCH, slot.epoch, cfg.ALTAIR_FORK_EPOCH, cfg.BELLATRIX_FORK_EPOCH,
cfg.CAPELLA_FORK_EPOCH, cfg.DENEB_FORK_EPOCH, isBehind) cfg.CAPELLA_FORK_EPOCH, cfg.DENEB_FORK_EPOCH, isBehind
)
template currentGossipState(): auto =
blocksGossipState
template currentGossipState(): auto = blocksGossipState
if currentGossipState == targetGossipState: if currentGossipState == targetGossipState:
return return
if currentGossipState.card == 0 and targetGossipState.card > 0: if currentGossipState.card == 0 and targetGossipState.card > 0:
debug "Enabling blocks topic subscriptions", debug "Enabling blocks topic subscriptions", wallSlot = slot, targetGossipState
wallSlot = slot, targetGossipState
elif currentGossipState.card > 0 and targetGossipState.card == 0: elif currentGossipState.card > 0 and targetGossipState.card == 0:
debug "Disabling blocks topic subscriptions", debug "Disabling blocks topic subscriptions", wallSlot = slot
wallSlot = slot
else: else:
# Individual forks added / removed # Individual forks added / removed
discard discard
@ -256,8 +271,8 @@ proc run*(config: VerifiedProxyConf, ctx: ptr Context) {.raises: [CatchableError
for gossipFork in newGossipForks: for gossipFork in newGossipForks:
let forkDigest = forkDigests[].atConsensusFork(gossipFork) let forkDigest = forkDigests[].atConsensusFork(gossipFork)
network.subscribe( network.subscribe(
getBeaconBlocksTopic(forkDigest), blocksTopicParams, getBeaconBlocksTopic(forkDigest), blocksTopicParams, enableTopicMetrics = true
enableTopicMetrics = true) )
blocksGossipState = targetGossipState blocksGossipState = targetGossipState
@ -295,7 +310,7 @@ proc run*(config: VerifiedProxyConf, ctx: ptr Context) {.raises: [CatchableError
when isMainModule: when isMainModule:
{.pop.} {.pop.}
var config = makeBannerAndConfig( var config =
"Nimbus verified proxy " & fullVersionStr, VerifiedProxyConf) makeBannerAndConfig("Nimbus verified proxy " & fullVersionStr, VerifiedProxyConf)
{.push raises: [].} {.push raises: [].}
run(config, nil) run(config, nil)

View File

@ -1,5 +1,5 @@
# nimbus_verified_proxy # nimbus_verified_proxy
# Copyright (c) 2022-2023 Status Research & Development GmbH # Copyright (c) 2022-2024 Status Research & Development GmbH
# Licensed and distributed under either of # Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). # * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). # * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
@ -17,157 +17,166 @@ import
export net, conf export net, conf
proc defaultVerifiedProxyDataDir*(): string = proc defaultVerifiedProxyDataDir*(): string =
let dataDir = when defined(windows): let dataDir =
"AppData" / "Roaming" / "NimbusVerifiedProxy" when defined(windows):
elif defined(macosx): "AppData" / "Roaming" / "NimbusVerifiedProxy"
"Library" / "Application Support" / "NimbusVerifiedProxy" elif defined(macosx):
else: "Library" / "Application Support" / "NimbusVerifiedProxy"
".cache" / "nimbus-verified-proxy" else:
".cache" / "nimbus-verified-proxy"
getHomeDir() / dataDir getHomeDir() / dataDir
const const defaultDataVerifiedProxyDirDesc* = defaultVerifiedProxyDataDir()
defaultDataVerifiedProxyDirDesc* = defaultVerifiedProxyDataDir()
type type
Web3UrlKind* = enum Web3UrlKind* = enum
HttpUrl, WsUrl HttpUrl
WsUrl
Web3Url* = object Web3Url* = object
kind*: Web3UrlKind kind*: Web3UrlKind
web3Url*: string web3Url*: string
type VerifiedProxyConf* = object type VerifiedProxyConf* = object # Config
# Config configFile* {.desc: "Loads the configuration from a TOML file", name: "config-file".}:
configFile* {. Option[InputFile]
desc: "Loads the configuration from a TOML file"
name: "config-file" .}: Option[InputFile]
# Logging # Logging
logLevel* {. logLevel* {.desc: "Sets the log level", defaultValue: "INFO", name: "log-level".}:
desc: "Sets the log level" string
defaultValue: "INFO"
name: "log-level" .}: string
logStdout* {. logStdout* {.
hidden hidden,
desc: "Specifies what kind of logs should be written to stdout (auto, colors, nocolors, json)" desc:
defaultValueDesc: "auto" "Specifies what kind of logs should be written to stdout (auto, colors, nocolors, json)",
defaultValue: StdoutLogKind.Auto defaultValueDesc: "auto",
name: "log-format" .}: StdoutLogKind defaultValue: StdoutLogKind.Auto,
name: "log-format"
.}: StdoutLogKind
# Storage # Storage
dataDir* {. dataDir* {.
desc: "The directory where nimbus_verified_proxy will store all data" desc: "The directory where nimbus_verified_proxy will store all data",
defaultValue: defaultVerifiedProxyDataDir() defaultValue: defaultVerifiedProxyDataDir(),
defaultValueDesc: $defaultDataVerifiedProxyDirDesc defaultValueDesc: $defaultDataVerifiedProxyDirDesc,
abbr: "d" abbr: "d",
name: "data-dir" .}: OutDir name: "data-dir"
.}: OutDir
# Network # Network
eth2Network* {. eth2Network* {.
desc: "The Eth2 network to join" desc: "The Eth2 network to join", defaultValueDesc: "mainnet", name: "network"
defaultValueDesc: "mainnet" .}: Option[string]
name: "network" .}: Option[string]
# Consensus light sync # Consensus light sync
# No default - Needs to be provided by the user # No default - Needs to be provided by the user
trustedBlockRoot* {. trustedBlockRoot* {.
desc: "Recent trusted finalized block root to initialize the consensus light client from" desc:
name: "trusted-block-root" .}: Eth2Digest "Recent trusted finalized block root to initialize the consensus light client from",
name: "trusted-block-root"
.}: Eth2Digest
# (Untrusted) web3 provider # (Untrusted) web3 provider
# No default - Needs to be provided by the user # No default - Needs to be provided by the user
web3url* {. web3url* {.desc: "URL of the web3 data provider", name: "web3-url".}: Web3Url
desc: "URL of the web3 data provider"
name: "web3-url" .}: Web3Url
# Local JSON-RPC server # Local JSON-RPC server
rpcAddress* {. rpcAddress* {.
desc: "Listening address of the JSON-RPC server" desc: "Listening address of the JSON-RPC server",
defaultValue: defaultAdminListenAddress defaultValue: defaultAdminListenAddress,
defaultValueDesc: $defaultAdminListenAddressDesc defaultValueDesc: $defaultAdminListenAddressDesc,
name: "rpc-address" .}: IpAddress name: "rpc-address"
.}: IpAddress
rpcPort* {. rpcPort* {.
desc: "Listening port of the JSON-RPC server" desc: "Listening port of the JSON-RPC server", defaultValue: 8545, name: "rpc-port"
defaultValue: 8545 .}: Port
name: "rpc-port" .}: Port
# Libp2p # Libp2p
bootstrapNodes* {. bootstrapNodes* {.
desc: "Specifies one or more bootstrap nodes to use when connecting to the network" desc: "Specifies one or more bootstrap nodes to use when connecting to the network",
abbr: "b" abbr: "b",
name: "bootstrap-node" .}: seq[string] name: "bootstrap-node"
.}: seq[string]
bootstrapNodesFile* {. bootstrapNodesFile* {.
desc: "Specifies a line-delimited file of bootstrap Ethereum network addresses" desc: "Specifies a line-delimited file of bootstrap Ethereum network addresses",
defaultValue: "" defaultValue: "",
name: "bootstrap-file" .}: InputFile name: "bootstrap-file"
.}: InputFile
listenAddress* {. listenAddress* {.
desc: "Listening address for the Ethereum LibP2P and Discovery v5 traffic" desc: "Listening address for the Ethereum LibP2P and Discovery v5 traffic",
defaultValue: defaultListenAddress defaultValue: defaultListenAddress,
defaultValueDesc: $defaultListenAddressDesc defaultValueDesc: $defaultListenAddressDesc,
name: "listen-address" .}: IpAddress name: "listen-address"
.}: IpAddress
tcpPort* {. tcpPort* {.
desc: "Listening TCP port for Ethereum LibP2P traffic" desc: "Listening TCP port for Ethereum LibP2P traffic",
defaultValue: defaultEth2TcpPort defaultValue: defaultEth2TcpPort,
defaultValueDesc: $defaultEth2TcpPortDesc defaultValueDesc: $defaultEth2TcpPortDesc,
name: "tcp-port" .}: Port name: "tcp-port"
.}: Port
udpPort* {. udpPort* {.
desc: "Listening UDP port for node discovery" desc: "Listening UDP port for node discovery",
defaultValue: defaultEth2TcpPort defaultValue: defaultEth2TcpPort,
defaultValueDesc: $defaultEth2TcpPortDesc defaultValueDesc: $defaultEth2TcpPortDesc,
name: "udp-port" .}: Port name: "udp-port"
.}: Port
# TODO: Select a lower amount of peers. # TODO: Select a lower amount of peers.
maxPeers* {. maxPeers* {.
desc: "The target number of peers to connect to" desc: "The target number of peers to connect to",
defaultValue: 160 # 5 (fanout) * 64 (subnets) / 2 (subs) for a healthy mesh defaultValue: 160, # 5 (fanout) * 64 (subnets) / 2 (subs) for a healthy mesh
name: "max-peers" .}: int name: "max-peers"
.}: int
hardMaxPeers* {. hardMaxPeers* {.
desc: "The maximum number of peers to connect to. Defaults to maxPeers * 1.5" desc: "The maximum number of peers to connect to. Defaults to maxPeers * 1.5",
name: "hard-max-peers" .}: Option[int] name: "hard-max-peers"
.}: Option[int]
nat* {. nat* {.
desc: "Specify method to use for determining public address. " & desc:
"Must be one of: any, none, upnp, pmp, extip:<IP>" "Specify method to use for determining public address. " &
defaultValue: NatConfig(hasExtIp: false, nat: NatAny) "Must be one of: any, none, upnp, pmp, extip:<IP>",
defaultValueDesc: "any" defaultValue: NatConfig(hasExtIp: false, nat: NatAny),
name: "nat" .}: NatConfig defaultValueDesc: "any",
name: "nat"
.}: NatConfig
enrAutoUpdate* {. enrAutoUpdate* {.
desc: "Discovery can automatically update its ENR with the IP address " & desc:
"and UDP port as seen by other nodes it communicates with. " & "Discovery can automatically update its ENR with the IP address " &
"This option allows to enable/disable this functionality" "and UDP port as seen by other nodes it communicates with. " &
defaultValue: false "This option allows to enable/disable this functionality",
name: "enr-auto-update" .}: bool defaultValue: false,
name: "enr-auto-update"
.}: bool
agentString* {. agentString* {.
defaultValue: "nimbus", defaultValue: "nimbus",
desc: "Node agent string which is used as identifier in the LibP2P network" desc: "Node agent string which is used as identifier in the LibP2P network",
name: "agent-string" .}: string name: "agent-string"
.}: string
discv5Enabled* {. discv5Enabled* {.desc: "Enable Discovery v5", defaultValue: true, name: "discv5".}:
desc: "Enable Discovery v5" bool
defaultValue: true
name: "discv5" .}: bool
directPeers* {. directPeers* {.
desc: "The list of priviledged, secure and known peers to connect and" & desc:
"maintain the connection to, this requires a not random netkey-file." & "The list of priviledged, secure and known peers to connect and" &
"In the complete multiaddress format like:" & "maintain the connection to, this requires a not random netkey-file." &
"/ip4/<address>/tcp/<port>/p2p/<peerId-public-key>." & "In the complete multiaddress format like:" &
"Peering agreements are established out of band and must be reciprocal" "/ip4/<address>/tcp/<port>/p2p/<peerId-public-key>." &
name: "direct-peer" .}: seq[string] "Peering agreements are established out of band and must be reciprocal",
name: "direct-peer"
.}: seq[string]
proc parseCmdArg*(T: type Web3Url, p: string): T {.raises: [ValueError].} =
proc parseCmdArg*(
T: type Web3Url, p: string): T {.raises: [ValueError].} =
let let
url = parseUri(p) url = parseUri(p)
normalizedScheme = url.scheme.toLowerAscii() normalizedScheme = url.scheme.toLowerAscii()
@ -207,7 +216,7 @@ func asLightClientConf*(pc: VerifiedProxyConf): LightClientConf =
trustedBlockRoot: pc.trustedBlockRoot, trustedBlockRoot: pc.trustedBlockRoot,
web3Urls: @[EngineApiUrlConfigValue(url: pc.web3url.web3Url)], web3Urls: @[EngineApiUrlConfigValue(url: pc.web3url.web3Url)],
jwtSecret: none(InputFile), jwtSecret: none(InputFile),
stopAtEpoch: 0 stopAtEpoch: 0,
) )
# TODO: Cannot use ClientConfig in VerifiedProxyConf due to the fact that # TODO: Cannot use ClientConfig in VerifiedProxyConf due to the fact that

View File

@ -1,5 +1,5 @@
# nimbus_verified_proxy # nimbus_verified_proxy
# Copyright (c) 2022-2023 Status Research & Development GmbH # Copyright (c) 2022-2024 Status Research & Development GmbH
# Licensed and distributed under either of # Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). # * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). # * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
@ -37,7 +37,8 @@ type
chainId: Quantity chainId: Quantity
QuantityTagKind = enum QuantityTagKind = enum
LatestBlock, BlockNumber LatestBlock
BlockNumber
BlockTag = eth_api_types.RtBlockIdentifier BlockTag = eth_api_types.RtBlockIdentifier
@ -68,9 +69,8 @@ template rpcClient(lcProxy: VerifiedRpcProxy): RpcClient =
lcProxy.proxy.getClient() lcProxy.proxy.getClient()
proc getPayloadByTag( proc getPayloadByTag(
proxy: VerifiedRpcProxy, proxy: VerifiedRpcProxy, quantityTag: BlockTag
quantityTag: BlockTag): ): results.Opt[ExecutionData] {.raises: [ValueError].} =
results.Opt[ExecutionData] {.raises: [ValueError].} =
checkPreconditions(proxy) checkPreconditions(proxy)
let tagResult = parseQuantityTag(quantityTag) let tagResult = parseQuantityTag(quantityTag)
@ -88,9 +88,8 @@ proc getPayloadByTag(
return proxy.blockCache.getByNumber(tag.blockNumber) return proxy.blockCache.getByNumber(tag.blockNumber)
proc getPayloadByTagOrThrow( proc getPayloadByTagOrThrow(
proxy: VerifiedRpcProxy, proxy: VerifiedRpcProxy, quantityTag: BlockTag
quantityTag: BlockTag): ExecutionData {.raises: [ValueError].} = ): ExecutionData {.raises: [ValueError].} =
let tagResult = getPayloadByTag(proxy, quantityTag) let tagResult = getPayloadByTag(proxy, quantityTag)
if tagResult.isErr: if tagResult.isErr:
@ -109,7 +108,8 @@ proc installEthApiHandlers*(lcProxy: VerifiedRpcProxy) =
return lcProxy.blockCache.latest.get.blockNumber return lcProxy.blockCache.latest.get.blockNumber
lcProxy.proxy.rpc("eth_getBalance") do( lcProxy.proxy.rpc("eth_getBalance") do(
address: Address, quantityTag: BlockTag) -> UInt256: address: Address, quantityTag: BlockTag
) -> UInt256:
# When requesting state for `latest` block number, we need to translate # When requesting state for `latest` block number, we need to translate
# `latest` to actual block number as `latest` on proxy and on data provider # `latest` to actual block number as `latest` on proxy and on data provider
# can mean different blocks and ultimatly piece received piece of state # can mean different blocks and ultimatly piece received piece of state
@ -120,17 +120,11 @@ proc installEthApiHandlers*(lcProxy: VerifiedRpcProxy) =
info "Forwarding eth_getBalance call", blockNumber info "Forwarding eth_getBalance call", blockNumber
let proof = await lcProxy.rpcClient.eth_getProof( let proof = await lcProxy.rpcClient.eth_getProof(address, @[], blockId(blockNumber))
address, @[], blockId(blockNumber))
let accountResult = getAccountFromProof( let accountResult = getAccountFromProof(
executionPayload.stateRoot, executionPayload.stateRoot, proof.address, proof.balance, proof.nonce,
proof.address, proof.codeHash, proof.storageHash, proof.accountProof
proof.balance,
proof.nonce,
proof.codeHash,
proof.storageHash,
proof.accountProof
) )
if accountResult.isOk(): if accountResult.isOk():
@ -139,15 +133,16 @@ proc installEthApiHandlers*(lcProxy: VerifiedRpcProxy) =
raise newException(ValueError, accountResult.error) raise newException(ValueError, accountResult.error)
lcProxy.proxy.rpc("eth_getStorageAt") do( lcProxy.proxy.rpc("eth_getStorageAt") do(
address: Address, slot: UInt256, quantityTag: BlockTag) -> UInt256: address: Address, slot: UInt256, quantityTag: BlockTag
) -> UInt256:
let let
executionPayload = lcProxy.getPayloadByTagOrThrow(quantityTag) executionPayload = lcProxy.getPayloadByTagOrThrow(quantityTag)
blockNumber = executionPayload.blockNumber.uint64 blockNumber = executionPayload.blockNumber.uint64
info "Forwarding eth_getStorageAt", blockNumber info "Forwarding eth_getStorageAt", blockNumber
let proof = await lcProxy.rpcClient.eth_getProof( let proof =
address, @[slot], blockId(blockNumber)) await lcProxy.rpcClient.eth_getProof(address, @[slot], blockId(blockNumber))
let dataResult = getStorageData(executionPayload.stateRoot, slot, proof) let dataResult = getStorageData(executionPayload.stateRoot, slot, proof)
@ -158,24 +153,19 @@ proc installEthApiHandlers*(lcProxy: VerifiedRpcProxy) =
raise newException(ValueError, dataResult.error) raise newException(ValueError, dataResult.error)
lcProxy.proxy.rpc("eth_getTransactionCount") do( lcProxy.proxy.rpc("eth_getTransactionCount") do(
address: Address, quantityTag: BlockTag) -> Quantity: address: Address, quantityTag: BlockTag
) -> Quantity:
let let
executionPayload = lcProxy.getPayloadByTagOrThrow(quantityTag) executionPayload = lcProxy.getPayloadByTagOrThrow(quantityTag)
blockNumber = executionPayload.blockNumber.uint64 blockNumber = executionPayload.blockNumber.uint64
info "Forwarding eth_getTransactionCount", blockNumber info "Forwarding eth_getTransactionCount", blockNumber
let proof = await lcProxy.rpcClient.eth_getProof( let proof = await lcProxy.rpcClient.eth_getProof(address, @[], blockId(blockNumber))
address, @[], blockId(blockNumber))
let accountResult = getAccountFromProof( let accountResult = getAccountFromProof(
executionPayload.stateRoot, executionPayload.stateRoot, proof.address, proof.balance, proof.nonce,
proof.address, proof.codeHash, proof.storageHash, proof.accountProof
proof.balance,
proof.nonce,
proof.codeHash,
proof.storageHash,
proof.accountProof
) )
if accountResult.isOk(): if accountResult.isOk():
@ -184,22 +174,17 @@ proc installEthApiHandlers*(lcProxy: VerifiedRpcProxy) =
raise newException(ValueError, accountResult.error) raise newException(ValueError, accountResult.error)
lcProxy.proxy.rpc("eth_getCode") do( lcProxy.proxy.rpc("eth_getCode") do(
address: Address, quantityTag: BlockTag) -> seq[byte]: address: Address, quantityTag: BlockTag
) -> seq[byte]:
let let
executionPayload = lcProxy.getPayloadByTagOrThrow(quantityTag) executionPayload = lcProxy.getPayloadByTagOrThrow(quantityTag)
blockNumber = executionPayload.blockNumber.uint64 blockNumber = executionPayload.blockNumber.uint64
let let
proof = await lcProxy.rpcClient.eth_getProof( proof = await lcProxy.rpcClient.eth_getProof(address, @[], blockId(blockNumber))
address, @[], blockId(blockNumber))
accountResult = getAccountFromProof( accountResult = getAccountFromProof(
executionPayload.stateRoot, executionPayload.stateRoot, proof.address, proof.balance, proof.nonce,
proof.address, proof.codeHash, proof.storageHash, proof.accountProof
proof.balance,
proof.nonce,
proof.codeHash,
proof.storageHash,
proof.accountProof
) )
if accountResult.isErr(): if accountResult.isErr():
@ -213,16 +198,14 @@ proc installEthApiHandlers*(lcProxy: VerifiedRpcProxy) =
info "Forwarding eth_getCode", blockNumber info "Forwarding eth_getCode", blockNumber
let code = await lcProxy.rpcClient.eth_getCode( let code = await lcProxy.rpcClient.eth_getCode(address, blockId(blockNumber))
address,
blockId(blockNumber)
)
if isValidCode(account, code): if isValidCode(account, code):
return code return code
else: else:
raise newException(ValueError, raise newException(
"Received code which does not match the account code hash") ValueError, "Received code which does not match the account code hash"
)
# TODO: # TODO:
# Following methods are forwarded directly to the web3 provider and therefore # Following methods are forwarded directly to the web3 provider and therefore
@ -235,7 +218,8 @@ proc installEthApiHandlers*(lcProxy: VerifiedRpcProxy) =
# TODO currently we do not handle fullTransactions flag. It require updates on # TODO currently we do not handle fullTransactions flag. It require updates on
# nim-web3 side # nim-web3 side
lcProxy.proxy.rpc("eth_getBlockByNumber") do( lcProxy.proxy.rpc("eth_getBlockByNumber") do(
quantityTag: BlockTag, fullTransactions: bool) -> Option[BlockObject]: quantityTag: BlockTag, fullTransactions: bool
) -> Option[BlockObject]:
let executionPayload = lcProxy.getPayloadByTag(quantityTag) let executionPayload = lcProxy.getPayloadByTag(quantityTag)
if executionPayload.isErr: if executionPayload.isErr:
@ -244,7 +228,8 @@ proc installEthApiHandlers*(lcProxy: VerifiedRpcProxy) =
return some(asBlockObject(executionPayload.get())) return some(asBlockObject(executionPayload.get()))
lcProxy.proxy.rpc("eth_getBlockByHash") do( lcProxy.proxy.rpc("eth_getBlockByHash") do(
blockHash: BlockHash, fullTransactions: bool) -> Option[BlockObject]: blockHash: BlockHash, fullTransactions: bool
) -> Option[BlockObject]:
let executionPayload = lcProxy.blockCache.getPayloadByHash(blockHash) let executionPayload = lcProxy.blockCache.getPayloadByHash(blockHash)
if executionPayload.isErr: if executionPayload.isErr:
@ -253,22 +238,16 @@ proc installEthApiHandlers*(lcProxy: VerifiedRpcProxy) =
return some(asBlockObject(executionPayload.get())) return some(asBlockObject(executionPayload.get()))
proc new*( proc new*(
T: type VerifiedRpcProxy, T: type VerifiedRpcProxy, proxy: RpcProxy, blockCache: BlockCache, chainId: Quantity
proxy: RpcProxy, ): T =
blockCache: BlockCache, VerifiedRpcProxy(proxy: proxy, blockCache: blockCache, chainId: chainId)
chainId: Quantity): T =
VerifiedRpcProxy(
proxy: proxy,
blockCache: blockCache,
chainId: chainId)
# Used to be in eth1_monitor.nim; not sure why it was deleted, # Used to be in eth1_monitor.nim; not sure why it was deleted,
# so I copied it here. --Adam # so I copied it here. --Adam
template awaitWithRetries*[T](lazyFutExpr: Future[T], template awaitWithRetries*[T](
retries = 3, lazyFutExpr: Future[T], retries = 3, timeout = 60.seconds
timeout = 60.seconds): untyped = ): untyped =
const const reqType = astToStr(lazyFutExpr)
reqType = astToStr(lazyFutExpr)
var var
retryDelayMs = 16000 retryDelayMs = 16000
f: Future[T] f: Future[T]
@ -281,7 +260,8 @@ template awaitWithRetries*[T](lazyFutExpr: Future[T],
await cancelAndWait(f) await cancelAndWait(f)
elif f.failed: elif f.failed:
when not (f.error of CatchableError): when not (f.error of CatchableError):
static: doAssert false, "f.error not CatchableError" static:
doAssert false, "f.error not CatchableError"
debug "Web3 request failed", req = reqType, err = f.error.msg debug "Web3 request failed", req = reqType, err = f.error.msg
else: else:
break break
@ -289,7 +269,8 @@ template awaitWithRetries*[T](lazyFutExpr: Future[T],
inc attempts inc attempts
if attempts >= retries: if attempts >= retries:
var errorMsg = reqType & " failed " & $retries & " times" var errorMsg = reqType & " failed " & $retries & " times"
if f.failed: errorMsg &= ". Last error: " & f.error.msg if f.failed:
errorMsg &= ". Last error: " & f.error.msg
raise newException(DataProviderFailure, errorMsg) raise newException(DataProviderFailure, errorMsg)
await sleepAsync(chronos.milliseconds(retryDelayMs)) await sleepAsync(chronos.milliseconds(retryDelayMs))
@ -302,20 +283,15 @@ proc verifyChaindId*(p: VerifiedRpcProxy): Future[void] {.async.} =
# retry 2 times, if the data provider fails despite the re-tries, propagate # retry 2 times, if the data provider fails despite the re-tries, propagate
# exception to the caller. # exception to the caller.
let providerId = awaitWithRetries( let providerId =
p.rpcClient.eth_chainId(), awaitWithRetries(p.rpcClient.eth_chainId(), retries = 2, timeout = seconds(30))
retries = 2,
timeout = seconds(30)
)
# This is a chain/network mismatch error between the Nimbus verified proxy and # This is a chain/network mismatch error between the Nimbus verified proxy and
# the application using it. Fail fast to avoid misusage. The user must fix # the application using it. Fail fast to avoid misusage. The user must fix
# the configuration. # the configuration.
if localId != providerId: if localId != providerId:
fatal "The specified data provider serves data for a different chain", fatal "The specified data provider serves data for a different chain",
expectedChain = distinctBase(localId), expectedChain = distinctBase(localId), providerChain = distinctBase(providerId)
providerChain = distinctBase(providerId)
quit 1 quit 1
return return

View File

@ -1,5 +1,5 @@
# nimbus_verified_proxy # nimbus_verified_proxy
# Copyright (c) 2022-2023 Status Research & Development GmbH # Copyright (c) 2022-2024 Status Research & Development GmbH
# Licensed and distributed under either of # Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). # * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). # * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
@ -17,27 +17,26 @@ import
web3/engine_api_types, web3/engine_api_types,
../../nimbus/db/core_db ../../nimbus/db/core_db
type type ExecutionData* = object
ExecutionData* = object parentHash*: BlockHash
parentHash*: BlockHash feeRecipient*: Address
feeRecipient*: Address stateRoot*: BlockHash
stateRoot*: BlockHash receiptsRoot*: BlockHash
receiptsRoot*: BlockHash logsBloom*: FixedBytes[256]
logsBloom*: FixedBytes[256] prevRandao*: FixedBytes[32]
prevRandao*: FixedBytes[32] blockNumber*: Quantity
blockNumber*: Quantity gasLimit*: Quantity
gasLimit*: Quantity gasUsed*: Quantity
gasUsed*: Quantity timestamp*: Quantity
timestamp*: Quantity extraData*: DynamicBytes[0, 32]
extraData*: DynamicBytes[0, 32] baseFeePerGas*: UInt256
baseFeePerGas*: UInt256 blockHash*: BlockHash
blockHash*: BlockHash transactions*: seq[TypedTransaction]
transactions*: seq[TypedTransaction] withdrawals*: seq[WithdrawalV1]
withdrawals*: seq[WithdrawalV1]
proc asExecutionData*( proc asExecutionData*(
payload: ExecutionPayloadV1 | ExecutionPayloadV2 | ExecutionPayloadV3): payload: ExecutionPayloadV1 | ExecutionPayloadV2 | ExecutionPayloadV3
ExecutionData = ): ExecutionData =
when payload is ExecutionPayloadV1: when payload is ExecutionPayloadV1:
return ExecutionData( return ExecutionData(
parentHash: payload.parentHash, parentHash: payload.parentHash,
@ -54,7 +53,7 @@ proc asExecutionData*(
baseFeePerGas: payload.baseFeePerGas, baseFeePerGas: payload.baseFeePerGas,
blockHash: payload.blockHash, blockHash: payload.blockHash,
transactions: payload.transactions, transactions: payload.transactions,
withdrawals: @[] withdrawals: @[],
) )
else: else:
# TODO: Deal with different payload types # TODO: Deal with different payload types
@ -73,7 +72,7 @@ proc asExecutionData*(
baseFeePerGas: payload.baseFeePerGas, baseFeePerGas: payload.baseFeePerGas,
blockHash: payload.blockHash, blockHash: payload.blockHash,
transactions: payload.transactions, transactions: payload.transactions,
withdrawals: payload.withdrawals withdrawals: payload.withdrawals,
) )
template unsafeQuantityToInt64(q: Quantity): int64 = template unsafeQuantityToInt64(q: Quantity): int64 =
@ -86,8 +85,8 @@ template asEthHash(hash: BlockHash): etypes.Hash256 =
etypes.Hash256(data: distinctBase(hash)) etypes.Hash256(data: distinctBase(hash))
proc calculateTransactionData( proc calculateTransactionData(
items: openArray[TypedTransaction]): items: openArray[TypedTransaction]
(etypes.Hash256, seq[TxOrHash], uint64) = ): (etypes.Hash256, seq[TxOrHash], uint64) =
## returns tuple composed of ## returns tuple composed of
## - root of transactions trie ## - root of transactions trie
## - list of transactions hashes ## - list of transactions hashes
@ -102,31 +101,28 @@ proc calculateTransactionData(
txHashes.add(txOrHash toFixedBytes(keccakHash(tx))) txHashes.add(txOrHash toFixedBytes(keccakHash(tx)))
return (tr.rootHash(), txHashes, txSize) return (tr.rootHash(), txHashes, txSize)
func blockHeaderSize( func blockHeaderSize(payload: ExecutionData, txRoot: etypes.Hash256): uint64 =
payload: ExecutionData, txRoot: etypes.Hash256): uint64 =
let bh = etypes.BlockHeader( let bh = etypes.BlockHeader(
parentHash : payload.parentHash.asEthHash, parentHash: payload.parentHash.asEthHash,
ommersHash : etypes.EMPTY_UNCLE_HASH, ommersHash: etypes.EMPTY_UNCLE_HASH,
coinbase : etypes.EthAddress payload.feeRecipient, coinbase: etypes.EthAddress payload.feeRecipient,
stateRoot : payload.stateRoot.asEthHash, stateRoot: payload.stateRoot.asEthHash,
txRoot : txRoot, txRoot: txRoot,
receiptRoot : payload.receiptsRoot.asEthHash, receiptRoot: payload.receiptsRoot.asEthHash,
bloom : distinctBase(payload.logsBloom), bloom: distinctBase(payload.logsBloom),
difficulty : default(etypes.DifficultyInt), difficulty: default(etypes.DifficultyInt),
blockNumber : payload.blockNumber.distinctBase.u256, blockNumber: payload.blockNumber.distinctBase.u256,
gasLimit : payload.gasLimit.unsafeQuantityToInt64, gasLimit: payload.gasLimit.unsafeQuantityToInt64,
gasUsed : payload.gasUsed.unsafeQuantityToInt64, gasUsed: payload.gasUsed.unsafeQuantityToInt64,
timestamp : payload.timestamp.EthTime, timestamp: payload.timestamp.EthTime,
extraData : bytes payload.extraData, extraData: bytes payload.extraData,
mixDigest : payload.prevRandao.asEthHash, mixDigest: payload.prevRandao.asEthHash,
nonce : default(etypes.BlockNonce), nonce: default(etypes.BlockNonce),
fee : some payload.baseFeePerGas fee: some payload.baseFeePerGas,
) )
return uint64(len(rlp.encode(bh))) return uint64(len(rlp.encode(bh)))
proc asBlockObject*( proc asBlockObject*(p: ExecutionData): BlockObject {.raises: [ValueError].} =
p: ExecutionData): BlockObject
{.raises: [ValueError].} =
# TODO: currently we always calculate txHashes as BlockObject does not have # TODO: currently we always calculate txHashes as BlockObject does not have
# option of returning full transactions. It needs fixing at nim-web3 library # option of returning full transactions. It needs fixing at nim-web3 library
# level # level
@ -156,6 +152,5 @@ proc asBlockObject*(
totalDifficulty: UInt256.zero, totalDifficulty: UInt256.zero,
transactions: txHashes, transactions: txHashes,
uncles: @[], uncles: @[],
baseFeePerGas: some(p.baseFeePerGas) baseFeePerGas: some(p.baseFeePerGas),
) )

View File

@ -1,5 +1,5 @@
# nimbus_verified_proxy # nimbus_verified_proxy
# Copyright (c) 2022-2023 Status Research & Development GmbH # Copyright (c) 2022-2024 Status Research & Development GmbH
# Licensed and distributed under either of # Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). # * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). # * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
@ -9,73 +9,144 @@
{.push raises: [].} {.push raises: [].}
import import unittest2, stint, stew/byteutils, web3, ../validate_proof
unittest2,
stint,
stew/byteutils,
web3,
../validate_proof
suite "Merkle proof of inclusion validation": suite "Merkle proof of inclusion validation":
test "Validate account proof": test "Validate account proof":
# Valid inclusion proof for account 0xf36f155486299ecaff2d4f5160ed5114c1f66000 # Valid inclusion proof for account 0xf36f155486299ecaff2d4f5160ed5114c1f66000
# at execution block 7533830 of goerli network # at execution block 7533830 of goerli network
let let
stateRoot = FixedBytes[32].fromHex("0x4cc43abefcb010e4176e82e44eadaa49a249d258867ba31f5c14d6099790a614") stateRoot = FixedBytes[32].fromHex(
codeHash = FixedBytes[32].fromHex("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470") "0x4cc43abefcb010e4176e82e44eadaa49a249d258867ba31f5c14d6099790a614"
storageRoot = FixedBytes[32].fromHex("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") )
codeHash = FixedBytes[32].fromHex(
"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
)
storageRoot = FixedBytes[32].fromHex(
"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
)
nonce = Quantity(uint64(71518)) nonce = Quantity(uint64(71518))
balance = UInt256.fromHex("3d25780abb5f0a89b7da") balance = UInt256.fromHex("3d25780abb5f0a89b7da")
address = Address(hexToByteArray[20]("0xf36f155486299ecaff2d4f5160ed5114c1f66000")) address =
rlpNodes = @[ Address(hexToByteArray[20]("0xf36f155486299ecaff2d4f5160ed5114c1f66000"))
RlpEncodedBytes(hexToSeqByte("0xf90211a00314821db27eb679525687656632f7fc3cd4e196dd8740a4fbf3c484d33cc87da0b32d41dd34b46eb2ed19133871e1c927a2b922662d512b0281965f9b44eae8dca0967240ead870312be02e54d36e91305ab81a92f9623ed1aa99505be9d05d8336a07324a33b901419dd8ae772a7ecf8a634dfbca267c1d7a8ae330800e997428db3a006dfd8d1aa5e9ceb38f3942d127a341f2b223ae2c52ec8d30528676d464c3936a04e0251f3bc74fe3a136d5de07adf754bdbf50046c1c07ef2575a8375fa780a25a0b58b1c4d2cb7cb0d5d03799ea1b9590054ac1ca12b9751a36a97bd6e5928e2d4a098af6c3153e28c974884a15b1559f27496d56d2b7cdc4dfa02ad7787adcfedbda05ab08ebefdda99feb3cb89f5d70b612de898fb387ac21d8334beb7d763748c63a0ba15badc1bb92fc1170d87b36ca1b600355312376b14802f9bc1028c6a1046e0a0bb89f3c908e5681b12b35795850ca555c41957ba680d5f88e5f4002ac092025ea0577014557fe78cca16ba9d98b7c2d1a4f1f5deb467ac24f4481cc733ff28088ca0a34409628aa8722d2977aeeb1a06a8b6220afdd20d7df376ae19d1c87fdddbeda06c59547c3b6eaec3330be1a224be6df0df62ab7d48a8b9d3dd7faf4bcef18725a087328e8cd421248ab4d6a9652e02bd27affed5ce0c4c1b7813bf9e6603b951b2a0e83ecf40ab16b2c1499c0a4431dbd507078268e31eab9f4d8747b7bfaf74b6e880")), rlpNodes =
RlpEncodedBytes(hexToSeqByte("0xf90211a0f8c7d5888d57dbc7c05198b347d48ccabae419b0240aa322b9ebc7eac04d6977a0b6190df5827a8de954713e947e6670f8424e3693ba43f514dbbc0e884b4a28a6a0708628ad543a7941dba0ddb1f1d4bf7844bba626a3a3aafd89b0385e72e57c56a08232da95725e034b1f3d9e9602765ad5e7598e7658ecad4db7c80993ca8cd82ea01ef4066c878575e664385f39ef77db1fb7a57a0a58e3b3c9b6cde5e310ddf399a02e845663f630667e0a3942b721a8dec00f01869afafcf668b0a7418cf4c89cc9a05f354987aac1183adabc4719a7b9c2607925f01d59d7334f391615b2bcbab59ea0090667b1bcf668a02a7e52c3abd65701f12ac6cebd8e2baafec3d5738c4f78bea07caa986367ce30ef3671ae12dbb31e273cdb8607bf4b4dca027eec19d68e1180a0b654499330b745fe687ff27aea175fc5ec1a170802de3422913b76742c46d29aa0f33e264f528eb4b18e558a81c5c44c8f626ed7da7a97db0f7f1f9dafc33d1793a030aa24216649d527b72e5d6e537ec39834828be1718d2454a83bbee7a4ff03e0a0b36d7321d4651737f7bf94e5a6c8e26f160a07d2c7dc572e64e2f3a332b34b9ea0c96767291f5bf5aa8849c96c9da108b2168f9268165916eb5e1fe25195a91afda011970351d8b437572eeda47c501b33c36601a2bc4f3f81aa6fc314300b8fb0f4a054558250264df1b4f7598c46ff847ee3cf880029377548d2f5dbe7ae9ea5ae6180")), @[
RlpEncodedBytes(hexToSeqByte("0xf90211a0645e0adf3fc44f24e122018134c8f3b354a9daf05489f9edea8421995af83d54a0f3aee49dabe2ee334de612dba0b5860b35373217f70860f1966fbf5ed87bd465a0959edf01ef89590429a1b024fd0f03c44a172725db0fbc2b06d3b48898756171a0b46320bd901a7c10859bb4855a558180fe03442d8f0ed5818aa0959ffac1cd52a0a137a658d13cc5cc1278f0e8f94d1c807183b81c248dd1d2d7d810d3888a84b5a0f472cc3565832a83d8f7196ecb582cb37ba5acce4e6d920854381101c6821dcfa0104bca973f514d8c49ea9ec29bd8e810f0126a8ee224a1d8dd38e841d9dffa64a0ade759bd4b3d4aee6afd2c6cc208d06cf61f18a3e368af4946d75270119b4417a065963fce379969fb0486089cae75302d029a5db1e11015e3ad74f0226f4e527ba0a3ee0d4db6e0a5c654ab98d3a52b06b1d5f91f481376ecbb1cb6be98221a8586a061426d1ccd902e701a6caaea223795d5f3e236aa55dce0460d2f045c6006fe3ca01619e291402e63179d5a0900bbce5604b32a1c0387611de2ddcb54ddee59f1aba0099661197942347bbe819915e9a5571ca39f0da8140f7bbf47a219a2914582ada0a7bcfa122de1249a971c58a59851a9a17d3818f4d8b6849c555ba822c5807b07a0e9d6d70a74952aaa417dac7af7ba0a730e296def339062a20e280f8149841d3aa0c5802c02299ecefe4d5881960cf7b18a1a7fa019c7a01d0ffa60ec22c68a96ec80")), RlpEncodedBytes(
RlpEncodedBytes(hexToSeqByte("0xf90211a0b33390ffe04f59199aa089264474955e382577538040fc9f772ad6b5c4c06e27a0a5fd2d2fbdd68b6117370131fcf2c721d0da0cf2d8f01a3ddf4ad5420cf92446a008f32325d4430b4a920fbe9501fb3a62f9b39519505b69de14e182d9e9c28fdaa049b6c110a5f95b039130fbe7c369e5c76b56d66c11b3cb49d15676b832c71ef9a018119a73e40c92fc80133e021351b5633dccee7c2e2d242cd621d43b7ec806a5a083d32aebce2b54863f4440dd80ef970ab5866a4fee9ce50336b51d6d6c6c514ca01432f1eb3e4afc6fa493fd75823455a86dd921c67ca7e0f81518ab35e5696ebda027ac89ec60eac73922fef5e0ff3d53e3a04a4dce200a9f9db673b595f94cd63fa060cac64c1ac701ab6ebc752f9678c5543b856ac1755a9fa497d036d59a761d43a012f241474b3c69e648a58f2decb402e5613b38119f052bc76841860919dfbf02a0fe6141f40b1e2106b560f85c69e533c9f8474be39c74adbfb27352c39b606c29a0a826e7c1ea4203742b201b9c87244042bb07acf7c75d5e171d548c4675748d79a010b898bbcbab926031138c96b851ab6ece680d0a0ee4ed9f0d3630505aefed00a0207ca951540621936ecb946527d630e987e1dae1f6b299615d5163cbae74c229a0680537757d58834489d865435cb3947988a361bba8ee446304d6dfe665581a75a0613b58f9069a610ebffaa7b8086a97ea3991587790eb1f096b90b9526ccf9d5280")), hexToSeqByte(
RlpEncodedBytes(hexToSeqByte("0xf90211a0f1b4b40950e332e3c246f6f6337bd559851b016d6b8eb7f40e31f01d63d5d003a02a77269847cfebd549834d7dac417f01b0f50d860e405305ec5988929b6c3339a0903f28b7912939efa6a807a4624702e28a6479583837b4e492aeae6a5d983a18a0638921e1fcf9bf9be37e6a648fa0ac7e1cc967abf4b975bb508515f9239260b2a015be428e82a9832418df65893858bb752f0aff3a380dd725854f64f5872b256ba09ea32765a32962713ba16c05bada54f7e4ac0e5da9fdc065f9c0deccecae61aba0a0c332c40ec2008c1d7e2176de631677317036c958991fa6a3773c9dabbd95fba06eaf67569e289f4f4c12486569b60325745a603d70fe836e28ed79abe608dd5fa0d09de843dd1de76e046a5de951db5330f03bc0b9df21d0a3ddb6a368f860cd09a063f9de11d14818fdfe6225306dbec74194c56a0f7b4c0cbb7c2200986d76d039a0a50fe5a0fac3e83bdaac397c0c4a32152e4ae756614961f2172492b42a576401a07119c9011c9eba49d196a878c6af0fe8204befccf6fb45ddce5ec0ebbe5d4c6da01d2ccefea315ac12691ce505e9bb828b731ce130b4108703f8ed7eedb2bcf1eba0e2fe8df21c00c13507e2b2870a213692ae455d4a6208f44e9bbd7d0a55b7cecba0ee91cbfa9b14ee3d2e958f0f6a383fa5da7dc667c0b93f6787b79861994d6f5fa089307ff3f6d958b9e5ef2e13ba5ceebaadcff82e99e92b6563acd0deef148e5c80")), "0xf90211a00314821db27eb679525687656632f7fc3cd4e196dd8740a4fbf3c484d33cc87da0b32d41dd34b46eb2ed19133871e1c927a2b922662d512b0281965f9b44eae8dca0967240ead870312be02e54d36e91305ab81a92f9623ed1aa99505be9d05d8336a07324a33b901419dd8ae772a7ecf8a634dfbca267c1d7a8ae330800e997428db3a006dfd8d1aa5e9ceb38f3942d127a341f2b223ae2c52ec8d30528676d464c3936a04e0251f3bc74fe3a136d5de07adf754bdbf50046c1c07ef2575a8375fa780a25a0b58b1c4d2cb7cb0d5d03799ea1b9590054ac1ca12b9751a36a97bd6e5928e2d4a098af6c3153e28c974884a15b1559f27496d56d2b7cdc4dfa02ad7787adcfedbda05ab08ebefdda99feb3cb89f5d70b612de898fb387ac21d8334beb7d763748c63a0ba15badc1bb92fc1170d87b36ca1b600355312376b14802f9bc1028c6a1046e0a0bb89f3c908e5681b12b35795850ca555c41957ba680d5f88e5f4002ac092025ea0577014557fe78cca16ba9d98b7c2d1a4f1f5deb467ac24f4481cc733ff28088ca0a34409628aa8722d2977aeeb1a06a8b6220afdd20d7df376ae19d1c87fdddbeda06c59547c3b6eaec3330be1a224be6df0df62ab7d48a8b9d3dd7faf4bcef18725a087328e8cd421248ab4d6a9652e02bd27affed5ce0c4c1b7813bf9e6603b951b2a0e83ecf40ab16b2c1499c0a4431dbd507078268e31eab9f4d8747b7bfaf74b6e880"
RlpEncodedBytes(hexToSeqByte("0xf90111a09725a5bda59d158e12856fd110eed37c2b2377833b01bbb730db1111658cb302a0acacf1fba3ed03da1672f5e12b06cc59a4e85eb8573bc64b30e598979963823f80808080808080a070555db94f94d4046ab94a7f99db7dc6caf8c1ddb9e083a8c807c99f96e0bf0ca0196f92289153376127494f86154dd26abf8273e443c4dc64d9d35ec974e63838a0969ef252c7141504f76fbb187f24e526035b3c649b18aa9d219ba9954c3312dda0bcb2b97af79709852e0f50edc795193938b18307e76f7dc87244c9dff11d5fe8a0bc7dcabe984dc42cef99f04a5c730b3c7e54f19014e6b18e5ee17add59c29b49a0d635c1be1b1ee4355531ffebdadd3cf470a0065c3a951063ef00fc60c5dece1d8080")), )
RlpEncodedBytes(hexToSeqByte("0xf8749e2070b0cf62febcfb17abd5e2189b6e0029e0f9b9a1aabf0e670469d6ab74b853f8518301175e8a3d25780abb5f0a89b7daa056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")) ),
] RlpEncodedBytes(
hexToSeqByte(
"0xf90211a0f8c7d5888d57dbc7c05198b347d48ccabae419b0240aa322b9ebc7eac04d6977a0b6190df5827a8de954713e947e6670f8424e3693ba43f514dbbc0e884b4a28a6a0708628ad543a7941dba0ddb1f1d4bf7844bba626a3a3aafd89b0385e72e57c56a08232da95725e034b1f3d9e9602765ad5e7598e7658ecad4db7c80993ca8cd82ea01ef4066c878575e664385f39ef77db1fb7a57a0a58e3b3c9b6cde5e310ddf399a02e845663f630667e0a3942b721a8dec00f01869afafcf668b0a7418cf4c89cc9a05f354987aac1183adabc4719a7b9c2607925f01d59d7334f391615b2bcbab59ea0090667b1bcf668a02a7e52c3abd65701f12ac6cebd8e2baafec3d5738c4f78bea07caa986367ce30ef3671ae12dbb31e273cdb8607bf4b4dca027eec19d68e1180a0b654499330b745fe687ff27aea175fc5ec1a170802de3422913b76742c46d29aa0f33e264f528eb4b18e558a81c5c44c8f626ed7da7a97db0f7f1f9dafc33d1793a030aa24216649d527b72e5d6e537ec39834828be1718d2454a83bbee7a4ff03e0a0b36d7321d4651737f7bf94e5a6c8e26f160a07d2c7dc572e64e2f3a332b34b9ea0c96767291f5bf5aa8849c96c9da108b2168f9268165916eb5e1fe25195a91afda011970351d8b437572eeda47c501b33c36601a2bc4f3f81aa6fc314300b8fb0f4a054558250264df1b4f7598c46ff847ee3cf880029377548d2f5dbe7ae9ea5ae6180"
)
),
RlpEncodedBytes(
hexToSeqByte(
"0xf90211a0645e0adf3fc44f24e122018134c8f3b354a9daf05489f9edea8421995af83d54a0f3aee49dabe2ee334de612dba0b5860b35373217f70860f1966fbf5ed87bd465a0959edf01ef89590429a1b024fd0f03c44a172725db0fbc2b06d3b48898756171a0b46320bd901a7c10859bb4855a558180fe03442d8f0ed5818aa0959ffac1cd52a0a137a658d13cc5cc1278f0e8f94d1c807183b81c248dd1d2d7d810d3888a84b5a0f472cc3565832a83d8f7196ecb582cb37ba5acce4e6d920854381101c6821dcfa0104bca973f514d8c49ea9ec29bd8e810f0126a8ee224a1d8dd38e841d9dffa64a0ade759bd4b3d4aee6afd2c6cc208d06cf61f18a3e368af4946d75270119b4417a065963fce379969fb0486089cae75302d029a5db1e11015e3ad74f0226f4e527ba0a3ee0d4db6e0a5c654ab98d3a52b06b1d5f91f481376ecbb1cb6be98221a8586a061426d1ccd902e701a6caaea223795d5f3e236aa55dce0460d2f045c6006fe3ca01619e291402e63179d5a0900bbce5604b32a1c0387611de2ddcb54ddee59f1aba0099661197942347bbe819915e9a5571ca39f0da8140f7bbf47a219a2914582ada0a7bcfa122de1249a971c58a59851a9a17d3818f4d8b6849c555ba822c5807b07a0e9d6d70a74952aaa417dac7af7ba0a730e296def339062a20e280f8149841d3aa0c5802c02299ecefe4d5881960cf7b18a1a7fa019c7a01d0ffa60ec22c68a96ec80"
)
),
RlpEncodedBytes(
hexToSeqByte(
"0xf90211a0b33390ffe04f59199aa089264474955e382577538040fc9f772ad6b5c4c06e27a0a5fd2d2fbdd68b6117370131fcf2c721d0da0cf2d8f01a3ddf4ad5420cf92446a008f32325d4430b4a920fbe9501fb3a62f9b39519505b69de14e182d9e9c28fdaa049b6c110a5f95b039130fbe7c369e5c76b56d66c11b3cb49d15676b832c71ef9a018119a73e40c92fc80133e021351b5633dccee7c2e2d242cd621d43b7ec806a5a083d32aebce2b54863f4440dd80ef970ab5866a4fee9ce50336b51d6d6c6c514ca01432f1eb3e4afc6fa493fd75823455a86dd921c67ca7e0f81518ab35e5696ebda027ac89ec60eac73922fef5e0ff3d53e3a04a4dce200a9f9db673b595f94cd63fa060cac64c1ac701ab6ebc752f9678c5543b856ac1755a9fa497d036d59a761d43a012f241474b3c69e648a58f2decb402e5613b38119f052bc76841860919dfbf02a0fe6141f40b1e2106b560f85c69e533c9f8474be39c74adbfb27352c39b606c29a0a826e7c1ea4203742b201b9c87244042bb07acf7c75d5e171d548c4675748d79a010b898bbcbab926031138c96b851ab6ece680d0a0ee4ed9f0d3630505aefed00a0207ca951540621936ecb946527d630e987e1dae1f6b299615d5163cbae74c229a0680537757d58834489d865435cb3947988a361bba8ee446304d6dfe665581a75a0613b58f9069a610ebffaa7b8086a97ea3991587790eb1f096b90b9526ccf9d5280"
)
),
RlpEncodedBytes(
hexToSeqByte(
"0xf90211a0f1b4b40950e332e3c246f6f6337bd559851b016d6b8eb7f40e31f01d63d5d003a02a77269847cfebd549834d7dac417f01b0f50d860e405305ec5988929b6c3339a0903f28b7912939efa6a807a4624702e28a6479583837b4e492aeae6a5d983a18a0638921e1fcf9bf9be37e6a648fa0ac7e1cc967abf4b975bb508515f9239260b2a015be428e82a9832418df65893858bb752f0aff3a380dd725854f64f5872b256ba09ea32765a32962713ba16c05bada54f7e4ac0e5da9fdc065f9c0deccecae61aba0a0c332c40ec2008c1d7e2176de631677317036c958991fa6a3773c9dabbd95fba06eaf67569e289f4f4c12486569b60325745a603d70fe836e28ed79abe608dd5fa0d09de843dd1de76e046a5de951db5330f03bc0b9df21d0a3ddb6a368f860cd09a063f9de11d14818fdfe6225306dbec74194c56a0f7b4c0cbb7c2200986d76d039a0a50fe5a0fac3e83bdaac397c0c4a32152e4ae756614961f2172492b42a576401a07119c9011c9eba49d196a878c6af0fe8204befccf6fb45ddce5ec0ebbe5d4c6da01d2ccefea315ac12691ce505e9bb828b731ce130b4108703f8ed7eedb2bcf1eba0e2fe8df21c00c13507e2b2870a213692ae455d4a6208f44e9bbd7d0a55b7cecba0ee91cbfa9b14ee3d2e958f0f6a383fa5da7dc667c0b93f6787b79861994d6f5fa089307ff3f6d958b9e5ef2e13ba5ceebaadcff82e99e92b6563acd0deef148e5c80"
)
),
RlpEncodedBytes(
hexToSeqByte(
"0xf90111a09725a5bda59d158e12856fd110eed37c2b2377833b01bbb730db1111658cb302a0acacf1fba3ed03da1672f5e12b06cc59a4e85eb8573bc64b30e598979963823f80808080808080a070555db94f94d4046ab94a7f99db7dc6caf8c1ddb9e083a8c807c99f96e0bf0ca0196f92289153376127494f86154dd26abf8273e443c4dc64d9d35ec974e63838a0969ef252c7141504f76fbb187f24e526035b3c649b18aa9d219ba9954c3312dda0bcb2b97af79709852e0f50edc795193938b18307e76f7dc87244c9dff11d5fe8a0bc7dcabe984dc42cef99f04a5c730b3c7e54f19014e6b18e5ee17add59c29b49a0d635c1be1b1ee4355531ffebdadd3cf470a0065c3a951063ef00fc60c5dece1d8080"
)
),
RlpEncodedBytes(
hexToSeqByte(
"0xf8749e2070b0cf62febcfb17abd5e2189b6e0029e0f9b9a1aabf0e670469d6ab74b853f8518301175e8a3d25780abb5f0a89b7daa056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
)
)
]
check: check:
getAccountFromProof( getAccountFromProof(
stateRoot, stateRoot, address, balance, nonce, codeHash, storageRoot, rlpNodes
address, )
balance, .isOk()
nonce,
codeHash,
storageRoot,
rlpNodes
).isOk()
test "Validate storage proof": test "Validate storage proof":
let slotValue = UInt256.fromHex("0x25a92a5853702f199bb2d805bba05d67025214a8") let slotValue = UInt256.fromHex("0x25a92a5853702f199bb2d805bba05d67025214a8")
let stateRoot = FixedBytes[32].fromHex("0x99b31961b56190853d6f20b17298c8e3aed0a88860f80d4662fb41712f93491d") let stateRoot = FixedBytes[32].fromHex(
"0x99b31961b56190853d6f20b17298c8e3aed0a88860f80d4662fb41712f93491d"
)
let proof = ProofResponse( let proof = ProofResponse(
address: Address(hexToByteArray[20]("0x805fe47d1fe7d86496753bb4b36206953c1ae660")), address: Address(hexToByteArray[20]("0x805fe47d1fe7d86496753bb4b36206953c1ae660")),
accountProof: @[ accountProof:
RlpEncodedBytes(hexToSeqByte("0xf90211a07399cef9c0d815f0ea8c485255564f7f749d3352f4cd13590b6354d521243433a0786151335ec66b81e6a5f8b0750d40a1440894febfae9021a246af0011dddc39a0d8be7a536ea6f5a70b6684a6bc5a954a3d87b424fe9c8d31e48b7697c2a439d6a0f270896eacce7a14d5f73c30c8d9864e18a7499a8c941872d0f543a583eed8d7a03d19b1d9c3294de123bab76b580db62e847b007ad24d7627c39513ad63ce7edea0cae2f92408fda1e856f7acb53c8f26984cc783dbb9ac8c4e93af362f458c2f0ca0fb6e6b3e8878fcd181be3b09eab73334d8ef6d89e26babf8072ba32e1ae5ce4aa016d11cb1bac71884c5057ec8afe714aa9b72125fb9ec6e2d9481869641a8e026a00d9828dddc21d4c4b5457a233ac518f508c88b3cd4e814eac2e28a2e2a632a08a00d396f8c462121f2e06a4288d668e98aafd2821d99b6dd1887aa660775318875a045c2a82a655fff0f7ab212635fff00ebf40e6918423f32c8abfeeb588a23c7c7a08be08722cc8bbd898101ce8a5299145d0964fd50eaf923f3feeb7df414c35fe5a0697c454102347fbd17fce54dc165220abac4ee992f1e19791c55ac17e14518e6a09502fa4ea94b14920ad984e6ab4d837068c5f00cfaefd1787a454a4705b4e2d5a08b9b53e865cd8910964ddfc3a0f1d87d8ea665ee9c0813d564de3744ffb147d7a0ae674b410e770b9fd691c72252a67ae461c82b91b88a9b42f1bbcc4a8733585780")), @[
RlpEncodedBytes(hexToSeqByte("0xf90211a09412f363cb562e21fccd9b4bb47a3b61215421eb9770b4a5730cb2cb6ea5bbc9a0ec0c28e23f6a9310c216965c08e1ec9c9fc9ec6112f12100263003be31d76e34a0378e652ba0a437830411206a126853271d599951a45d94a267ad5e31516563cca09b3a79cc886fd7dce88c60d39d8280ee625725b21e066358b8ca8c768911490ba088abe98c021c60a356abab43474f3fd9a3a852161b7933b0c8c932ba47e900cda052a527e30350d47b10cf22f43cf1ab288d8ffb723e6de54bc8f83b6189db2266a0bd5d883c317ab84c75785444ff61feae3ed9c2d4aab2017637ca8e974806e3c7a006c3451ace02de15b65cfd7c19c02c5c1040335f995dd957d3e07e8dc3079485a015af1df6ff5da1c38d32cf7a788c9764556e149c09bcfa92f020f77b155a03b4a0e0a5c318b7881c9e9a56d7f652a3532d5003565d5bd94337a180ce4ff1db8467a030d718ee799736a89d72b69189f1e27b0563d500ace86729685d056b09c6701ca0e2d4a13abc46bbe7b34290ca6ebd94dbbe228460fb6bb10413f6144459aa8463a0a7af172aa05889771cea29cdebdcd6bb7d4a6ec09b96629bbb64a99f4856fab8a07ece8ac878f91890f51a66f9ab6a145e1a6734cd2505ce8f2be7548617b065fda0c8819fca92b6ff1e3ea5624c0b4b582554ef7696a0e96fe696858739a8a5af9da0314d236293a35e001b071f1682bdc1e20c79af444b115fd0f8e697803b727d9180")), RlpEncodedBytes(
RlpEncodedBytes(hexToSeqByte("0xf90211a0e8dd0264185a25c11978679ef7f80c8e50804286b5f3f15ac26d11f8f4fe8612a0398a219de5df7abe3f16eb8571583d262196726e74575ad86b88e2e27a14c529a0aafdffb23bdb02384873ed6d5df2beaf8ba1a3d7eb89a7a9cf145861ef3fd18fa09f7299d9c05587feee543d34f49c59401997d6a9d44e78d7a144b002e838be7ea0bc385eca8be25dcdf3b6b58a230ef917da28e568dbff4ad05b054feec92bd53da0bea9a90577955f6fa5a60150f37b9e77a6b233e0b75168cfb3aec7d8eb098163a0ca0114d558ad84b5afd4f5a0bd5f7469758a446cffbed94c996e4c57302d9b0aa0158a3d1058957bc5cd41d816bdb42a066132cde9439b7c1925af42256cfcfc07a0ec12e2d93e3f7862e5c86de6131caae8ac623ddbc9109b74ebc62a5ed919f60aa0fd900e1d33be45abd3e1ddda1447739c2eb90e3b53604a16c65b44bd96b2a999a019693693106b6a90707e1c9bdad704dc128c8a5690c126d573daaf007f2aedcba0ce308e3364196afb1988196382015c90e8d65f349b72e60ced504870c7f307d3a0677e417e01c738c8818f647984dbfb7683820dd8a50dba02eeb79f4314f6d81ba0ecd210d3a979b55b6d33ebc53434441d3cade0e96d6a101a082bda6cd4ca88baa055d90842c7606222257aa1e98d949a23f7d676512bb21395bfacebc9d718e1bda027e473f101976ee9201de7f867158e165eedf3fe472567a9178d96ca6856c01c80")), hexToSeqByte(
RlpEncodedBytes(hexToSeqByte("0xf90211a09044017f2c2743fb2a70885262ce105c4d63095cc85e998b844ca5a08e2a6e14a020f6c529f0fcd791436640ba14ec77555cf06ac65cb75bd15a70270c940ad900a0c8f51f52d62882314e3b004ca0c3afdca1cb374582e484b10c371f553ff951c4a0975183fc3697fe81104fd4acc5e3a6167614786efcc52c940187cd517dc5f88fa00bf7e6698b3f1ba0963ced4ecd5f3fce6b7ae9346ee331ddfe54323a9027f944a06405c7db333d93ebad9e660b513373c974c5492012401a8ae14b5f2953c80e90a0bf9bad639ffcc1a8e047e03aace972039aa25c463c5880d1fd8907f684f82440a02cca4a3426ceabb8da2f06fe3491147a01eb0134128ec174d6836902f76ca9f2a070a886a555112f301b1545f883ed686519ae56cae46fb512e93986c37c63ec29a07df58e619bfcb18dc3ac5b49cf9eaa2817616e81e59204ccc66fd063b35aa4c6a09185c8c8e02e8a5dcfe642e776cf691208d0c79f8886585fc1bad1deebdf1dc8a0b660d946ab0ccca5467484c88789bc0baefcbb8f36b091f5758da2aa8f46a5e8a0127150d53d1b8d5aa81eeb898af87dbc55a2d0c2c6f1ef4d575e2dc1138dffa4a0a50a7266499bd407a2e60475df45b14cea1673957aca1a03740a5606117aa2bfa0434e10c0ff2e6b5ac8713a40b29bf8995e302c7d0b821c55c9f0cfc6d81fce87a0ed37d722b70122d0a5c96cd52810781b8b1a88277064d691a282d896fd301f0a80")), "0xf90211a07399cef9c0d815f0ea8c485255564f7f749d3352f4cd13590b6354d521243433a0786151335ec66b81e6a5f8b0750d40a1440894febfae9021a246af0011dddc39a0d8be7a536ea6f5a70b6684a6bc5a954a3d87b424fe9c8d31e48b7697c2a439d6a0f270896eacce7a14d5f73c30c8d9864e18a7499a8c941872d0f543a583eed8d7a03d19b1d9c3294de123bab76b580db62e847b007ad24d7627c39513ad63ce7edea0cae2f92408fda1e856f7acb53c8f26984cc783dbb9ac8c4e93af362f458c2f0ca0fb6e6b3e8878fcd181be3b09eab73334d8ef6d89e26babf8072ba32e1ae5ce4aa016d11cb1bac71884c5057ec8afe714aa9b72125fb9ec6e2d9481869641a8e026a00d9828dddc21d4c4b5457a233ac518f508c88b3cd4e814eac2e28a2e2a632a08a00d396f8c462121f2e06a4288d668e98aafd2821d99b6dd1887aa660775318875a045c2a82a655fff0f7ab212635fff00ebf40e6918423f32c8abfeeb588a23c7c7a08be08722cc8bbd898101ce8a5299145d0964fd50eaf923f3feeb7df414c35fe5a0697c454102347fbd17fce54dc165220abac4ee992f1e19791c55ac17e14518e6a09502fa4ea94b14920ad984e6ab4d837068c5f00cfaefd1787a454a4705b4e2d5a08b9b53e865cd8910964ddfc3a0f1d87d8ea665ee9c0813d564de3744ffb147d7a0ae674b410e770b9fd691c72252a67ae461c82b91b88a9b42f1bbcc4a8733585780"
RlpEncodedBytes(hexToSeqByte("0xf90211a05febd97d485ae84c4aa444320eddf9361b45ac0cd966eca4e86acadbbb9b1919a06b014b81f4328a4c92bd6639a0b7f06e55a875b5891b958e3f32aed237a60128a0878844a864828586bad11cc05427f942475e040da74a17affa41284c7c2b8a5ca0afa3cf559f694ca29166fd02462f8dc4263b25f5a6bcd012b5ea7792adf2aebba02ce34320a3ade650b5d6951fe0c6628a03ce227f06e46e2646f0dc85cb227348a01b4b6baed79a52ed6737deffe81b0f2fc55f2888639470266222946b9c85d47fa014b15187e49585497a789fa11b3499603a250f0f48f8f12313b453937239af72a0a304eac356264043417a7c9ca624d92ff08d32d3390d229a3ed96c089ac0a602a0f723b00e76886ba3206a92fa098996c87990e4231d4f08667201cc0891b778a7a0d67ede626d7500ad5d4f11bd9b9de562209627c50f3cfd967a03b41a17009a1aa04f46efe2492e2905d02802a7ff1f5d1718edfe36fcae46dd45954ee9861f13e1a042d8c5e5834755e7183313443996885b561b1ba6daa0e484b60d0becc245460da07302dec93846a62ecb50892edbc5a485775700aebf816badfa42af6e3853d16aa04b2b25079c39ad8d517a61e47141519b4b497b36c4edb81e6f34c7917823d414a01aac7bb66afad0b0e7f8ffeb928d34ab59fe428e4a77b30689956fabb94e9f56a01accc5cd467129ec35675c04625ae805dc974fef16119f49e44f27853aee58f480")), )
RlpEncodedBytes(hexToSeqByte("0xf90111a0d7559f6dc085b66ea2cf7928f3aff9ca07e9518113f44678a662b8fd5c91ab60a0b584675ea78138a4fd465b08895f3e791e717c2e259bff313d922994ad1085da80a0901123278214a37f6cd1d18d67c9ad8c51a64f8cf18c7de342d59a6b072d2f25a097533fa6c344fb668de71a3aa0c30da9190d2b6ce2974b05ba6caa9c8a9c495aa0344b048b149b2c08d1aa92ba1741009c6a8a4726bf5e7db12c78f4ad521122ae80808080a092677d6f81cdcafb80add68e79d7322af8771830d7d444a7587e8296203b16a88080a0930e22b8279f903ce0046cabc3cd24f2659dcb9c08980509ee0d12cc0ddecbee80a0156aa8328726c06af81bc6219dfada3e7826f1337da178258886015e94b0501c80")), ),
RlpEncodedBytes(hexToSeqByte("0xf8679e20da5951bceaed385c03546f45f276b83d86bc0755e045f92f1d9071f431b846f8440180a07bb85da974b0ee4efcb379f528bcf7e947a55901d5a2c0d38bc9cc16c851e785a03b45ab254ec24f2bcb75a922f15031796bc433ea5a4514783705d185321e5f82")) RlpEncodedBytes(
], hexToSeqByte(
"0xf90211a09412f363cb562e21fccd9b4bb47a3b61215421eb9770b4a5730cb2cb6ea5bbc9a0ec0c28e23f6a9310c216965c08e1ec9c9fc9ec6112f12100263003be31d76e34a0378e652ba0a437830411206a126853271d599951a45d94a267ad5e31516563cca09b3a79cc886fd7dce88c60d39d8280ee625725b21e066358b8ca8c768911490ba088abe98c021c60a356abab43474f3fd9a3a852161b7933b0c8c932ba47e900cda052a527e30350d47b10cf22f43cf1ab288d8ffb723e6de54bc8f83b6189db2266a0bd5d883c317ab84c75785444ff61feae3ed9c2d4aab2017637ca8e974806e3c7a006c3451ace02de15b65cfd7c19c02c5c1040335f995dd957d3e07e8dc3079485a015af1df6ff5da1c38d32cf7a788c9764556e149c09bcfa92f020f77b155a03b4a0e0a5c318b7881c9e9a56d7f652a3532d5003565d5bd94337a180ce4ff1db8467a030d718ee799736a89d72b69189f1e27b0563d500ace86729685d056b09c6701ca0e2d4a13abc46bbe7b34290ca6ebd94dbbe228460fb6bb10413f6144459aa8463a0a7af172aa05889771cea29cdebdcd6bb7d4a6ec09b96629bbb64a99f4856fab8a07ece8ac878f91890f51a66f9ab6a145e1a6734cd2505ce8f2be7548617b065fda0c8819fca92b6ff1e3ea5624c0b4b582554ef7696a0e96fe696858739a8a5af9da0314d236293a35e001b071f1682bdc1e20c79af444b115fd0f8e697803b727d9180"
)
),
RlpEncodedBytes(
hexToSeqByte(
"0xf90211a0e8dd0264185a25c11978679ef7f80c8e50804286b5f3f15ac26d11f8f4fe8612a0398a219de5df7abe3f16eb8571583d262196726e74575ad86b88e2e27a14c529a0aafdffb23bdb02384873ed6d5df2beaf8ba1a3d7eb89a7a9cf145861ef3fd18fa09f7299d9c05587feee543d34f49c59401997d6a9d44e78d7a144b002e838be7ea0bc385eca8be25dcdf3b6b58a230ef917da28e568dbff4ad05b054feec92bd53da0bea9a90577955f6fa5a60150f37b9e77a6b233e0b75168cfb3aec7d8eb098163a0ca0114d558ad84b5afd4f5a0bd5f7469758a446cffbed94c996e4c57302d9b0aa0158a3d1058957bc5cd41d816bdb42a066132cde9439b7c1925af42256cfcfc07a0ec12e2d93e3f7862e5c86de6131caae8ac623ddbc9109b74ebc62a5ed919f60aa0fd900e1d33be45abd3e1ddda1447739c2eb90e3b53604a16c65b44bd96b2a999a019693693106b6a90707e1c9bdad704dc128c8a5690c126d573daaf007f2aedcba0ce308e3364196afb1988196382015c90e8d65f349b72e60ced504870c7f307d3a0677e417e01c738c8818f647984dbfb7683820dd8a50dba02eeb79f4314f6d81ba0ecd210d3a979b55b6d33ebc53434441d3cade0e96d6a101a082bda6cd4ca88baa055d90842c7606222257aa1e98d949a23f7d676512bb21395bfacebc9d718e1bda027e473f101976ee9201de7f867158e165eedf3fe472567a9178d96ca6856c01c80"
)
),
RlpEncodedBytes(
hexToSeqByte(
"0xf90211a09044017f2c2743fb2a70885262ce105c4d63095cc85e998b844ca5a08e2a6e14a020f6c529f0fcd791436640ba14ec77555cf06ac65cb75bd15a70270c940ad900a0c8f51f52d62882314e3b004ca0c3afdca1cb374582e484b10c371f553ff951c4a0975183fc3697fe81104fd4acc5e3a6167614786efcc52c940187cd517dc5f88fa00bf7e6698b3f1ba0963ced4ecd5f3fce6b7ae9346ee331ddfe54323a9027f944a06405c7db333d93ebad9e660b513373c974c5492012401a8ae14b5f2953c80e90a0bf9bad639ffcc1a8e047e03aace972039aa25c463c5880d1fd8907f684f82440a02cca4a3426ceabb8da2f06fe3491147a01eb0134128ec174d6836902f76ca9f2a070a886a555112f301b1545f883ed686519ae56cae46fb512e93986c37c63ec29a07df58e619bfcb18dc3ac5b49cf9eaa2817616e81e59204ccc66fd063b35aa4c6a09185c8c8e02e8a5dcfe642e776cf691208d0c79f8886585fc1bad1deebdf1dc8a0b660d946ab0ccca5467484c88789bc0baefcbb8f36b091f5758da2aa8f46a5e8a0127150d53d1b8d5aa81eeb898af87dbc55a2d0c2c6f1ef4d575e2dc1138dffa4a0a50a7266499bd407a2e60475df45b14cea1673957aca1a03740a5606117aa2bfa0434e10c0ff2e6b5ac8713a40b29bf8995e302c7d0b821c55c9f0cfc6d81fce87a0ed37d722b70122d0a5c96cd52810781b8b1a88277064d691a282d896fd301f0a80"
)
),
RlpEncodedBytes(
hexToSeqByte(
"0xf90211a05febd97d485ae84c4aa444320eddf9361b45ac0cd966eca4e86acadbbb9b1919a06b014b81f4328a4c92bd6639a0b7f06e55a875b5891b958e3f32aed237a60128a0878844a864828586bad11cc05427f942475e040da74a17affa41284c7c2b8a5ca0afa3cf559f694ca29166fd02462f8dc4263b25f5a6bcd012b5ea7792adf2aebba02ce34320a3ade650b5d6951fe0c6628a03ce227f06e46e2646f0dc85cb227348a01b4b6baed79a52ed6737deffe81b0f2fc55f2888639470266222946b9c85d47fa014b15187e49585497a789fa11b3499603a250f0f48f8f12313b453937239af72a0a304eac356264043417a7c9ca624d92ff08d32d3390d229a3ed96c089ac0a602a0f723b00e76886ba3206a92fa098996c87990e4231d4f08667201cc0891b778a7a0d67ede626d7500ad5d4f11bd9b9de562209627c50f3cfd967a03b41a17009a1aa04f46efe2492e2905d02802a7ff1f5d1718edfe36fcae46dd45954ee9861f13e1a042d8c5e5834755e7183313443996885b561b1ba6daa0e484b60d0becc245460da07302dec93846a62ecb50892edbc5a485775700aebf816badfa42af6e3853d16aa04b2b25079c39ad8d517a61e47141519b4b497b36c4edb81e6f34c7917823d414a01aac7bb66afad0b0e7f8ffeb928d34ab59fe428e4a77b30689956fabb94e9f56a01accc5cd467129ec35675c04625ae805dc974fef16119f49e44f27853aee58f480"
)
),
RlpEncodedBytes(
hexToSeqByte(
"0xf90111a0d7559f6dc085b66ea2cf7928f3aff9ca07e9518113f44678a662b8fd5c91ab60a0b584675ea78138a4fd465b08895f3e791e717c2e259bff313d922994ad1085da80a0901123278214a37f6cd1d18d67c9ad8c51a64f8cf18c7de342d59a6b072d2f25a097533fa6c344fb668de71a3aa0c30da9190d2b6ce2974b05ba6caa9c8a9c495aa0344b048b149b2c08d1aa92ba1741009c6a8a4726bf5e7db12c78f4ad521122ae80808080a092677d6f81cdcafb80add68e79d7322af8771830d7d444a7587e8296203b16a88080a0930e22b8279f903ce0046cabc3cd24f2659dcb9c08980509ee0d12cc0ddecbee80a0156aa8328726c06af81bc6219dfada3e7826f1337da178258886015e94b0501c80"
)
),
RlpEncodedBytes(
hexToSeqByte(
"0xf8679e20da5951bceaed385c03546f45f276b83d86bc0755e045f92f1d9071f431b846f8440180a07bb85da974b0ee4efcb379f528bcf7e947a55901d5a2c0d38bc9cc16c851e785a03b45ab254ec24f2bcb75a922f15031796bc433ea5a4514783705d185321e5f82"
)
)
],
balance: UInt256.fromHex("0x0"), balance: UInt256.fromHex("0x0"),
codeHash: FixedBytes[32].fromHex("0x3b45ab254ec24f2bcb75a922f15031796bc433ea5a4514783705d185321e5f82"), codeHash: FixedBytes[32].fromHex(
"0x3b45ab254ec24f2bcb75a922f15031796bc433ea5a4514783705d185321e5f82"
),
nonce: Quantity(uint64(1)), nonce: Quantity(uint64(1)),
storageHash: FixedBytes[32].fromHex("0x7bb85da974b0ee4efcb379f528bcf7e947a55901d5a2c0d38bc9cc16c851e785"), storageHash: FixedBytes[32].fromHex(
storageProof: @[ "0x7bb85da974b0ee4efcb379f528bcf7e947a55901d5a2c0d38bc9cc16c851e785"
StorageProof( ),
key: u256(0), storageProof:
value: slotValue, @[
proof: @[ StorageProof(
RlpEncodedBytes(hexToSeqByte("0xf8b18080a0a24d07e12c3fedf892f5325b16f489fc7f14d267cef99aa6b7b74da7eab7a47a80a078a183d317824c686d46f3cf0a344cd5e1f8f73e095ea29864d3f8ef599dc643808080a0925cf9d2d4b35a02377f6ef9c51f1bbab4842dff4befd4ee5d85bbc15bb8554a808080a020db4b8930daa709db04119c07ee39896da3ac30b961b7901a7bea81a5329a8680a024f50ff7b56d6a9de8a2fcfe21e1710377dddb106c39c834362bd41a9bce22518080")), key: u256(0),
RlpEncodedBytes(hexToSeqByte("0xf7a0390decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563959425a92a5853702f199bb2d805bba05d67025214a8")) value: slotValue,
] proof:
) @[
] RlpEncodedBytes(
hexToSeqByte(
"0xf8b18080a0a24d07e12c3fedf892f5325b16f489fc7f14d267cef99aa6b7b74da7eab7a47a80a078a183d317824c686d46f3cf0a344cd5e1f8f73e095ea29864d3f8ef599dc643808080a0925cf9d2d4b35a02377f6ef9c51f1bbab4842dff4befd4ee5d85bbc15bb8554a808080a020db4b8930daa709db04119c07ee39896da3ac30b961b7901a7bea81a5329a8680a024f50ff7b56d6a9de8a2fcfe21e1710377dddb106c39c834362bd41a9bce22518080"
)
),
RlpEncodedBytes(
hexToSeqByte(
"0xf7a0390decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563959425a92a5853702f199bb2d805bba05d67025214a8"
)
)
],
)
],
) )
let validationResult = getStorageData(stateRoot, u256(0), proof) let validationResult = getStorageData(stateRoot, u256(0), proof)

View File

@ -1,5 +1,5 @@
# nimbus_verified_proxy # nimbus_verified_proxy
# Copyright (c) 2022-2023 Status Research & Development GmbH # Copyright (c) 2022-2024 Status Research & Development GmbH
# Licensed and distributed under either of # Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). # * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). # * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
@ -27,13 +27,12 @@ func emptyAccount(): etypes.Account =
nonce: uint64(0), nonce: uint64(0),
balance: UInt256.zero, balance: UInt256.zero,
storageRoot: etypes.EMPTY_ROOT_HASH, storageRoot: etypes.EMPTY_ROOT_HASH,
codeHash: etypes.EMPTY_CODE_HASH codeHash: etypes.EMPTY_CODE_HASH,
) )
proc isValidProof( proc isValidProof(
branch: seq[seq[byte]], branch: seq[seq[byte]], rootHash: KeccakHash, key, value: seq[byte]
rootHash: KeccakHash, ): bool =
key, value: seq[byte]): bool =
try: try:
# TODO: Investigate if this handles proof of non-existence. # TODO: Investigate if this handles proof of non-existence.
# Probably not as bool is not expressive enough to say if proof is valid, # Probably not as bool is not expressive enough to say if proof is valid,
@ -49,8 +48,8 @@ proc getAccountFromProof*(
accountNonce: Quantity, accountNonce: Quantity,
accountCodeHash: CodeHash, accountCodeHash: CodeHash,
accountStorageRootHash: StorageHash, accountStorageRootHash: StorageHash,
mptNodes: seq[RlpEncodedBytes] mptNodes: seq[RlpEncodedBytes],
): Result[etypes.Account, string] = ): Result[etypes.Account, string] =
let let
mptNodesBytes = mptNodes.mapIt(distinctBase(it)) mptNodesBytes = mptNodes.mapIt(distinctBase(it))
keccakStateRootHash = toMDigest(stateRoot) keccakStateRootHash = toMDigest(stateRoot)
@ -58,17 +57,13 @@ proc getAccountFromProof*(
nonce: distinctBase(accountNonce), nonce: distinctBase(accountNonce),
balance: accountBalance, balance: accountBalance,
storageRoot: toMDigest(accountStorageRootHash), storageRoot: toMDigest(accountStorageRootHash),
codeHash: toMDigest(accountCodeHash) codeHash: toMDigest(accountCodeHash),
) )
accountEncoded = rlp.encode(acc) accountEncoded = rlp.encode(acc)
accountKey = toSeq(keccakHash(distinctBase(accountAddress)).data) accountKey = toSeq(keccakHash(distinctBase(accountAddress)).data)
let proofResult = verifyMptProof( let proofResult =
mptNodesBytes, verifyMptProof(mptNodesBytes, keccakStateRootHash, accountKey, accountEncoded)
keccakStateRootHash,
accountKey,
accountEncoded
)
case proofResult.kind case proofResult.kind
of MissingKey: of MissingKey:
@ -79,14 +74,14 @@ proc getAccountFromProof*(
return err(proofResult.errorMsg) return err(proofResult.errorMsg)
proc getStorageData( proc getStorageData(
account: etypes.Account, account: etypes.Account, storageProof: StorageProof
storageProof: StorageProof): Result[UInt256, string] = ): Result[UInt256, string] =
let let
storageMptNodes = storageProof.proof.mapIt(distinctBase(it)) storageMptNodes = storageProof.proof.mapIt(distinctBase(it))
key = toSeq(keccakHash(toBytesBE(storageProof.key)).data) key = toSeq(keccakHash(toBytesBE(storageProof.key)).data)
encodedValue = rlp.encode(storageProof.value) encodedValue = rlp.encode(storageProof.value)
proofResult = verifyMptProof( proofResult =
storageMptNodes, account.storageRoot, key, encodedValue) verifyMptProof(storageMptNodes, account.storageRoot, key, encodedValue)
case proofResult.kind case proofResult.kind
of MissingKey: of MissingKey:
@ -97,19 +92,13 @@ proc getStorageData(
return err(proofResult.errorMsg) return err(proofResult.errorMsg)
proc getStorageData*( proc getStorageData*(
stateRoot: FixedBytes[32], stateRoot: FixedBytes[32], requestedSlot: UInt256, proof: ProofResponse
requestedSlot: UInt256, ): Result[UInt256, string] =
proof: ProofResponse): Result[UInt256, string] = let account =
?getAccountFromProof(
let account = ?getAccountFromProof( stateRoot, proof.address, proof.balance, proof.nonce, proof.codeHash,
stateRoot, proof.storageHash, proof.accountProof
proof.address, )
proof.balance,
proof.nonce,
proof.codeHash,
proof.storageHash,
proof.accountProof
)
if account.storageRoot == etypes.EMPTY_ROOT_HASH: if account.storageRoot == etypes.EMPTY_ROOT_HASH:
# valid account with empty storage, in that case getStorageAt # valid account with empty storage, in that case getStorageAt
@ -130,4 +119,4 @@ proc getStorageData*(
return getStorageData(account, sproof) return getStorageData(account, sproof)
func isValidCode*(account: etypes.Account, code: openArray[byte]): bool = func isValidCode*(account: etypes.Account, code: openArray[byte]): bool =
return account.codeHash == keccakHash(code) return account.codeHash == keccakHash(code)