implement web3, net, and some eth namespace rpc
This commit is contained in:
parent
032c29288a
commit
336efdb0c3
|
@ -18,6 +18,12 @@ type
|
|||
pruneTrie*: bool
|
||||
config* : ChainConfig
|
||||
|
||||
# startingBlock, currentBlock, and highestBlock
|
||||
# are progress indicator
|
||||
startingBlock*: BlockNumber
|
||||
currentBlock*: BlockNumber
|
||||
highestBlock*: BlockNumber
|
||||
|
||||
#KeyType = enum
|
||||
# blockNumberToHash
|
||||
# blockHashToScore
|
||||
|
@ -64,6 +70,15 @@ proc getCanonicalHead*(self: BaseChainDB): BlockHeader =
|
|||
raise newException(CanonicalHeadNotFound,
|
||||
"No canonical head set for this chain")
|
||||
|
||||
proc populateProgress*(self: BaseChainDB) =
|
||||
try:
|
||||
self.startingBlock = self.getCanonicalHead().blockNumber
|
||||
except CanonicalHeadNotFound:
|
||||
self.startingBlock = toBlockNumber(0)
|
||||
|
||||
self.currentBlock = self.startingBlock
|
||||
self.highestBlock = self.startingBlock
|
||||
|
||||
proc getBlockHash*(self: BaseChainDB, n: BlockNumber, output: var Hash256): bool {.inline.} =
|
||||
## Return the block hash for the given block number.
|
||||
self.getHash(blockNumberToHashKey(n), output)
|
||||
|
@ -127,7 +142,7 @@ proc persistTransactions*(self: BaseChainDB, blockNumber: BlockNumber, transacti
|
|||
trie.put(rlp.encode(idx), encodedTx)
|
||||
self.db.put(transactionHashToBlockKey(txHash).toOpenArray, rlp.encode(txKey))
|
||||
|
||||
iterator getBlockTransactionData(self: BaseChainDB, transactionRoot: Hash256): seq[byte] =
|
||||
iterator getBlockTransactionData*(self: BaseChainDB, transactionRoot: Hash256): seq[byte] =
|
||||
var transactionDb = initHexaryTrie(self.db, transactionRoot)
|
||||
var transactionIdx = 0
|
||||
while true:
|
||||
|
@ -144,6 +159,17 @@ iterator getBlockTransactionHashes(self: BaseChainDB, blockHeader: BlockHeader):
|
|||
for encodedTx in self.getBlockTransactionData(blockHeader.txRoot):
|
||||
yield keccakHash(encodedTx)
|
||||
|
||||
proc getTransactionCount*(chain: BaseChainDB, blockHash: Hash256): int =
|
||||
var header: BlockHeader
|
||||
if chain.getBlockHeader(blockHash, header):
|
||||
var trie = initHexaryTrie(chain.db, header.txRoot)
|
||||
var txCount = 0
|
||||
while true:
|
||||
let txKey = rlp.encode(txCount)
|
||||
if txKey notin trie:
|
||||
break
|
||||
inc txCount
|
||||
|
||||
proc getBlockBody*(self: BaseChainDB, blockHash: Hash256, output: var BlockBody): bool =
|
||||
var header: BlockHeader
|
||||
if self.getBlockHeader(blockHash, header):
|
||||
|
|
|
@ -52,11 +52,6 @@ proc start(nimbus: NimbusNode) =
|
|||
discard setTimer(Moment.fromNow(conf.debug.logMetricsInterval.seconds), logMetrics)
|
||||
discard setTimer(Moment.fromNow(conf.debug.logMetricsInterval.seconds), logMetrics)
|
||||
|
||||
## Creating RPC Server
|
||||
if RpcFlags.Enabled in conf.rpc.flags:
|
||||
nimbus.rpcServer = newRpcHttpServer(conf.rpc.binds)
|
||||
setupCommonRpc(nimbus.rpcServer)
|
||||
|
||||
## Creating P2P Server
|
||||
let keypair = conf.net.nodekey.toKeyPair()
|
||||
|
||||
|
@ -88,6 +83,8 @@ proc start(nimbus: NimbusNode) =
|
|||
conf.prune == PruneMode.Full,
|
||||
conf.net.networkId.toPublicNetwork())
|
||||
|
||||
chainDB.populateProgress()
|
||||
|
||||
if canonicalHeadHashKey().toOpenArray notin trieDB:
|
||||
initializeEmptyDb(chainDb)
|
||||
doAssert(canonicalHeadHashKey().toOpenArray in trieDB)
|
||||
|
@ -107,6 +104,11 @@ proc start(nimbus: NimbusNode) =
|
|||
|
||||
nimbus.ethNode.chain = newChain(chainDB)
|
||||
|
||||
## Creating RPC Server
|
||||
if RpcFlags.Enabled in conf.rpc.flags:
|
||||
nimbus.rpcServer = newRpcHttpServer(conf.rpc.binds)
|
||||
setupCommonRpc(nimbus.ethNode, nimbus.rpcServer)
|
||||
|
||||
# Enable RPC APIs based on RPC flags and protocol flags
|
||||
if RpcFlags.Eth in conf.rpc.flags and ProtocolFlags.Eth in conf.net.protocols:
|
||||
setupEthRpc(nimbus.ethNode, chainDB, nimbus.rpcServer)
|
||||
|
|
|
@ -3,6 +3,9 @@ import ../db/db_chain, eth/common, chronicles, ../vm_state, ../vm_types,
|
|||
../utils, eth/trie/db, ./executor, ../config, ../genesis, ../utils,
|
||||
stew/endians2
|
||||
|
||||
when not defined(release):
|
||||
import ../tracer
|
||||
|
||||
type
|
||||
# Chain's forks not always equals to EVM's forks
|
||||
ChainFork = enum
|
||||
|
@ -125,6 +128,7 @@ method persistBlocks*(c: Chain, headers: openarray[BlockHeader], bodies: openarr
|
|||
debug "Number of headers not matching number of bodies"
|
||||
return ValidationResult.Error
|
||||
|
||||
c.db.highestBlock = headers[^1].blockNumber
|
||||
let transaction = c.db.db.beginTransaction()
|
||||
defer: transaction.dispose()
|
||||
|
||||
|
@ -151,6 +155,11 @@ method persistBlocks*(c: Chain, headers: openarray[BlockHeader], bodies: openarr
|
|||
c.db.persistTransactions(headers[i].blockNumber, bodies[i].transactions)
|
||||
c.db.persistReceipts(vmState.receipts)
|
||||
|
||||
# update currentBlock *after* we persist it
|
||||
# so the rpc return consistent result
|
||||
# between eth_blockNumber and eth_syncing
|
||||
c.db.currentBlock = headers[i].blockNumber
|
||||
|
||||
transaction.commit()
|
||||
|
||||
method getTrieDB*(c: Chain): TrieDatabaseRef {.gcsafe.} =
|
||||
|
|
|
@ -8,14 +8,28 @@
|
|||
# those terms.
|
||||
|
||||
import
|
||||
strutils,
|
||||
strutils, tables,
|
||||
nimcrypto, eth/common as eth_common, stint, json_rpc/server,
|
||||
eth/p2p,
|
||||
../config, hexstrings
|
||||
|
||||
proc setupCommonRPC*(server: RpcServer) =
|
||||
proc setupCommonRPC*(node: EthereumNode, server: RpcServer) =
|
||||
server.rpc("web3_clientVersion") do() -> string:
|
||||
result = NimbusIdent
|
||||
|
||||
server.rpc("web3_sha3") do(data: HexDataStr) -> string:
|
||||
var rawdata = nimcrypto.fromHex(data.string[2 .. ^1])
|
||||
result = "0x" & $keccak_256.digest(rawdata)
|
||||
|
||||
server.rpc("net_version") do() -> string:
|
||||
let conf = getConfiguration()
|
||||
result = $conf.net.networkId
|
||||
|
||||
server.rpc("net_listening") do() -> bool:
|
||||
let conf = getConfiguration()
|
||||
let numPeers = node.peerPool.connectedNodes.len
|
||||
result = numPeers < conf.net.maxPeers
|
||||
|
||||
server.rpc("net_peerCount") do() -> HexQuantityStr:
|
||||
let peerCount = uint node.peerPool.connectedNodes.len
|
||||
result = encodeQuantity(peerCount)
|
||||
|
|
|
@ -34,8 +34,8 @@ import
|
|||
type
|
||||
HexQuantityStr* = distinct string
|
||||
HexDataStr* = distinct string
|
||||
EthAddressStr* = distinct string # Same as HexDataStr but must be less <= 20 bytes
|
||||
EthHashStr* = distinct string # Same as HexDataStr but must be exactly 32 bytes
|
||||
EthAddressStr* = distinct string # Same as HexDataStr but must be less <= 20 bytes
|
||||
EthHashStr* = distinct string # Same as HexDataStr but must be exactly 32 bytes
|
||||
Identifier* = distinct string # 32 bytes, no 0x prefix!
|
||||
HexStrings = HexQuantityStr | HexDataStr | EthAddressStr | EthHashStr |
|
||||
Identifier
|
||||
|
@ -51,9 +51,13 @@ template stripLeadingZeros(value: string): string =
|
|||
cidx.inc
|
||||
value[cidx .. ^1]
|
||||
|
||||
func encodeQuantity*(value: SomeUnsignedInt): string {.inline.} =
|
||||
func encodeQuantity*(value: SomeUnsignedInt): HexQuantityStr {.inline.} =
|
||||
var hValue = value.toHex.stripLeadingZeros
|
||||
result = "0x" & hValue
|
||||
result = HexQuantityStr("0x" & hValue)
|
||||
|
||||
func encodeQuantity*(value: UInt256): HexQuantityStr {.inline.} =
|
||||
var hValue = value.toHex
|
||||
result = HexQuantityStr("0x" & hValue)
|
||||
|
||||
template hasHexHeader(value: string): bool =
|
||||
if value.len >= 2 and value[0] == '0' and value[1] in {'x', 'X'}: true
|
||||
|
@ -65,6 +69,15 @@ template isHexChar(c: char): bool =
|
|||
c notin {'A'..'F'}: false
|
||||
else: true
|
||||
|
||||
func `==`*(a, b: HexQuantityStr): bool {.inline.} =
|
||||
a.string == b.string
|
||||
|
||||
func `==`*(a, b: EthAddressStr): bool {.inline.} =
|
||||
a.string == b.string
|
||||
|
||||
func `==`*(a, b: HexDataStr): bool {.inline.} =
|
||||
a.string == b.string
|
||||
|
||||
func isValidHexQuantity*(value: string): bool =
|
||||
if not value.hasHexHeader:
|
||||
return false
|
||||
|
@ -158,10 +171,19 @@ proc hexDataStr*(value: string): HexDataStr {.inline.} =
|
|||
value.validateHexData
|
||||
result = value.HexDataStr
|
||||
|
||||
proc hexDataStr*(value: openArray[byte]): HexDataStr {.inline.} =
|
||||
result = HexDataStr("0x" & value.toHex)
|
||||
|
||||
proc hexDataStr*(value: Uint256): HexDataStr {.inline.} =
|
||||
result = HexDataStr("0x" & toBytesBE(value).toHex)
|
||||
|
||||
proc ethAddressStr*(value: string): EthAddressStr {.inline.} =
|
||||
value.validateHexAddressStr
|
||||
result = value.EthAddressStr
|
||||
|
||||
func ethAddressStr*(x: EthAddress): EthAddressStr {.inline.} =
|
||||
result = EthAddressStr("0x" & toHex(x))
|
||||
|
||||
proc ethHashStr*(value: string): EthHashStr {.inline.} =
|
||||
value.validateHashStr
|
||||
result = value.EthHashStr
|
||||
|
@ -175,7 +197,6 @@ proc `%`*(value: HexStrings): JsonNode =
|
|||
result = %(value.string)
|
||||
|
||||
# Overloads to support expected representation of hex data
|
||||
|
||||
proc `%`*(value: EthAddress): JsonNode =
|
||||
result = %("0x" & value.toHex)
|
||||
|
||||
|
|
|
@ -8,12 +8,13 @@
|
|||
# those terms.
|
||||
|
||||
import
|
||||
strutils, times, options,
|
||||
strutils, times, options, tables,
|
||||
json_rpc/rpcserver, hexstrings, stint, stew/byteutils,
|
||||
eth/[common, keys, rlp, p2p], nimcrypto,
|
||||
eth/p2p/rlpx_protocols/eth_protocol,
|
||||
../transaction, ../config, ../vm_state, ../constants, ../vm_types,
|
||||
../vm_state_transactions, ../utils,
|
||||
../db/[db_chain, accounts_cache],
|
||||
../db/[db_chain, state_db],
|
||||
rpc_types, rpc_utils, ../vm/[message, computation],
|
||||
../vm/interpreter/vm_forks
|
||||
|
||||
|
@ -27,7 +28,7 @@ import
|
|||
]#
|
||||
|
||||
# Work around for https://github.com/nim-lang/Nim/issues/8645
|
||||
proc `%`*(value: Time): JsonNode =
|
||||
#[proc `%`*(value: Time): JsonNode =
|
||||
result = %value.toUnix
|
||||
|
||||
template balance(addressDb: ReadOnlyStateDb, address: EthAddress): GasInt =
|
||||
|
@ -83,65 +84,66 @@ proc binarySearchGas(vmState: var BaseVMState, transaction: Transaction, sender:
|
|||
else:
|
||||
maxVal = midPoint
|
||||
result = minVal
|
||||
|
||||
proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
||||
]#
|
||||
proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB , server: RpcServer) =
|
||||
|
||||
proc getAccountDb(header: BlockHeader): ReadOnlyStateDB =
|
||||
## Retrieves the account db from canonical head
|
||||
let ac = AccountsCache.init(chain.db, header.stateRoot, chain.pruneTrie)
|
||||
# we don't use accounst_cache here because it's only read operations
|
||||
let ac = newAccountStateDB(chain.db, header.stateRoot, chain.pruneTrie)
|
||||
result = ReadOnlyStateDB(ac)
|
||||
|
||||
proc accountDbFromTag(tag: string, readOnly = true): ReadOnlyStateDB =
|
||||
result = getAccountDb(chain.headerFromTag(tag))
|
||||
|
||||
proc getBlockBody(hash: KeccakHash): BlockBody =
|
||||
#[proc getBlockBody(hash: KeccakHash): BlockBody =
|
||||
if not chain.getBlockBody(hash, result):
|
||||
raise newException(ValueError, "Cannot find hash")
|
||||
raise newException(ValueError, "Cannot find hash")]#
|
||||
|
||||
rpcsrv.rpc("net_version") do() -> uint:
|
||||
let conf = getConfiguration()
|
||||
result = conf.net.networkId
|
||||
server.rpc("eth_protocolVersion") do() -> string:
|
||||
result = $eth_protocol.protocolVersion
|
||||
|
||||
rpcsrv.rpc("eth_syncing") do() -> JsonNode:
|
||||
server.rpc("eth_syncing") do() -> JsonNode:
|
||||
## Returns SyncObject or false when not syncing.
|
||||
# TODO: Requires PeerPool to check sync state.
|
||||
# TODO: Use variant objects
|
||||
var
|
||||
sync: SyncState
|
||||
if true:
|
||||
# TODO: Populate sync state, this is a placeholder
|
||||
sync.startingBlock = GENESIS_BLOCK_NUMBER
|
||||
sync.currentBlock = chain.getCanonicalHead().blockNumber
|
||||
sync.highestBlock = chain.getCanonicalHead().blockNumber
|
||||
let numPeers = node.peerPool.connectedNodes.len
|
||||
if numPeers > 0:
|
||||
var sync = SyncState(
|
||||
startingBlock: encodeQuantity chain.startingBlock,
|
||||
currentBlock : encodeQuantity chain.currentBlock,
|
||||
highestBlock : encodeQuantity chain.highestBlock
|
||||
)
|
||||
result = %sync
|
||||
else:
|
||||
result = newJBool(false)
|
||||
|
||||
rpcsrv.rpc("eth_coinbase") do() -> EthAddress:
|
||||
server.rpc("eth_coinbase") do() -> EthAddress:
|
||||
## Returns the current coinbase address.
|
||||
result = chain.getCanonicalHead().coinbase
|
||||
# currently we don't have miner
|
||||
result = default(EthAddress)
|
||||
|
||||
rpcsrv.rpc("eth_mining") do() -> bool:
|
||||
server.rpc("eth_mining") do() -> bool:
|
||||
## Returns true if the client is mining, otherwise false.
|
||||
discard
|
||||
# currently we don't have miner
|
||||
result = false
|
||||
|
||||
rpcsrv.rpc("eth_hashrate") do() -> int:
|
||||
server.rpc("eth_hashrate") do() -> HexQuantityStr:
|
||||
## Returns the number of hashes per second that the node is mining with.
|
||||
discard
|
||||
# currently we don't have miner
|
||||
result = encodeQuantity(0.uint)
|
||||
|
||||
rpcsrv.rpc("eth_gasPrice") do() -> int64:
|
||||
server.rpc("eth_gasPrice") do() -> HexQuantityStr:
|
||||
## Returns an integer of the current gas price in wei.
|
||||
discard
|
||||
result = encodeQuantity(calculateMedianGasPrice(chain).uint64)
|
||||
|
||||
rpcsrv.rpc("eth_accounts") do() -> seq[EthAddressStr]:
|
||||
server.rpc("eth_accounts") do() -> seq[EthAddressStr]:
|
||||
## Returns a list of addresses owned by client.
|
||||
result = @[]
|
||||
|
||||
rpcsrv.rpc("eth_blockNumber") do() -> BlockNumber:
|
||||
server.rpc("eth_blockNumber") do() -> HexQuantityStr:
|
||||
## Returns integer of the current block number the client is on.
|
||||
result = chain.getCanonicalHead().blockNumber
|
||||
result = encodeQuantity(chain.getCanonicalHead().blockNumber)
|
||||
|
||||
rpcsrv.rpc("eth_getBalance") do(data: EthAddressStr, quantityTag: string) -> UInt256:
|
||||
server.rpc("eth_getBalance") do(data: EthAddressStr, quantityTag: string) -> HexQuantityStr:
|
||||
## Returns the balance of the account of given address.
|
||||
##
|
||||
## data: address to check for balance.
|
||||
|
@ -149,12 +151,11 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
|||
## Returns integer of the current balance in wei.
|
||||
let
|
||||
accountDb = accountDbFromTag(quantityTag)
|
||||
addrBytes = data.toAddress
|
||||
balance = accountDb.getBalance(addrBytes)
|
||||
address = data.toAddress
|
||||
balance = accountDb.getBalance(address)
|
||||
result = encodeQuantity(balance)
|
||||
|
||||
result = balance
|
||||
|
||||
rpcsrv.rpc("eth_getStorageAt") do(data: EthAddressStr, quantity: int, quantityTag: string) -> UInt256:
|
||||
server.rpc("eth_getStorageAt") do(data: EthAddressStr, quantity: HexQuantityStr, quantityTag: string) -> HexDataStr:
|
||||
## Returns the value from a storage position at a given address.
|
||||
##
|
||||
## data: address of the storage.
|
||||
|
@ -163,29 +164,33 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
|||
## Returns: the value at this storage position.
|
||||
let
|
||||
accountDb = accountDbFromTag(quantityTag)
|
||||
addrBytes = data.toAddress
|
||||
result = accountDb.getStorage(addrBytes, quantity.u256)
|
||||
address = data.toAddress
|
||||
key = fromHex(Uint256, quantity.string)
|
||||
value = accountDb.getStorage(address, key)[0]
|
||||
result = hexDataStr(value)
|
||||
|
||||
rpcsrv.rpc("eth_getTransactionCount") do(data: EthAddressStr, quantityTag: string) -> AccountNonce:
|
||||
server.rpc("eth_getTransactionCount") do(data: EthAddressStr, quantityTag: string) -> HexQuantityStr:
|
||||
## Returns the number of transactions sent from an address.
|
||||
##
|
||||
## data: address.
|
||||
## quantityTag: integer block number, or the string "latest", "earliest" or "pending", see the default block parameter.
|
||||
## Returns integer of the number of transactions send from this address.
|
||||
let
|
||||
addrBytes = data.toAddress
|
||||
address = data.toAddress
|
||||
accountDb = accountDbFromTag(quantityTag)
|
||||
result = accountDb.getNonce(addrBytes)
|
||||
result = encodeQuantity(accountDb.getNonce(address))
|
||||
|
||||
rpcsrv.rpc("eth_getBlockTransactionCountByHash") do(data: EthHashStr) -> int:
|
||||
server.rpc("eth_getBlockTransactionCountByHash") do(data: EthHashStr) -> HexQuantityStr:
|
||||
## Returns the number of transactions in a block from a block matching the given block hash.
|
||||
##
|
||||
## data: hash of a block
|
||||
## Returns integer of the number of transactions in this block.
|
||||
var hashData = data.toHash
|
||||
result = getBlockBody(hashData).transactions.len
|
||||
|
||||
rpcsrv.rpc("eth_getBlockTransactionCountByNumber") do(quantityTag: string) -> int:
|
||||
let
|
||||
hashData = data.toHash
|
||||
txCount = chain.getTransactionCount(hashData)
|
||||
result = encodeQuantity(txCount.uint)
|
||||
#[
|
||||
server.rpc("eth_getBlockTransactionCountByNumber") do(quantityTag: string) -> int:
|
||||
## Returns the number of transactions in a block matching the given block number.
|
||||
##
|
||||
## data: integer of a block number, or the string "earliest", "latest" or "pending", as in the default block parameter.
|
||||
|
@ -193,7 +198,7 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
|||
let header = chain.headerFromTag(quantityTag)
|
||||
result = getBlockBody(header.hash).transactions.len
|
||||
|
||||
rpcsrv.rpc("eth_getUncleCountByBlockHash") do(data: EthHashStr) -> int:
|
||||
server.rpc("eth_getUncleCountByBlockHash") do(data: EthHashStr) -> int:
|
||||
## Returns the number of uncles in a block from a block matching the given block hash.
|
||||
##
|
||||
## data: hash of a block.
|
||||
|
@ -201,7 +206,7 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
|||
var hashData = data.toHash
|
||||
result = getBlockBody(hashData).uncles.len
|
||||
|
||||
rpcsrv.rpc("eth_getUncleCountByBlockNumber") do(quantityTag: string) -> int:
|
||||
server.rpc("eth_getUncleCountByBlockNumber") do(quantityTag: string) -> int:
|
||||
## Returns the number of uncles in a block from a block matching the given block number.
|
||||
##
|
||||
## quantityTag: integer of a block number, or the string "latest", "earliest" or "pending", see the default block parameter.
|
||||
|
@ -209,7 +214,7 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
|||
let header = chain.headerFromTag(quantityTag)
|
||||
result = getBlockBody(header.hash).uncles.len
|
||||
|
||||
rpcsrv.rpc("eth_getCode") do(data: EthAddressStr, quantityTag: string) -> HexDataStr:
|
||||
server.rpc("eth_getCode") do(data: EthAddressStr, quantityTag: string) -> HexDataStr:
|
||||
## Returns code at a given address.
|
||||
##
|
||||
## data: address
|
||||
|
@ -217,8 +222,8 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
|||
## Returns the code from the given address.
|
||||
let
|
||||
accountDb = accountDbFromTag(quantityTag)
|
||||
addrBytes = toAddress(data)
|
||||
storage = accountDb.getCode(addrBytes)
|
||||
address = toAddress(data)
|
||||
storage = accountDb.getCode(address)
|
||||
# Easier to return the string manually here rather than expect ByteRange to be marshalled
|
||||
result = byteutils.toHex(storage).HexDataStr
|
||||
|
||||
|
@ -227,7 +232,7 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
|||
let msgData = "\x19Ethereum Signed Message:\n" & $message.len & message
|
||||
$sign(privateKey, msgData.toBytes())
|
||||
|
||||
rpcsrv.rpc("eth_sign") do(data: EthAddressStr, message: HexDataStr) -> HexDataStr:
|
||||
server.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))).
|
||||
## By adding a prefix to the message makes the calculated signature recognisable as an Ethereum specific signature.
|
||||
## This prevents misuse where a malicious DApp can sign arbitrary data (e.g. transaction) and use the signature to impersonate the victim.
|
||||
|
@ -250,7 +255,7 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
|||
# s = 0.u256
|
||||
# result = initTransaction(send.nonce, send.gasPrice, send.gas, destination, send.value, data, v, r, s, contractCreation)
|
||||
|
||||
rpcsrv.rpc("eth_sendTransaction") do(obj: EthSend) -> HexDataStr:
|
||||
server.rpc("eth_sendTransaction") do(obj: EthSend) -> HexDataStr:
|
||||
## Creates new message call transaction or a contract creation, if the data field contains code.
|
||||
##
|
||||
## obj: the transaction object.
|
||||
|
@ -259,7 +264,7 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
|||
# TODO: Relies on pending pool implementation
|
||||
discard
|
||||
|
||||
rpcsrv.rpc("eth_sendRawTransaction") do(data: string, quantityTag: int) -> HexDataStr:
|
||||
server.rpc("eth_sendRawTransaction") do(data: string, quantityTag: int) -> HexDataStr:
|
||||
## Creates new message call transaction or a contract creation for signed transactions.
|
||||
##
|
||||
## data: the signed transaction data.
|
||||
|
@ -293,7 +298,7 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
|||
|
||||
result = newComputation(vmState, message)
|
||||
|
||||
rpcsrv.rpc("eth_call") do(call: EthCall, quantityTag: string) -> HexDataStr:
|
||||
server.rpc("eth_call") do(call: EthCall, quantityTag: string) -> HexDataStr:
|
||||
## Executes a new message call immediately without creating a transaction on the block chain.
|
||||
##
|
||||
## call: the transaction call object.
|
||||
|
@ -329,7 +334,7 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
|||
comp.execComputation
|
||||
result = ("0x" & nimcrypto.toHex(comp.output)).HexDataStr
|
||||
|
||||
rpcsrv.rpc("eth_estimateGas") do(call: EthCall, quantityTag: string) -> GasInt:
|
||||
server.rpc("eth_estimateGas") do(call: EthCall, quantityTag: string) -> GasInt:
|
||||
## Generates and returns an estimate of how much gas is necessary to allow the transaction to complete.
|
||||
## The transaction will not be added to the blockchain. Note that the estimate may be significantly more than
|
||||
## the amount of gas actually used by the transaction, for a variety of reasons including EVM mechanics and node performance.
|
||||
|
@ -402,7 +407,7 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
|||
for i in 0 ..< blockBody.uncles.len:
|
||||
result.uncles[i] = blockBody.uncles[i].hash
|
||||
|
||||
rpcsrv.rpc("eth_getBlockByHash") do(data: EthHashStr, fullTransactions: bool) -> Option[BlockObject]:
|
||||
server.rpc("eth_getBlockByHash") do(data: EthHashStr, fullTransactions: bool) -> Option[BlockObject]:
|
||||
## Returns information about a block by hash.
|
||||
##
|
||||
## data: Hash of a block.
|
||||
|
@ -413,7 +418,7 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
|||
header = chain.getBlockHeader(h)
|
||||
result = some(populateBlockObject(header, getBlockBody(h)))
|
||||
|
||||
rpcsrv.rpc("eth_getBlockByNumber") do(quantityTag: string, fullTransactions: bool) -> Option[BlockObject]:
|
||||
server.rpc("eth_getBlockByNumber") do(quantityTag: string, fullTransactions: bool) -> Option[BlockObject]:
|
||||
## Returns information about a block by block number.
|
||||
##
|
||||
## quantityTag: integer of a block number, or the string "earliest", "latest" or "pending", as in the default block parameter.
|
||||
|
@ -446,7 +451,7 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
|||
result.gas = accountGas
|
||||
result.input = transaction.payload
|
||||
|
||||
rpcsrv.rpc("eth_getTransactionByHash") do(data: EthHashStr) -> TransactionObject:
|
||||
server.rpc("eth_getTransactionByHash") do(data: EthHashStr) -> TransactionObject:
|
||||
## Returns the information about a transaction requested by transaction hash.
|
||||
##
|
||||
## data: hash of a transaction.
|
||||
|
@ -461,7 +466,7 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
|||
# TODO: if the requested transaction not in blockchain
|
||||
# try to look for pending transaction in txpool
|
||||
|
||||
rpcsrv.rpc("eth_getTransactionByBlockHashAndIndex") do(data: EthHashStr, quantity: int) -> TransactionObject:
|
||||
server.rpc("eth_getTransactionByBlockHashAndIndex") do(data: EthHashStr, quantity: int) -> TransactionObject:
|
||||
## Returns information about a transaction by block hash and transaction index position.
|
||||
##
|
||||
## data: hash of a block.
|
||||
|
@ -473,7 +478,7 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
|||
transaction = getBlockBody(blockHash).transactions[quantity]
|
||||
result = populateTransactionObject(transaction, quantity, header, blockHash)
|
||||
|
||||
rpcsrv.rpc("eth_getTransactionByBlockNumberAndIndex") do(quantityTag: string, quantity: int) -> TransactionObject:
|
||||
server.rpc("eth_getTransactionByBlockNumberAndIndex") do(quantityTag: string, quantity: int) -> TransactionObject:
|
||||
## Returns information about a transaction by block number and transaction index position.
|
||||
##
|
||||
## quantityTag: a block number, or the string "earliest", "latest" or "pending", as in the default block parameter.
|
||||
|
@ -513,7 +518,7 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
|||
# 1 = success, 0 = failure.
|
||||
result.status = some(receipt.status)
|
||||
|
||||
rpcsrv.rpc("eth_getTransactionReceipt") do(data: EthHashStr) -> ReceiptObject:
|
||||
server.rpc("eth_getTransactionReceipt") do(data: EthHashStr) -> ReceiptObject:
|
||||
## Returns the receipt of a transaction by transaction hash.
|
||||
##
|
||||
## data: hash of a transaction.
|
||||
|
@ -534,7 +539,7 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
|||
return populateReceipt(receipt, gasUsed, body.transactions[txDetails.index], txDetails.index, header)
|
||||
idx.inc
|
||||
|
||||
rpcsrv.rpc("eth_getUncleByBlockHashAndIndex") do(data: EthHashStr, quantity: int) -> Option[BlockObject]:
|
||||
server.rpc("eth_getUncleByBlockHashAndIndex") do(data: EthHashStr, quantity: int) -> Option[BlockObject]:
|
||||
## Returns information about a uncle of a block by hash and uncle index position.
|
||||
##
|
||||
## data: hash of block.
|
||||
|
@ -548,7 +553,7 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
|||
let uncle = body.uncles[quantity]
|
||||
result = some(populateBlockObject(uncle, body))
|
||||
|
||||
rpcsrv.rpc("eth_getUncleByBlockNumberAndIndex") do(quantityTag: string, quantity: int) -> Option[BlockObject]:
|
||||
server.rpc("eth_getUncleByBlockNumberAndIndex") do(quantityTag: string, quantity: int) -> Option[BlockObject]:
|
||||
# Returns information about a uncle of a block by number and uncle index position.
|
||||
##
|
||||
## quantityTag: a block number, or the string "earliest", "latest" or "pending", as in the default block parameter.
|
||||
|
@ -562,7 +567,7 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
|||
let uncle = body.uncles[quantity]
|
||||
result = some(populateBlockObject(uncle, body))
|
||||
|
||||
rpcsrv.rpc("eth_newFilter") do(filterOptions: FilterOptions) -> int:
|
||||
server.rpc("eth_newFilter") do(filterOptions: FilterOptions) -> int:
|
||||
## Creates a filter object, based on filter options, to notify when the state changes (logs).
|
||||
## To check if the state has changed, call eth_getFilterChanges.
|
||||
## Topics are order-dependent. A transaction with a log with topics [A, B] will be matched by the following topic filters:
|
||||
|
@ -576,21 +581,21 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
|||
## Returns integer filter id.
|
||||
discard
|
||||
|
||||
rpcsrv.rpc("eth_newBlockFilter") do() -> int:
|
||||
server.rpc("eth_newBlockFilter") do() -> int:
|
||||
## Creates a filter in the node, to notify when a new block arrives.
|
||||
## To check if the state has changed, call eth_getFilterChanges.
|
||||
##
|
||||
## Returns integer filter id.
|
||||
discard
|
||||
|
||||
rpcsrv.rpc("eth_newPendingTransactionFilter") do() -> int:
|
||||
server.rpc("eth_newPendingTransactionFilter") do() -> int:
|
||||
## Creates a filter in the node, to notify when a new block arrives.
|
||||
## To check if the state has changed, call eth_getFilterChanges.
|
||||
##
|
||||
## Returns integer filter id.
|
||||
discard
|
||||
|
||||
rpcsrv.rpc("eth_uninstallFilter") do(filterId: int) -> bool:
|
||||
server.rpc("eth_uninstallFilter") do(filterId: int) -> bool:
|
||||
## Uninstalls a filter with given id. Should always be called when watch is no longer needed.
|
||||
## Additonally Filters timeout when they aren't requested with eth_getFilterChanges for a period of time.
|
||||
##
|
||||
|
@ -598,23 +603,23 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
|||
## Returns true if the filter was successfully uninstalled, otherwise false.
|
||||
discard
|
||||
|
||||
rpcsrv.rpc("eth_getFilterChanges") do(filterId: int) -> seq[FilterLog]:
|
||||
server.rpc("eth_getFilterChanges") do(filterId: int) -> seq[FilterLog]:
|
||||
## Polling method for a filter, which returns an list of logs which occurred since last poll.
|
||||
##
|
||||
## filterId: the filter id.
|
||||
result = @[]
|
||||
|
||||
rpcsrv.rpc("eth_getFilterLogs") do(filterId: int) -> seq[FilterLog]:
|
||||
server.rpc("eth_getFilterLogs") do(filterId: int) -> seq[FilterLog]:
|
||||
## filterId: the filter id.
|
||||
## Returns a list of all logs matching filter with given id.
|
||||
result = @[]
|
||||
|
||||
rpcsrv.rpc("eth_getLogs") do(filterOptions: FilterOptions) -> seq[FilterLog]:
|
||||
server.rpc("eth_getLogs") do(filterOptions: FilterOptions) -> seq[FilterLog]:
|
||||
## filterOptions: settings for this filter.
|
||||
## Returns a list of all logs matching a given filter object.
|
||||
result = @[]
|
||||
|
||||
rpcsrv.rpc("eth_getWork") do() -> array[3, UInt256]:
|
||||
server.rpc("eth_getWork") do() -> array[3, UInt256]:
|
||||
## Returns the hash of the current block, the seedHash, and the boundary condition to be met ("target").
|
||||
## Returned list has the following properties:
|
||||
## DATA, 32 Bytes - current block header pow-hash.
|
||||
|
@ -622,7 +627,7 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
|||
## DATA, 32 Bytes - the boundary condition ("target"), 2^256 / difficulty.
|
||||
discard
|
||||
|
||||
rpcsrv.rpc("eth_submitWork") do(nonce: int64, powHash: HexDataStr, mixDigest: HexDataStr) -> bool:
|
||||
server.rpc("eth_submitWork") do(nonce: int64, powHash: HexDataStr, mixDigest: HexDataStr) -> bool:
|
||||
## Used for submitting a proof-of-work solution.
|
||||
##
|
||||
## nonce: the nonce found.
|
||||
|
@ -631,12 +636,10 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
|||
## Returns true if the provided solution is valid, otherwise false.
|
||||
discard
|
||||
|
||||
rpcsrv.rpc("eth_submitHashrate") do(hashRate: HexDataStr, id: HexDataStr) -> bool:
|
||||
server.rpc("eth_submitHashrate") do(hashRate: HexDataStr, id: HexDataStr) -> bool:
|
||||
## Used for submitting mining hashrate.
|
||||
##
|
||||
## hashRate: a hexadecimal string representation (32 bytes) of the hash rate.
|
||||
## id: a random hexadecimal(32 bytes) ID identifying the client.
|
||||
## Returns true if submitting went through succesfully and false otherwise.
|
||||
discard
|
||||
|
||||
|
||||
discard]#
|
||||
|
|
|
@ -16,9 +16,9 @@ import
|
|||
type
|
||||
SyncState* = object
|
||||
# Returned to user
|
||||
startingBlock*: BlockNumber
|
||||
currentBlock*: BlockNumber
|
||||
highestBlock*: BlockNumber
|
||||
startingBlock*: HexQuantityStr # BlockNumber
|
||||
currentBlock* : HexQuantityStr # BlockNumber
|
||||
highestBlock* : HexQuantityStr # BlockNumber
|
||||
|
||||
EthSend* = object
|
||||
# Parameter from user
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
import hexstrings, eth/common, stew/byteutils,
|
||||
../db/[db_chain], strutils,
|
||||
import hexstrings, eth/[common, rlp], stew/byteutils,
|
||||
../db/[db_chain], strutils, algorithm,
|
||||
../constants, stint
|
||||
|
||||
func toAddress*(value: EthAddressStr): EthAddress = hexToPaddedByteArray[20](value.string)
|
||||
|
@ -32,3 +32,20 @@ proc headerFromTag*(chain: BaseChainDB, blockTag: string): BlockHeader =
|
|||
tag.validateHexQuantity
|
||||
let blockNum = stint.fromHex(UInt256, tag)
|
||||
result = chain.getBlockHeader(blockNum.toBlockNumber)
|
||||
|
||||
proc calculateMedianGasPrice*(chain: BaseChainDB): GasInt =
|
||||
var prices = newSeqOfCap[GasInt](64)
|
||||
let header = chain.getCanonicalHead()
|
||||
for encodedTx in chain.getBlockTransactionData(header.txRoot):
|
||||
let tx = rlp.decode(encodedTx, Transaction)
|
||||
prices.add(tx.gasPrice)
|
||||
|
||||
if prices.len > 0:
|
||||
sort(prices)
|
||||
let middle = prices.len div 2
|
||||
if prices.len mod 2 == 0:
|
||||
# prevent overflow
|
||||
let price = prices[middle].uint64 + prices[middle - 1].uint64
|
||||
result = (price div 2).GasInt
|
||||
else:
|
||||
result = prices[middle]
|
||||
|
|
|
@ -50,7 +50,7 @@ proc captureAccount(n: JsonNode, db: AccountsCache, address: EthAddress, name: s
|
|||
let codeHash = db.getCodeHash(address)
|
||||
let storageRoot = db.getStorageRoot(address)
|
||||
|
||||
jaccount["nonce"] = %(encodeQuantity(nonce).toLowerAscii)
|
||||
jaccount["nonce"] = %(encodeQuantity(nonce).string.toLowerAscii)
|
||||
jaccount["balance"] = %("0x" & balance.toHex)
|
||||
|
||||
let code = db.getCode(address)
|
||||
|
|
|
@ -16,20 +16,20 @@ import
|
|||
proc web3_clientVersion(): string
|
||||
proc web3_sha3(data: string): string
|
||||
proc net_version(): string
|
||||
proc net_peerCount(): int
|
||||
proc net_peerCount(): HexQuantityStr
|
||||
proc net_listening(): bool
|
||||
proc eth_protocolVersion(): string
|
||||
proc eth_syncing(): JsonNode
|
||||
proc eth_coinbase(): EthAddressStr
|
||||
proc eth_mining(): bool
|
||||
proc eth_hashrate(): int
|
||||
proc eth_gasPrice(): GasInt
|
||||
proc eth_hashrate(): HexQuantityStr
|
||||
proc eth_gasPrice(): HexQuantityStr
|
||||
proc eth_accounts(): seq[EthAddressStr]
|
||||
proc eth_blockNumber(): BlockNumber
|
||||
proc eth_getBalance(data: EthAddressStr, quantityTag: string): UInt256
|
||||
proc eth_getStorageAt(data: EthAddressStr, quantity: int, quantityTag: string): seq[byte]
|
||||
proc eth_getTransactionCount(data: EthAddressStr, quantityTag: string)
|
||||
proc eth_getBlockTransactionCountByHash(data: array[32, byte])
|
||||
proc eth_blockNumber(): HexQuantityStr
|
||||
proc eth_getBalance(data: EthAddressStr, quantityTag: string): HexQuantityStr
|
||||
proc eth_getStorageAt(data: EthAddressStr, quantity: HexQuantityStr, quantityTag: string): seq[byte]
|
||||
proc eth_getTransactionCount(data: EthAddressStr, quantityTag: string): HexQuantityStr
|
||||
proc eth_getBlockTransactionCountByHash(data: Hash256): HexQuantityStr
|
||||
proc eth_getBlockTransactionCountByNumber(quantityTag: string)
|
||||
proc eth_getUncleCountByBlockHash(data: array[32, byte])
|
||||
proc eth_getUncleCountByBlockNumber(quantityTag: string)
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
unittest, json, strformat, options, nimcrypto, stew/byteutils,
|
||||
unittest, json, strformat, strutils, options, tables, nimcrypto, stew/byteutils,
|
||||
json_rpc/[rpcserver, rpcclient], eth/common as eth_common,
|
||||
eth/[rlp, keys], eth/trie/db, eth/p2p/rlpx_protocols/eth_protocol,
|
||||
../nimbus/rpc/[common, p2p, hexstrings, rpc_types],
|
||||
|
@ -18,7 +18,7 @@ import
|
|||
from eth/p2p/rlpx_protocols/whisper_protocol import SymKey
|
||||
|
||||
# Perform checks for hex string validation
|
||||
doHexStrTests()
|
||||
#doHexStrTests()
|
||||
|
||||
from os import getCurrentDir, DirSep
|
||||
from strutils import rsplit
|
||||
|
@ -32,6 +32,7 @@ createRpcSigs(RpcSocketClient, sigPath)
|
|||
proc toEthAddressStr(address: EthAddress): EthAddressStr =
|
||||
result = ("0x" & address.toHex).ethAddressStr
|
||||
|
||||
|
||||
proc doTests {.async.} =
|
||||
# TODO: Include other transports such as Http
|
||||
var ethNode = setupEthNode(eth)
|
||||
|
@ -57,7 +58,7 @@ proc doTests {.async.} =
|
|||
var
|
||||
rpcServer = newRpcSocketServer(["localhost:" & $RPC_PORT])
|
||||
client = newRpcSocketClient()
|
||||
setupCommonRpc(rpcServer)
|
||||
setupCommonRpc(ethNode, rpcServer)
|
||||
setupEthRpc(ethNode, chain, rpcServer)
|
||||
|
||||
# Begin tests
|
||||
|
@ -66,25 +67,122 @@ proc doTests {.async.} =
|
|||
|
||||
# TODO: add more tests here
|
||||
suite "Remote Procedure Calls":
|
||||
test "eth_call":
|
||||
let
|
||||
blockNum = state.blockheader.blockNumber
|
||||
callParams = EthCall(value: some(100.u256))
|
||||
r1 = await client.eth_call(callParams, "0x" & blockNum.toHex)
|
||||
check r1 == "0x"
|
||||
test "eth_getBalance":
|
||||
let r2 = await client.eth_getBalance(ZERO_ADDRESS.toEthAddressStr, "0x0")
|
||||
check r2 == 0
|
||||
test "web3_clientVersion":
|
||||
let res = await client.web3_clientVersion()
|
||||
check res == NimbusIdent
|
||||
|
||||
let blockNum = state.blockheader.blockNumber
|
||||
let r3 = await client.eth_getBalance(address.toEthAddressStr, "0x" & blockNum.toHex)
|
||||
check r3 == 0
|
||||
test "eth_estimateGas":
|
||||
let
|
||||
call = EthCall()
|
||||
blockNum = state.blockheader.blockNumber
|
||||
r4 = await client.eth_estimateGas(call, "0x" & blockNum.toHex)
|
||||
check r4 == 21_000
|
||||
test "web3_sha3":
|
||||
expect ValueError:
|
||||
discard await client.web3_sha3(NimbusName)
|
||||
|
||||
let data = "0x" & byteutils.toHex(NimbusName.toOpenArrayByte(0, NimbusName.len-1))
|
||||
let res = await client.web3_sha3(data)
|
||||
let rawdata = nimcrypto.fromHex(data[2 .. ^1])
|
||||
let hash = "0x" & $keccak_256.digest(rawdata)
|
||||
check hash == res
|
||||
|
||||
test "net_version":
|
||||
let res = await client.net_version()
|
||||
check res == $conf.net.networkId
|
||||
|
||||
test "net_listening":
|
||||
let res = await client.net_listening()
|
||||
let listening = ethNode.peerPool.connectedNodes.len < conf.net.maxPeers
|
||||
check res == listening
|
||||
|
||||
test "net_peerCount":
|
||||
let res = await client.net_peerCount()
|
||||
let peerCount = ethNode.peerPool.connectedNodes.len
|
||||
check isValidHexQuantity res.string
|
||||
check res == encodeQuantity(peerCount.uint)
|
||||
|
||||
test "eth_protocolVersion":
|
||||
let res = await client.eth_protocolVersion()
|
||||
check res == $eth_protocol.protocolVersion
|
||||
|
||||
test "eth_syncing":
|
||||
let res = await client.eth_syncing()
|
||||
if res.kind == JBool:
|
||||
let syncing = ethNode.peerPool.connectedNodes.len > 0
|
||||
check res.getBool() == syncing
|
||||
else:
|
||||
check res.kind == JObject
|
||||
check chain.startingBlock == UInt256.fromHex(res["startingBlock"].getStr())
|
||||
check chain.currentBlock == UInt256.fromHex(res["currentBlock"].getStr())
|
||||
check chain.highestBlock == UInt256.fromHex(res["highestBlock"].getStr())
|
||||
|
||||
test "eth_coinbase":
|
||||
let res = await client.eth_coinbase()
|
||||
# currently we don't have miner
|
||||
check isValidEthAddress(res.string)
|
||||
check res == ethAddressStr(EthAddress.default)
|
||||
|
||||
test "eth_mining":
|
||||
let res = await client.eth_mining()
|
||||
# currently we don't have miner
|
||||
check res == false
|
||||
|
||||
test "eth_hashrate":
|
||||
let res = await client.eth_hashrate()
|
||||
# currently we don't have miner
|
||||
check res == encodeQuantity(0.uint)
|
||||
|
||||
test "eth_gasPrice":
|
||||
let res = await client.eth_gasPrice()
|
||||
# genesis block doesn't have any transaction
|
||||
# to generate meaningful prices
|
||||
check res.string == "0x0"
|
||||
|
||||
test "eth_accounts":
|
||||
let res = await client.eth_accounts()
|
||||
# we do not own any accounts, yet
|
||||
check res.len == 0
|
||||
|
||||
test "eth_blockNumber":
|
||||
let res = await client.eth_blockNumber()
|
||||
check res.string == "0x0"
|
||||
|
||||
test "eth_getBalance":
|
||||
let a = await client.eth_getBalance(ethAddressStr("0xfff33a3bd36abdbd412707b8e310d6011454a7ae"), "0x0")
|
||||
check a.string == "0x1b1ae4d6e2ef5000000"
|
||||
let b = await client.eth_getBalance(ethAddressStr("0xfff4bad596633479a2a29f9a8b3f78eefd07e6ee"), "0x0")
|
||||
check b.string == "0x56bc75e2d63100000"
|
||||
let c = await client.eth_getBalance(ethAddressStr("0xfff7ac99c8e4feb60c9750054bdc14ce1857f181"), "0x0")
|
||||
check c.string == "0x3635c9adc5dea00000"
|
||||
|
||||
test "eth_getStorageAt":
|
||||
let res = await client.eth_getStorageAt(ethAddressStr("0xfff33a3bd36abdbd412707b8e310d6011454a7ae"), hexQuantityStr "0x0", "0x0")
|
||||
check hexDataStr(0.u256).string == hexDataStr(res).string
|
||||
|
||||
test "eth_getTransactionCount":
|
||||
let res = await client.eth_getTransactionCount(ethAddressStr("0xfff7ac99c8e4feb60c9750054bdc14ce1857f181"), "0x0")
|
||||
check res.string == "0x0"
|
||||
|
||||
test "eth_getBlockTransactionCountByHash":
|
||||
let hash = chain.getBlockHash(0.toBlockNumber)
|
||||
let res = await client.eth_getBlockTransactionCountByHash(hash)
|
||||
check res.string == "0x0"
|
||||
|
||||
|
||||
#test "eth_call":
|
||||
# let
|
||||
# blockNum = state.blockheader.blockNumber
|
||||
# callParams = EthCall(value: some(100.u256))
|
||||
# r1 = await client.eth_call(callParams, "0x" & blockNum.toHex)
|
||||
# check r1 == "0x"
|
||||
#test "eth_getBalance":
|
||||
# let r2 = await client.eth_getBalance(ZERO_ADDRESS.toEthAddressStr, "0x0")
|
||||
# check r2 == 0
|
||||
#
|
||||
# let blockNum = state.blockheader.blockNumber
|
||||
# let r3 = await client.eth_getBalance(address.toEthAddressStr, "0x" & blockNum.toHex)
|
||||
# check r3 == 0
|
||||
#test "eth_estimateGas":
|
||||
# let
|
||||
# call = EthCall()
|
||||
# blockNum = state.blockheader.blockNumber
|
||||
# r4 = await client.eth_estimateGas(call, "0x" & blockNum.toHex)
|
||||
# check r4 == 21_000
|
||||
|
||||
rpcServer.stop()
|
||||
rpcServer.close()
|
||||
|
|
Loading…
Reference in New Issue