mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-12 21:34:33 +00:00
parent
e56bd994ff
commit
52a2ba4bd7
@ -60,3 +60,8 @@ proc getByNumber*(
|
|||||||
break
|
break
|
||||||
|
|
||||||
return payloadResult
|
return payloadResult
|
||||||
|
|
||||||
|
proc getPayloadByHash*(
|
||||||
|
self: BlockCache,
|
||||||
|
hash: BlockHash): Opt[ExecutionPayloadV1] =
|
||||||
|
return self.blocks.eq(hash)
|
||||||
|
@ -19,6 +19,7 @@ import
|
|||||||
beacon_chain/eth1/eth1_monitor,
|
beacon_chain/eth1/eth1_monitor,
|
||||||
beacon_chain/networking/network_metadata,
|
beacon_chain/networking/network_metadata,
|
||||||
beacon_chain/spec/forks,
|
beacon_chain/spec/forks,
|
||||||
|
./rpc_utils,
|
||||||
../validate_proof,
|
../validate_proof,
|
||||||
../block_cache
|
../block_cache
|
||||||
|
|
||||||
@ -88,7 +89,7 @@ template rpcClient(lcProxy: LightClientRpcProxy): RpcClient = lcProxy.proxy.getC
|
|||||||
|
|
||||||
proc getPayloadByTag(
|
proc getPayloadByTag(
|
||||||
proxy: LightClientRpcProxy,
|
proxy: LightClientRpcProxy,
|
||||||
quantityTag: string): ExecutionPayloadV1 {.raises: [ValueError, Defect].} =
|
quantityTag: string): results.Opt[ExecutionPayloadV1] {.raises: [ValueError, Defect].} =
|
||||||
checkPreconditions(proxy)
|
checkPreconditions(proxy)
|
||||||
|
|
||||||
let tagResult = parseQuantityTag(quantityTag)
|
let tagResult = parseQuantityTag(quantityTag)
|
||||||
@ -98,25 +99,25 @@ proc getPayloadByTag(
|
|||||||
|
|
||||||
let tag = tagResult.get()
|
let tag = tagResult.get()
|
||||||
|
|
||||||
var payload: ExecutionPayloadV1
|
|
||||||
|
|
||||||
case tag.kind
|
case tag.kind
|
||||||
of LatestBlock:
|
of LatestBlock:
|
||||||
# this will always be ok as we always validate that cache is not empty
|
# this will always return some block, as we always checkPreconditions
|
||||||
payload = proxy.blockCache.latest.get
|
return proxy.blockCache.latest
|
||||||
of BlockNumber:
|
of BlockNumber:
|
||||||
let payLoadResult = proxy.blockCache.getByNumber(tag.blockNumber)
|
return proxy.blockCache.getByNumber(tag.blockNumber)
|
||||||
if payLoadResult.isErr():
|
|
||||||
raise newException(
|
|
||||||
ValueError, "Block not stored in cache " & $tag.blockNumber
|
|
||||||
)
|
|
||||||
payload = payLoadResult.get
|
|
||||||
|
|
||||||
return payload
|
proc getPayloadByTagOrThrow(
|
||||||
|
proxy: LightClientRpcProxy,
|
||||||
|
quantityTag: string): ExecutionPayloadV1 {.raises: [ValueError, Defect].} =
|
||||||
|
|
||||||
|
let tagResult = getPayloadByTag(proxy, quantityTag)
|
||||||
|
|
||||||
|
if tagResult.isErr:
|
||||||
|
raise newException(ValueError, "No block stored for given tag " & quantityTag)
|
||||||
|
|
||||||
|
return tagResult.get()
|
||||||
|
|
||||||
proc installEthApiHandlers*(lcProxy: LightClientRpcProxy) =
|
proc installEthApiHandlers*(lcProxy: LightClientRpcProxy) =
|
||||||
template payload(): Opt[ExecutionPayloadV1] = lcProxy.executionPayload
|
|
||||||
|
|
||||||
lcProxy.proxy.rpc("eth_chainId") do() -> HexQuantityStr:
|
lcProxy.proxy.rpc("eth_chainId") do() -> HexQuantityStr:
|
||||||
return encodeQuantity(lcProxy.chainId)
|
return encodeQuantity(lcProxy.chainId)
|
||||||
|
|
||||||
@ -132,7 +133,7 @@ proc installEthApiHandlers*(lcProxy: LightClientRpcProxy) =
|
|||||||
# can mean different blocks and ultimatly piece received piece of state
|
# can mean different blocks and ultimatly piece received piece of state
|
||||||
# must by validated against correct state root
|
# must by validated against correct state root
|
||||||
let
|
let
|
||||||
executionPayload = lcProxy.getPayloadByTag(quantityTag)
|
executionPayload = lcProxy.getPayloadByTagOrThrow(quantityTag)
|
||||||
blockNumber = executionPayload.blockNumber.uint64
|
blockNumber = executionPayload.blockNumber.uint64
|
||||||
|
|
||||||
info "Forwarding get_Balance", executionBn = blockNumber
|
info "Forwarding get_Balance", executionBn = blockNumber
|
||||||
@ -156,7 +157,7 @@ proc installEthApiHandlers*(lcProxy: LightClientRpcProxy) =
|
|||||||
|
|
||||||
lcProxy.proxy.rpc("eth_getStorageAt") do(address: Address, slot: HexDataStr, quantityTag: string) -> HexDataStr:
|
lcProxy.proxy.rpc("eth_getStorageAt") do(address: Address, slot: HexDataStr, quantityTag: string) -> HexDataStr:
|
||||||
let
|
let
|
||||||
executionPayload = lcProxy.getPayloadByTag(quantityTag)
|
executionPayload = lcProxy.getPayloadByTagOrThrow(quantityTag)
|
||||||
uslot = UInt256.fromHex(slot.string)
|
uslot = UInt256.fromHex(slot.string)
|
||||||
blockNumber = executionPayload.blockNumber.uint64
|
blockNumber = executionPayload.blockNumber.uint64
|
||||||
|
|
||||||
@ -174,7 +175,7 @@ proc installEthApiHandlers*(lcProxy: LightClientRpcProxy) =
|
|||||||
|
|
||||||
lcProxy.proxy.rpc("eth_getTransactionCount") do(address: Address, quantityTag: string) -> HexQuantityStr:
|
lcProxy.proxy.rpc("eth_getTransactionCount") do(address: Address, quantityTag: string) -> HexQuantityStr:
|
||||||
let
|
let
|
||||||
executionPayload = lcProxy.getPayloadByTag(quantityTag)
|
executionPayload = lcProxy.getPayloadByTagOrThrow(quantityTag)
|
||||||
blockNumber = executionPayload.blockNumber.uint64
|
blockNumber = executionPayload.blockNumber.uint64
|
||||||
|
|
||||||
info "Forwarding eth_getTransactionCount", executionBn = blockNumber
|
info "Forwarding eth_getTransactionCount", executionBn = blockNumber
|
||||||
@ -198,7 +199,7 @@ proc installEthApiHandlers*(lcProxy: LightClientRpcProxy) =
|
|||||||
|
|
||||||
lcProxy.proxy.rpc("eth_getCode") do(address: Address, quantityTag: string) -> HexDataStr:
|
lcProxy.proxy.rpc("eth_getCode") do(address: Address, quantityTag: string) -> HexDataStr:
|
||||||
let
|
let
|
||||||
executionPayload = lcProxy.getPayloadByTag(quantityTag)
|
executionPayload = lcProxy.getPayloadByTagOrThrow(quantityTag)
|
||||||
blockNumber = executionPayload.blockNumber.uint64
|
blockNumber = executionPayload.blockNumber.uint64
|
||||||
|
|
||||||
let
|
let
|
||||||
@ -239,9 +240,23 @@ proc installEthApiHandlers*(lcProxy: LightClientRpcProxy) =
|
|||||||
lcProxy.proxy.registerProxyMethod("eth_sendRawTransaction")
|
lcProxy.proxy.registerProxyMethod("eth_sendRawTransaction")
|
||||||
lcProxy.proxy.registerProxyMethod("eth_getTransactionReceipt")
|
lcProxy.proxy.registerProxyMethod("eth_getTransactionReceipt")
|
||||||
|
|
||||||
# TODO Respond to this calls using BlockCache
|
# TODO currently we do not handle fullTransactions flag. It require updates on
|
||||||
lcProxy.proxy.registerProxyMethod("eth_getBlockByNumber")
|
# nim-web3 side
|
||||||
lcProxy.proxy.registerProxyMethod("eth_getBlockByHash")
|
lcProxy.proxy.rpc("eth_getBlockByNumber") do(quantityTag: string, fullTransactions: bool) -> Option[BlockObject]:
|
||||||
|
let executionPayload = lcProxy.getPayloadByTag(quantityTag)
|
||||||
|
|
||||||
|
if executionPayload.isErr:
|
||||||
|
return none(BlockObject)
|
||||||
|
|
||||||
|
return some(asBlockObject(executionPayload.get()))
|
||||||
|
|
||||||
|
lcProxy.proxy.rpc("eth_getBlockByHash") do(blockHash: BlockHash, fullTransactions: bool) -> Option[BlockObject]:
|
||||||
|
let executionPayload = lcProxy.blockCache.getPayloadByHash(blockHash)
|
||||||
|
|
||||||
|
if executionPayload.isErr:
|
||||||
|
return none(BlockObject)
|
||||||
|
|
||||||
|
return some(asBlockObject(executionPayload.get()))
|
||||||
|
|
||||||
proc new*(
|
proc new*(
|
||||||
T: type LightClientRpcProxy,
|
T: type LightClientRpcProxy,
|
||||||
|
86
lc_proxy/rpc/rpc_utils.nim
Normal file
86
lc_proxy/rpc/rpc_utils.nim
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import
|
||||||
|
std/typetraits,
|
||||||
|
eth/common/eth_types as etypes,
|
||||||
|
eth/[trie, rlp, trie/db],
|
||||||
|
stint,
|
||||||
|
web3
|
||||||
|
|
||||||
|
template unsafeQuantityToInt64(q: Quantity): int64 =
|
||||||
|
int64 q
|
||||||
|
|
||||||
|
func toFixedBytes(d: MDigest[256]): FixedBytes[32] =
|
||||||
|
FixedBytes[32](d.data)
|
||||||
|
|
||||||
|
template asEthHash(hash: BlockHash): Hash256 =
|
||||||
|
Hash256(data: distinctBase(hash))
|
||||||
|
|
||||||
|
proc calculateTransactionData(
|
||||||
|
items: openArray[TypedTransaction]): (etypes.Hash256, seq[TxHash], uint64) =
|
||||||
|
## returns tuple composed of
|
||||||
|
## - root of transactions trie
|
||||||
|
## - list of transactions hashes
|
||||||
|
## - total size of transactions in block
|
||||||
|
var tr = initHexaryTrie(newMemoryDB())
|
||||||
|
var txHashes: seq[TxHash]
|
||||||
|
var txSize: uint64
|
||||||
|
for i, t in items:
|
||||||
|
let tx = distinctBase(t)
|
||||||
|
txSize = txSize + uint64(len(tx))
|
||||||
|
tr.put(rlp.encode(i), tx)
|
||||||
|
txHashes.add(toFixedBytes(keccakHash(tx)))
|
||||||
|
return (tr.rootHash(), txHashes, txSize)
|
||||||
|
|
||||||
|
func blockHeaderSize(payload: ExecutionPayloadV1, txRoot: etypes.Hash256): uint64 =
|
||||||
|
let bh = etypes.BlockHeader(
|
||||||
|
parentHash : payload.parentHash.asEthHash,
|
||||||
|
ommersHash : etypes.EMPTY_UNCLE_HASH,
|
||||||
|
coinbase : etypes.EthAddress payload.feeRecipient,
|
||||||
|
stateRoot : payload.stateRoot.asEthHash,
|
||||||
|
txRoot : txRoot,
|
||||||
|
receiptRoot : payload.receiptsRoot.asEthHash,
|
||||||
|
bloom : distinctBase(payload.logsBloom),
|
||||||
|
difficulty : default(etypes.DifficultyInt),
|
||||||
|
blockNumber : payload.blockNumber.distinctBase.u256,
|
||||||
|
gasLimit : payload.gasLimit.unsafeQuantityToInt64,
|
||||||
|
gasUsed : payload.gasUsed.unsafeQuantityToInt64,
|
||||||
|
timestamp : fromUnix payload.timestamp.unsafeQuantityToInt64,
|
||||||
|
extraData : bytes payload.extraData,
|
||||||
|
mixDigest : payload.prevRandao.asEthHash,
|
||||||
|
nonce : default(etypes.BlockNonce),
|
||||||
|
fee : some payload.baseFeePerGas
|
||||||
|
)
|
||||||
|
return uint64(len(rlp.encode(bh)))
|
||||||
|
|
||||||
|
proc asBlockObject*(p: ExecutionPayloadV1): BlockObject =
|
||||||
|
# TODO currently we always calculate txHashes as BlockObject does not have
|
||||||
|
# option of returning full transactions. It needs fixing at nim-web3 library
|
||||||
|
# level
|
||||||
|
let (txRoot, txHashes, txSize) = calculateTransactionData(p.transactions)
|
||||||
|
let headerSize = blockHeaderSize(p, txRoot)
|
||||||
|
let blockSize = txSize + headerSize
|
||||||
|
BlockObject(
|
||||||
|
number: p.blockNumber,
|
||||||
|
hash: p.blockHash,
|
||||||
|
parentHash: p.parentHash,
|
||||||
|
sha3Uncles: FixedBytes(etypes.EMPTY_UNCLE_HASH.data),
|
||||||
|
logsBloom: p.logsBloom,
|
||||||
|
transactionsRoot: toFixedBytes(txRoot),
|
||||||
|
stateRoot: p.stateRoot,
|
||||||
|
receiptsRoot: p.receiptsRoot,
|
||||||
|
miner: p.feeRecipient,
|
||||||
|
difficulty: UInt256.zero,
|
||||||
|
extraData: p.extraData.toHex,
|
||||||
|
gasLimit: p.gasLimit,
|
||||||
|
gasUsed: p.gasUsed,
|
||||||
|
timestamp: p.timestamp,
|
||||||
|
nonce: some(default(FixedBytes[8])),
|
||||||
|
size: Quantity(blockSize),
|
||||||
|
# TODO It does not matter what we put here in after merge blocks.
|
||||||
|
# Other projects like `helios` return `0`, data providers like alchemy return
|
||||||
|
# transition difficulty. For now retruning `0` as this is a bit easier to do.
|
||||||
|
totalDifficulty: UInt256.zero,
|
||||||
|
transactions: txHashes,
|
||||||
|
uncles: @[],
|
||||||
|
baseFeePerGas: some(p.baseFeePerGas)
|
||||||
|
)
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user