More clean-up since eth types refactor (#2742)

This commit is contained in:
Kim De Mey 2024-10-16 14:18:02 +02:00 committed by GitHub
parent f797d55c35
commit b885f822d0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 63 additions and 112 deletions

View File

@ -10,6 +10,7 @@
import import
chronos, chronos,
testutils/unittests, testutils/unittests,
stew/byteutils,
json_rpc/rpcserver, json_rpc/rpcserver,
json_rpc/clients/httpclient, json_rpc/clients/httpclient,
stint, stint,
@ -67,6 +68,6 @@ procSuite "Discovery v5 JSON-RPC API":
check: check:
nodeEnr == tc.localDiscovery.localNode.record.toURI() nodeEnr == tc.localDiscovery.localNode.record.toURI()
nodeId == "0x" & tc.localDiscovery.localNode.id.toHex() nodeId == tc.localDiscovery.localNode.id.toBytesBE().to0xHex()
waitFor tc.stop() waitFor tc.stop()

View File

@ -79,9 +79,9 @@ func asReceipt(receiptObject: ReceiptObject): Result[Receipt, string] =
var logs: seq[Log] var logs: seq[Log]
if receiptObject.logs.len > 0: if receiptObject.logs.len > 0:
for log in receiptObject.logs: for log in receiptObject.logs:
var topics: seq[eth_types.Topic] var topics: seq[Topic]
for topic in log.topics: for topic in log.topics:
topics.add(eth_types.Topic(topic)) topics.add(Topic(topic))
logs.add(Log(address: log.address, data: log.data, topics: topics)) logs.add(Log(address: log.address, data: log.data, topics: topics))

View File

@ -12,7 +12,7 @@ import
chronos, chronos,
json_rpc/rpcclient, json_rpc/rpcclient,
stew/byteutils, stew/byteutils,
eth/keys, eth/common/keys,
./utp_test_rpc_client ./utp_test_rpc_client
proc generateBytesHex(rng: var HmacDrbgContext, length: int): string = proc generateBytesHex(rng: var HmacDrbgContext, length: int): string =

View File

@ -17,7 +17,7 @@ import
eth/p2p/discoveryv5/protocol, eth/p2p/discoveryv5/protocol,
eth/p2p/discoveryv5/enr, eth/p2p/discoveryv5/enr,
eth/utp/[utp_discv5_protocol, utp_router], eth/utp/[utp_discv5_protocol, utp_router],
eth/keys, eth/common/keys,
../../rpc/rpc_discovery_api, ../../rpc/rpc_discovery_api,
./utp_rpc_types ./utp_rpc_types
@ -46,7 +46,7 @@ proc writeValue*(w: var JsonWriter[JrpcConv], v: Record) {.gcsafe, raises: [IOEr
proc readValue*( proc readValue*(
r: var JsonReader[JrpcConv], val: var Record r: var JsonReader[JrpcConv], val: var Record
) {.gcsafe, raises: [IOError, JsonReaderError].} = ) {.gcsafe, raises: [IOError, JsonReaderError].} =
if not fromURI(val, r.parseString()): val = enr.Record.fromURI(r.parseString()).valueOr:
r.raiseUnexpectedValue("Invalid ENR") r.raiseUnexpectedValue("Invalid ENR")
proc installUtpHandlers( proc installUtpHandlers(

View File

@ -7,7 +7,7 @@
{.push raises: [].} {.push raises: [].}
import std/tables, web3/primitives, stew/keyed_queue, results, ./rpc/rpc_utils import eth/common/hashes, web3/primitives, stew/keyed_queue, results, ./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.
@ -15,15 +15,14 @@ import std/tables, web3/primitives, stew/keyed_queue, results, ./rpc/rpc_utils
## oldest payload is deleted first. ## oldest payload is deleted first.
type BlockCache* = ref object type BlockCache* = ref object
max: int max: int
blocks: KeyedQueue[BlockHash, ExecutionData] blocks: KeyedQueue[Hash32, ExecutionData]
proc `==`(x, y: Quantity): bool {.borrow, noSideEffect.} 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
max: maxAsInt, blocks: KeyedQueue[BlockHash, ExecutionData].init(maxAsInt) BlockCache(max: maxAsInt, blocks: KeyedQueue[Hash32, ExecutionData].init(maxAsInt))
)
func len*(self: BlockCache): int = func len*(self: BlockCache): int =
return len(self.blocks) return len(self.blocks)
@ -54,5 +53,5 @@ proc getByNumber*(self: BlockCache, number: Quantity): Opt[ExecutionData] =
return payloadResult return payloadResult
proc getPayloadByHash*(self: BlockCache, hash: BlockHash): Opt[ExecutionData] = proc getPayloadByHash*(self: BlockCache, hash: Hash32): Opt[ExecutionData] =
return self.blocks.eq(hash) return self.blocks.eq(hash)

View File

@ -200,7 +200,7 @@ proc run*(
try: try:
headerCallback(cstring(Json.encode(forkyHeader)), 0) headerCallback(cstring(Json.encode(forkyHeader)), 0)
except SerializationError as e: except SerializationError as e:
notice "finalizedHeaderCallback exception" error "finalizedHeaderCallback exception", error = e.msg
proc onOptimisticHeader( proc onOptimisticHeader(
lightClient: LightClient, optimisticHeader: ForkedLightClientHeader lightClient: LightClient, optimisticHeader: ForkedLightClientHeader
@ -212,7 +212,7 @@ proc run*(
try: try:
headerCallback(cstring(Json.encode(forkyHeader)), 1) headerCallback(cstring(Json.encode(forkyHeader)), 1)
except SerializationError as e: except SerializationError as e:
notice "optimisticHeaderCallback exception" error "optimisticHeaderCallback exception", error = e.msg
lightClient.onFinalizedHeader = onFinalizedHeader lightClient.onFinalizedHeader = onFinalizedHeader
lightClient.onOptimisticHeader = onOptimisticHeader lightClient.onOptimisticHeader = onOptimisticHeader

View File

@ -8,15 +8,14 @@
{.push raises: [].} {.push raises: [].}
import import
std/[strutils, typetraits], std/strutils,
stint, stint,
stew/byteutils, stew/byteutils,
results, results,
chronicles, chronicles,
json_rpc/[rpcproxy, rpcserver, rpcclient], json_rpc/[rpcproxy, rpcserver, rpcclient],
eth/common/eth_types as etypes, eth/common/accounts,
web3, web3/[primitives, eth_api_types, eth_api],
web3/[primitives, eth_api_types],
beacon_chain/el/el_manager, beacon_chain/el/el_manager,
beacon_chain/networking/network_metadata, beacon_chain/networking/network_metadata,
beacon_chain/spec/forks, beacon_chain/spec/forks,
@ -26,15 +25,9 @@ import
export forks export forks
type
FixedBytes[N: static int] = primitives.FixedBytes[N]
Address = primitives.Address
logScope: logScope:
topics = "verified_proxy" topics = "verified_proxy"
proc `==`(x, y: Quantity): bool {.borrow, noSideEffect.}
type type
VerifiedRpcProxy* = ref object VerifiedRpcProxy* = ref object
proxy: RpcProxy proxy: RpcProxy
@ -63,7 +56,7 @@ func parseQuantityTag(blockTag: BlockTag): Result[QuantityTag, string] =
else: else:
return err("Unsupported blockTag: " & tag) return err("Unsupported blockTag: " & tag)
else: else:
let quantity = blockTag.number.Quantity let quantity = blockTag.number
return ok(QuantityTag(kind: BlockNumber, blockNumber: quantity)) return ok(QuantityTag(kind: BlockNumber, blockNumber: quantity))
template checkPreconditions(proxy: VerifiedRpcProxy) = template checkPreconditions(proxy: VerifiedRpcProxy) =
@ -197,7 +190,7 @@ proc installEthApiHandlers*(lcProxy: VerifiedRpcProxy) =
let account = accountResult.get() let account = accountResult.get()
if account.codeHash == etypes.EMPTY_CODE_HASH: if account.codeHash == EMPTY_CODE_HASH:
# account does not have any code, return empty hex data # account does not have any code, return empty hex data
return @[] return @[]
@ -233,7 +226,7 @@ proc installEthApiHandlers*(lcProxy: VerifiedRpcProxy) =
return Opt.some(asBlockObject(executionPayload.get())) return Opt.some(asBlockObject(executionPayload.get()))
lcProxy.proxy.rpc("eth_getBlockByHash") do( lcProxy.proxy.rpc("eth_getBlockByHash") do(
blockHash: BlockHash, fullTransactions: bool blockHash: Hash32, fullTransactions: bool
) -> Opt[BlockObject]: ) -> Opt[BlockObject]:
let executionPayload = lcProxy.blockCache.getPayloadByHash(blockHash) let executionPayload = lcProxy.blockCache.getPayloadByHash(blockHash)

View File

@ -8,24 +8,19 @@
{.push raises: [].} {.push raises: [].}
import import
std/typetraits, eth/common/[base_rlp, headers_rlp, blocks, hashes],
eth/common/eth_types as etypes,
eth/rlp,
nimcrypto/hash,
stint, stint,
web3, web3/eth_api_types,
web3/engine_api_types, web3/engine_api_types,
../../nimbus/db/core_db ../../nimbus/db/core_db
type export eth_api_types, engine_api_types
FixedBytes[N: static int] = primitives.FixedBytes[N]
Address = primitives.Address
type ExecutionData* = object type ExecutionData* = object
parentHash*: BlockHash parentHash*: Hash32
feeRecipient*: Address feeRecipient*: Address
stateRoot*: BlockHash stateRoot*: Hash32
receiptsRoot*: BlockHash receiptsRoot*: Hash32
logsBloom*: FixedBytes[256] logsBloom*: FixedBytes[256]
prevRandao*: FixedBytes[32] prevRandao*: FixedBytes[32]
blockNumber*: Quantity blockNumber*: Quantity
@ -34,7 +29,7 @@ type ExecutionData* = object
timestamp*: Quantity timestamp*: Quantity
extraData*: DynamicBytes[0, 32] extraData*: DynamicBytes[0, 32]
baseFeePerGas*: UInt256 baseFeePerGas*: UInt256
blockHash*: BlockHash blockHash*: Hash32
transactions*: seq[TypedTransaction] transactions*: seq[TypedTransaction]
withdrawals*: seq[WithdrawalV1] withdrawals*: seq[WithdrawalV1]
@ -77,15 +72,9 @@ proc asExecutionData*(payload: SomeExecutionPayload): ExecutionData =
withdrawals: payload.withdrawals, withdrawals: payload.withdrawals,
) )
func toFixedBytes(d: MDigest[256]): FixedBytes[32] =
FixedBytes[32](d.data)
template asEthHash(hash: BlockHash): etypes.Hash32 =
etypes.Hash32(distinctBase(hash))
proc calculateTransactionData( proc calculateTransactionData(
items: openArray[TypedTransaction] items: openArray[TypedTransaction]
): (etypes.Hash32, seq[TxOrHash], uint64) = ): (Hash32, 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
@ -97,30 +86,30 @@ proc calculateTransactionData(
let tx = distinctBase(t) let tx = distinctBase(t)
txSize = txSize + uint64(len(tx)) txSize = txSize + uint64(len(tx))
tr.merge(rlp.encode(uint64 i), tx).expect "merge data" tr.merge(rlp.encode(uint64 i), tx).expect "merge data"
txHashes.add(txOrHash keccakHash(tx)) txHashes.add(txOrHash keccak256(tx))
let rootHash = tr.state(updateOk = true).expect "hash" let rootHash = tr.state(updateOk = true).expect "hash"
(rootHash, txHashes, txSize) (rootHash, txHashes, txSize)
func blockHeaderSize(payload: ExecutionData, txRoot: etypes.Hash32): uint64 = func blockHeaderSize(payload: ExecutionData, txRoot: Hash32): uint64 =
let bh = etypes.BlockHeader( let header = Header(
parentHash: payload.parentHash, parentHash: payload.parentHash,
ommersHash: etypes.EMPTY_UNCLE_HASH, ommersHash: EMPTY_UNCLE_HASH,
coinbase: payload.feeRecipient, coinbase: payload.feeRecipient,
stateRoot: payload.stateRoot, stateRoot: payload.stateRoot,
transactionsRoot: txRoot, transactionsRoot: txRoot,
receiptsRoot: payload.receiptsRoot, receiptsRoot: payload.receiptsRoot,
logsBloom: distinctBase(payload.logsBloom).to(Bloom), logsBloom: payload.logsBloom,
difficulty: default(etypes.DifficultyInt), difficulty: default(DifficultyInt),
number: payload.blockNumber.distinctBase, number: distinctBase(payload.blockNumber),
gasLimit: distinctBase(payload.gasLimit), gasLimit: distinctBase(payload.gasLimit),
gasUsed: distinctBase(payload.gasUsed), gasUsed: distinctBase(payload.gasUsed),
timestamp: payload.timestamp.EthTime, timestamp: payload.timestamp.EthTime,
extraData: bytes payload.extraData, extraData: payload.extraData.data,
mixHash: payload.prevRandao, mixHash: payload.prevRandao,
nonce: default(etypes.BlockNonce), nonce: default(Bytes8),
baseFeePerGas: Opt.some payload.baseFeePerGas, baseFeePerGas: Opt.some payload.baseFeePerGas,
) )
return uint64(len(rlp.encode(bh))) return uint64(len(rlp.encode(header)))
proc asBlockObject*(p: ExecutionData): BlockObject {.raises: [ValueError].} = proc asBlockObject*(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
@ -130,10 +119,10 @@ proc asBlockObject*(p: ExecutionData): BlockObject {.raises: [ValueError].} =
let headerSize = blockHeaderSize(p, txRoot) let headerSize = blockHeaderSize(p, txRoot)
let blockSize = txSize + headerSize let blockSize = txSize + headerSize
BlockObject( BlockObject(
number: web3.BlockNumber p.blockNumber, number: p.blockNumber,
hash: p.blockHash, hash: p.blockHash,
parentHash: p.parentHash, parentHash: p.parentHash,
sha3Uncles: etypes.EMPTY_UNCLE_HASH, sha3Uncles: EMPTY_UNCLE_HASH,
logsBloom: p.logsBloom, logsBloom: p.logsBloom,
transactionsRoot: txRoot, transactionsRoot: txRoot,
stateRoot: p.stateRoot, stateRoot: p.stateRoot,
@ -144,7 +133,7 @@ proc asBlockObject*(p: ExecutionData): BlockObject {.raises: [ValueError].} =
gasLimit: p.gasLimit, gasLimit: p.gasLimit,
gasUsed: p.gasUsed, gasUsed: p.gasUsed,
timestamp: p.timestamp, timestamp: p.timestamp,
nonce: Opt.some(default(FixedBytes[8])), nonce: Opt.some(default(Bytes8)),
size: Quantity(blockSize), size: Quantity(blockSize),
# TODO: It does not matter what we put here after merge blocks. # TODO: It does not matter what we put here after merge blocks.
# Other projects like `helios` return `0`, data providers like alchemy return # Other projects like `helios` return `0`, data providers like alchemy return

View File

@ -8,82 +8,51 @@
{.push raises: [].} {.push raises: [].}
import import
std/[sequtils, typetraits, options], std/sequtils,
stint, stint,
results, results,
nimcrypto/hash, eth/common/[base_rlp, accounts_rlp, hashes_rlp],
eth/common/eth_types as etypes, eth/trie/[hexary_proof_verification],
eth/common/eth_types_rlp,
eth/rlp,
eth/trie/[hexary, hexary_proof_verification],
web3/eth_api_types web3/eth_api_types
export results export results, stint, hashes_rlp, accounts_rlp, eth_api_types
type
FixedBytes[N: static int] = primitives.FixedBytes[N]
Address = primitives.Address
func toMDigest(arg: primitives.FixedBytes[32]): MDigest[256] =
MDigest[256](data: distinctBase(arg))
func emptyAccount(): etypes.Account =
return etypes.Account(
nonce: uint64(0),
balance: UInt256.zero,
storageRoot: etypes.EMPTY_ROOT_HASH,
codeHash: etypes.EMPTY_CODE_HASH,
)
proc isValidProof(
branch: seq[seq[byte]], rootHash: KeccakHash, key, value: seq[byte]
): bool =
try:
# TODO: Investigate if this handles proof of non-existence.
# Probably not as bool is not expressive enough to say if proof is valid,
# but key actually does not exists in MPT
return isValidBranch(branch, rootHash, key, value)
except RlpError:
return false
proc getAccountFromProof*( proc getAccountFromProof*(
stateRoot: Hash32, stateRoot: Hash32,
accountAddress: Address, accountAddress: Address,
accountBalance: UInt256, accountBalance: UInt256,
accountNonce: Quantity, accountNonce: Quantity,
accountCodeHash: CodeHash, accountCodeHash: Hash32,
accountStorageRootHash: StorageHash, accountStorageRoot: Hash32,
mptNodes: seq[RlpEncodedBytes], mptNodes: seq[RlpEncodedBytes],
): Result[etypes.Account, string] = ): Result[Account, string] =
let let
mptNodesBytes = mptNodes.mapIt(distinctBase(it)) mptNodesBytes = mptNodes.mapIt(distinctBase(it))
keccakStateRootHash = Hash32(stateRoot) acc = Account(
acc = etypes.Account(
nonce: distinctBase(accountNonce), nonce: distinctBase(accountNonce),
balance: accountBalance, balance: accountBalance,
storageRoot: Hash32(accountStorageRootHash), storageRoot: accountStorageRoot,
codeHash: Hash32(accountCodeHash), codeHash: accountCodeHash,
) )
accountEncoded = rlp.encode(acc) accountEncoded = rlp.encode(acc)
accountKey = toSeq(keccakHash(distinctBase(accountAddress)).data) accountKey = toSeq(keccak256((accountAddress.data)).data)
let proofResult = let proofResult = verifyMptProof(mptNodesBytes, stateRoot, accountKey, accountEncoded)
verifyMptProof(mptNodesBytes, keccakStateRootHash, accountKey, accountEncoded)
case proofResult.kind case proofResult.kind
of MissingKey: of MissingKey:
return ok(emptyAccount()) return ok(EMPTY_ACCOUNT)
of ValidProof: of ValidProof:
return ok(acc) return ok(acc)
of InvalidProof: of InvalidProof:
return err(proofResult.errorMsg) return err(proofResult.errorMsg)
proc getStorageData( proc getStorageData(
account: etypes.Account, storageProof: StorageProof account: Account, 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(keccak256(toBytesBE(storageProof.key)).data)
encodedValue = rlp.encode(storageProof.value) encodedValue = rlp.encode(storageProof.value)
proofResult = proofResult =
verifyMptProof(storageMptNodes, account.storageRoot, key, encodedValue) verifyMptProof(storageMptNodes, account.storageRoot, key, encodedValue)
@ -105,7 +74,7 @@ proc getStorageData*(
proof.storageHash, proof.accountProof, proof.storageHash, proof.accountProof,
) )
if account.storageRoot == etypes.EMPTY_ROOT_HASH: if account.storageRoot == EMPTY_ROOT_HASH:
# valid account with empty storage, in that case getStorageAt # valid account with empty storage, in that case getStorageAt
# return 0 value # return 0 value
return ok(u256(0)) return ok(u256(0))
@ -113,15 +82,15 @@ proc getStorageData*(
if len(proof.storageProof) != 1: if len(proof.storageProof) != 1:
return err("no storage proof for requested slot") return err("no storage proof for requested slot")
let sproof = proof.storageProof[0] let storageProof = proof.storageProof[0]
if len(sproof.proof) == 0: if len(storageProof.proof) == 0:
return err("empty mpt proof for account with not empty storage") return err("empty mpt proof for account with not empty storage")
if sproof.key != requestedSlot: if storageProof.key != requestedSlot:
return err("received proof for invalid slot") return err("received proof for invalid slot")
return getStorageData(account, sproof) getStorageData(account, storageProof)
func isValidCode*(account: etypes.Account, code: openArray[byte]): bool = func isValidCode*(account: Account, code: openArray[byte]): bool =
return account.codeHash == keccakHash(code) account.codeHash == keccak256(code)