2019-01-06 15:21:34 +00:00
|
|
|
import
|
|
|
|
json_rpc/[rpcclient], json, parser, httputils, strutils,
|
2019-02-05 19:15:50 +00:00
|
|
|
eth/[common, rlp], chronicles, ../nimbus/[utils], nimcrypto
|
2019-01-06 15:21:34 +00:00
|
|
|
|
|
|
|
logScope:
|
|
|
|
topics = "downloader"
|
|
|
|
|
|
|
|
type
|
|
|
|
Block* = object
|
|
|
|
header*: BlockHeader
|
|
|
|
body*: BlockBody
|
|
|
|
traces*: JsonNode
|
|
|
|
receipts*: seq[Receipt]
|
|
|
|
jsonData*: JsonNode
|
|
|
|
|
|
|
|
DownloadFlags* = enum
|
|
|
|
DownloadReceipts
|
|
|
|
DownloadTxTrace
|
|
|
|
|
|
|
|
proc request*(methodName: string, params: JsonNode): JsonNode =
|
|
|
|
var client = newRpcHttpClient()
|
|
|
|
client.httpMethod(MethodPost)
|
|
|
|
waitFor client.connect("localhost", Port(8545))
|
|
|
|
var r = waitFor client.call(methodName, params)
|
|
|
|
if r.error:
|
|
|
|
result = newJNull()
|
|
|
|
else:
|
|
|
|
result = r.result
|
|
|
|
client.transp.close()
|
|
|
|
|
|
|
|
proc requestBlockBody(n: JsonNode, blockNumber: BlockNumber): BlockBody =
|
|
|
|
let txs = n["transactions"]
|
|
|
|
if txs.len > 0:
|
|
|
|
result.transactions = newSeqOfCap[Transaction](txs.len)
|
|
|
|
for tx in txs:
|
|
|
|
let txn = parseTransaction(tx)
|
|
|
|
result.transactions.add txn
|
|
|
|
|
|
|
|
let uncles = n["uncles"]
|
|
|
|
if uncles.len > 0:
|
|
|
|
result.uncles = newSeqOfCap[BlockHeader](uncles.len)
|
|
|
|
let blockNumber = blockNumber.prefixHex
|
|
|
|
for i in 0 ..< uncles.len:
|
|
|
|
let idx = i.prefixHex
|
|
|
|
let uncle = request("eth_getUncleByBlockNumberAndIndex", %[%blockNumber, %idx])
|
|
|
|
if uncle.kind == JNull:
|
|
|
|
error "requested uncle not available", blockNumber=blockNumber, uncleIdx=i
|
|
|
|
raise newException(ValueError, "Error when retrieving block uncles")
|
|
|
|
result.uncles.add parseBlockHeader(uncle)
|
|
|
|
|
|
|
|
proc requestReceipts(n: JsonNode): seq[Receipt] =
|
|
|
|
let txs = n["transactions"]
|
|
|
|
if txs.len > 0:
|
|
|
|
result = newSeqOfCap[Receipt](txs.len)
|
|
|
|
for tx in txs:
|
|
|
|
let txHash = tx["hash"]
|
|
|
|
let rec = request("eth_getTransactionReceipt", %[txHash])
|
|
|
|
if rec.kind == JNull:
|
|
|
|
error "requested receipt not available", txHash=txHash
|
|
|
|
raise newException(ValueError, "Error when retrieving block receipts")
|
|
|
|
result.add parseReceipt(rec)
|
|
|
|
|
|
|
|
proc requestTxTraces(n: JsonNode): JsonNode =
|
2019-01-11 06:53:18 +00:00
|
|
|
result = newJArray()
|
2019-01-06 15:21:34 +00:00
|
|
|
let txs = n["transactions"]
|
2019-01-11 06:53:18 +00:00
|
|
|
if txs.len == 0: return
|
|
|
|
for tx in txs:
|
|
|
|
let txHash = tx["hash"]
|
|
|
|
let txTrace = request("debug_traceTransaction", %[txHash])
|
|
|
|
if txTrace.kind == JNull:
|
|
|
|
error "requested trace not available", txHash=txHash
|
|
|
|
raise newException(ValueError, "Error when retrieving transaction trace")
|
|
|
|
result.add txTrace
|
2019-01-06 15:21:34 +00:00
|
|
|
|
2019-02-22 08:52:53 +00:00
|
|
|
proc requestHeader*(blockNumber: BlockNumber): JsonNode =
|
|
|
|
result = request("eth_getBlockByNumber", %[%blockNumber.prefixHex, %true])
|
|
|
|
if result.kind == JNull:
|
2019-01-06 15:21:34 +00:00
|
|
|
error "requested block not available", blockNumber=blockNumber
|
|
|
|
raise newException(ValueError, "Error when retrieving block header")
|
|
|
|
|
2019-02-22 08:52:53 +00:00
|
|
|
proc requestBlock*(blockNumber: BlockNumber, flags: set[DownloadFlags] = {}): Block =
|
|
|
|
let header = requestHeader(blockNumber)
|
2019-01-06 15:21:34 +00:00
|
|
|
result.jsonData = header
|
|
|
|
result.header = parseBlockHeader(header)
|
|
|
|
result.body = requestBlockBody(header, blockNumber)
|
|
|
|
|
|
|
|
if DownloadTxTrace in flags:
|
|
|
|
result.traces = requestTxTraces(header)
|
|
|
|
|
|
|
|
let
|
|
|
|
txRoot = calcTxRoot(result.body.transactions).prefixHex
|
|
|
|
txRootOK = result.header.txRoot.prefixHex
|
|
|
|
ommersHash = rlpHash(result.body.uncles).prefixHex
|
|
|
|
ommersHashOK = result.header.ommersHash.prefixHex
|
|
|
|
headerHash = rlpHash(result.header).prefixHex
|
|
|
|
headerHashOK = header["hash"].getStr().toLowerAscii
|
|
|
|
|
|
|
|
if DownloadReceipts in flags:
|
|
|
|
result.receipts = requestReceipts(header)
|
|
|
|
let
|
|
|
|
receiptRoot = calcReceiptRoot(result.receipts).prefixHex
|
|
|
|
receiptRootOK = result.header.receiptRoot.prefixHex
|
|
|
|
if receiptRoot != receiptRootOK:
|
|
|
|
debug "wrong receipt root", receiptRoot, receiptRootOK, blockNumber
|
|
|
|
raise newException(ValueError, "Error when validating receipt root")
|
|
|
|
|
|
|
|
if txRoot != txRootOK:
|
|
|
|
debug "wrong tx root", txRoot, txRootOK, blockNumber
|
|
|
|
raise newException(ValueError, "Error when validating tx root")
|
|
|
|
|
|
|
|
if ommersHash != ommersHashOK:
|
|
|
|
debug "wrong ommers hash", ommersHash, ommersHashOK, blockNumber
|
|
|
|
raise newException(ValueError, "Error when validating ommers hash")
|
|
|
|
|
|
|
|
if headerHash != headerHashOK:
|
|
|
|
debug "wrong header hash", headerHash, headerHashOK, blockNumber
|
|
|
|
raise newException(ValueError, "Error when validating block header hash")
|