eth_getBlockByHash, changes to support returning marshalled Nim types

This commit is contained in:
coffeepots 2018-08-15 14:08:40 +01:00
parent 1826c0ce92
commit 845866fc97
1 changed files with 52 additions and 14 deletions

View File

@ -10,15 +10,23 @@ import
nimcrypto, json_rpc/rpcserver, eth_p2p, hexstrings, strutils, stint, nimcrypto, json_rpc/rpcserver, eth_p2p, hexstrings, strutils, stint,
../config, ../vm_state, ../constants, eth_trie/[memdb, types], ../config, ../vm_state, ../constants, eth_trie/[memdb, types],
../db/[db_chain, state_db], eth_common, rpc_types, byteutils, ../db/[db_chain, state_db], eth_common, rpc_types, byteutils,
ranges/typedranges ranges/typedranges, times, ../utils/header
#[ #[
Note: Note:
* Hexstring types (HexQuantitySt, HexDataStr, EthAddressStr, EthHashStr) * Hexstring types (HexQuantitySt, HexDataStr, EthAddressStr, EthHashStr)
are parsed to check format before the RPC blocks are executed and will are parsed to check format before the RPC blocks are executed and will
raise an exception if invalid. raise an exception if invalid.
* Many of the RPC calls do not validate hex string types when output, only
type cast to avoid extra processing.
]# ]#
# TODO: Don't use stateRoot for block hash.
# Work around for https://github.com/nim-lang/Nim/issues/8645
proc `%`*(value: Time): JsonNode =
result = %value.toSeconds
func strToAddress(value: string): EthAddress = hexToPaddedByteArray[20](value) func strToAddress(value: string): EthAddress = hexToPaddedByteArray[20](value)
func headerFromTag(chain:BaseChainDB, blockTag: string): BlockHeader = func headerFromTag(chain:BaseChainDB, blockTag: string): BlockHeader =
@ -58,9 +66,9 @@ proc setupP2PRPC*(node: EthereumNode, rpcsrv: RpcServer) =
sync: SyncState sync: SyncState
if true: if true:
# TODO: Populate sync state, this is a placeholder # TODO: Populate sync state, this is a placeholder
sync.startingBlock = GENESIS_BLOCK_NUMBER.toHex.HexDataStr sync.startingBlock = GENESIS_BLOCK_NUMBER
sync.currentBlock = chain.getCanonicalHead().blockNumber.toHex.HexDataStr sync.currentBlock = chain.getCanonicalHead().blockNumber
sync.highestBlock = chain.getCanonicalHead().blockNumber.toHex.HexDataStr sync.highestBlock = chain.getCanonicalHead().blockNumber
result = %sync result = %sync
else: else:
result = newJBool(false) result = newJBool(false)
@ -102,7 +110,7 @@ proc setupP2PRPC*(node: EthereumNode, rpcsrv: RpcServer) =
result = balance.toInt result = balance.toInt
rpcsrv.rpc("eth_getStorageAt") do(data: EthAddressStr, quantity: int, quantityTag: string) -> HexDataStr: rpcsrv.rpc("eth_getStorageAt") do(data: EthAddressStr, quantity: int, quantityTag: string) -> UInt256:
## Returns the value from a storage position at a given address. ## Returns the value from a storage position at a given address.
## ##
## data: address of the storage. ## data: address of the storage.
@ -114,7 +122,7 @@ proc setupP2PRPC*(node: EthereumNode, rpcsrv: RpcServer) =
addrBytes = strToAddress(data.string) addrBytes = strToAddress(data.string)
storage = account_db.getStorage(addrBytes, quantity.u256) storage = account_db.getStorage(addrBytes, quantity.u256)
if storage[1]: if storage[1]:
result = ("0x" & storage[0].toHex).HexDataStr result = storage[0]
rpcsrv.rpc("eth_getTransactionCount") do(data: EthAddressStr, quantityTag: string) -> int: rpcsrv.rpc("eth_getTransactionCount") do(data: EthAddressStr, quantityTag: string) -> int:
## Returns the number of transactions sent from an address. ## Returns the number of transactions sent from an address.
@ -177,13 +185,8 @@ proc setupP2PRPC*(node: EthereumNode, rpcsrv: RpcServer) =
account_db = accountDbFromTag(quantityTag) account_db = accountDbFromTag(quantityTag)
addrBytes = strToAddress(data.string) addrBytes = strToAddress(data.string)
storage = account_db.getCode(addrBytes) storage = account_db.getCode(addrBytes)
var # Easier to return the string manually here rather than expect ByteRange to be marshalled
idx = 2 result = byteutils.toHex(storage.toOpenArray).HexDataStr
res = newString(storage.len + 2)
res[0..1] = "0x"
for b in storage:
res[idx] = b.char
result = hexDataStr(res)
rpcsrv.rpc("eth_sign") do(data: EthAddressStr, message: HexDataStr) -> HexDataStr: rpcsrv.rpc("eth_sign") do(data: EthAddressStr, message: HexDataStr) -> HexDataStr:
## The sign method calculates an Ethereum specific signature with: sign(keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))). ## The sign method calculates an Ethereum specific signature with: sign(keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))).
@ -230,13 +233,48 @@ proc setupP2PRPC*(node: EthereumNode, rpcsrv: RpcServer) =
## Returns the amount of gas used. ## Returns the amount of gas used.
discard discard
func populateBlockObject(header: BlockHeader, blockBody: BlockBodyRef): BlockObject =
result.number = new BlockNumber
result.number[] = header.blockNumber
result.hash = new Hash256
result.hash[] = header.hash
result.parentHash = header.parentHash
result.nonce = header.nonce.toUint
# Calculate hash for all uncle headers
var
rawdata = newSeq[byte](blockBody.uncles.len * 32)
startIdx = 0
for i in 0 ..< blockBody.uncles.len:
rawData[startIdx .. startIdx + 32] = blockBody.uncles[i].hash.data
startIdx += 32
result.sha3Uncles = keccak256.digest(rawData)
result.logsBloom = nil # TODO: Create bloom filter for logs
result.transactionsRoot = header.txRoot
result.stateRoot = header.stateRoot
result.receiptsRoot = header.receiptRoot
result.miner = ZERO_ADDRESS # TODO: Get miner address
result.difficulty = header.difficulty
result.totalDifficulty = header.difficulty # TODO: Calculate
result.extraData = header.extraData
result.size = 0 # TODO: Calculate block size
result.gasLimit = header.gasLimit
result.gasUsed = header.gasUsed
result.timestamp = header.timeStamp
result.transactions = blockBody.transactions
result.uncles = blockBody.uncles
rpcsrv.rpc("eth_getBlockByHash") do(data: HexDataStr, fullTransactions: bool) -> BlockObject: rpcsrv.rpc("eth_getBlockByHash") do(data: HexDataStr, fullTransactions: bool) -> BlockObject:
## Returns information about a block by hash. ## Returns information about a block by hash.
## ##
## data: Hash of a block. ## data: Hash of a block.
## fullTransactions: If true it returns the full transaction objects, if false only the hashes of the transactions. ## fullTransactions: If true it returns the full transaction objects, if false only the hashes of the transactions.
## Returns BlockObject or nil when no block was found. ## Returns BlockObject or nil when no block was found.
discard let
header = chain.getCanonicalHead()
body = chain.getBlockBody(header.stateRoot)
populateBlockObject(header, body)
rpcsrv.rpc("eth_getBlockByNumber") do(quantityTag: string, fullTransactions: bool) -> BlockObject: rpcsrv.rpc("eth_getBlockByNumber") do(quantityTag: string, fullTransactions: bool) -> BlockObject:
## Returns information about a block by block number. ## Returns information about a block by block number.