diff --git a/nimbus.nimble b/nimbus.nimble
index 43d67eafc..33f1267bb 100644
--- a/nimbus.nimble
+++ b/nimbus.nimble
@@ -39,9 +39,10 @@ task test, "Run tests":
test "all_tests"
# debugging tools don't yet have tests
# but they should be compilable
- buildBinary "premix", "premix/"
- buildBinary "persist", "premix/"
- buildBinary "debug", "premix/"
+ exec "nim c premix/premix"
+ exec "nim c premix/persist"
+ exec "nim c premix/debug"
+ exec "nim c premix/dumper"
task nimbus, "Build Nimbus":
buildBinary "nimbus", "nimbus/"
diff --git a/nimbus/tracer.nim b/nimbus/tracer.nim
index 8062811b3..8fdaeb659 100644
--- a/nimbus/tracer.nim
+++ b/nimbus/tracer.nim
@@ -2,7 +2,7 @@ import
db/[db_chain, state_db, capturedb], eth_common, utils, json,
constants, vm_state, vm_types, transaction, p2p/executor,
eth_trie/db, nimcrypto, strutils, ranges, ./utils/addresses,
- chronicles
+ chronicles, rpc/hexstrings
proc getParentHeader(self: BaseChainDB, header: BlockHeader): BlockHeader =
self.getBlockHeader(header.parentHash)
@@ -46,19 +46,19 @@ proc getRecipient*(tx: Transaction): EthAddress =
proc captureAccount(n: JsonNode, db: AccountStateDB, address: EthAddress, name: string) =
var jaccount = newJObject()
jaccount["name"] = %name
- jaccount["address"] = %($address)
+ jaccount["address"] = %("0x" & $address)
let account = db.getAccount(address)
- jaccount["nonce"] = %(account.nonce.toHex)
- jaccount["balance"] = %(account.balance.toHex)
+ jaccount["nonce"] = %(encodeQuantity(account.nonce).toLowerAscii)
+ jaccount["balance"] = %("0x" & account.balance.toHex)
let code = db.getCode(address)
- jaccount["codeHash"] = %(($account.codeHash).toLowerAscii)
- jaccount["code"] = %(toHex(code.toOpenArray, true))
- jaccount["storageRoot"] = %(($account.storageRoot).toLowerAscii)
+ jaccount["codeHash"] = %("0x" & ($account.codeHash).toLowerAscii)
+ jaccount["code"] = %("0x" & toHex(code.toOpenArray, true))
+ jaccount["storageRoot"] = %("0x" & ($account.storageRoot).toLowerAscii)
var storage = newJObject()
for key, value in db.storage(address):
- storage[key.dumpHex] = %(value.dumpHex)
+ storage["0x" & key.dumpHex] = %("0x" & value.dumpHex)
jaccount["storage"] = storage
n.add jaccount
diff --git a/premix/assets/js/index.js b/premix/assets/js/index.js
index d504418af..8ec30552c 100644
--- a/premix/assets/js/index.js
+++ b/premix/assets/js/index.js
@@ -120,6 +120,7 @@ function opCodeRenderer(txId, nimbus, geth) {
}
function transactionsRenderer(txId, nimbus, geth) {
+ txId = parseInt(txId);
$('#transactionsTitle').text(`Tx #${(txId+1)}`);
let container = $('#transactionsContainer').empty();
@@ -130,13 +131,17 @@ function transactionsRenderer(txId, nimbus, geth) {
premix.renderRow(body, nimbus, geth, x);
}
- // TODO: receipt logs
+ // TODO: render receipt logs
}
txId = parseInt(txId);
let ntx = nimbus.txTraces[txId];
let gtx = geth.txTraces[txId];
+ if(ntx.returnValue.length == 0) {
+ ntx.returnValue = "0x";
+ }
+
let ncr = $.extend({
gas: ntx.gas,
returnValue: ntx.returnValue
@@ -155,36 +160,52 @@ function transactionsRenderer(txId, nimbus, geth) {
}
function headerRenderer(nimbus, geth) {
+ function emptyAccount() {
+ return {
+ address: '',
+ nonce: '',
+ balance: '',
+ codeHash: '',
+ code: '',
+ storageRoot: '',
+ storage: {}
+ };
+ }
+
let container = $('#headerContainer').empty();
let ncs = nimbus.stateDump.after;
let gcs = geth.accounts;
+ let accounts = [];
-
- for(var n of ncs) {
- n.address = '0x' + n.address;
- n.balance = '0x' + n.balance;
- n.code = '0x' + n.code;
- let g = gcs[n.address];
-
+ for(var address in ncs) {
+ let n = ncs[address];
+ n.address = address;
+ if(gcs[address]) {
+ let geth = gcs[address];
+ geth.address = address;
+ accounts.push({name: n.name, nimbus: n, geth: geth});
+ delete gcs[address];
+ } else {
+ accounts.push({name: n.name, nimbus: n, geth: emptyAccount()});
+ }
}
- /*"name": "internalTx0",
- "address": "0000000000000000000000000000000000000004",
- "nonce": "0000000000000000",
- "balance": "0",
- "codeHash": "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
- "code": "",
- "storageRoot": "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
- "storage": {}*/
-
- /*"0xf927a40c8b7f6e07c5af7fa2155b4864a4112b13": {
- "balance": "0x607c9cea65ef7e19dd8",
- "nonce": "0000000000000000",
- "code": "0x",
- "storage": {}*/
-
+ for(var address in gcs) {
+ let geth = gcs[address];
+ geth.address = address;
+ accounts.push({name: "unknown", nimbus: emptyAccount(), geth: geth});
+ }
+ for(var acc of accounts) {
+ $(`
Account Name: ${acc.name}
`).appendTo(container);
+ let body = premix.newTable(container);
+ const fields = ['address', 'nonce', 'balance', 'codeHash', 'code', 'storageRoot'];
+ for(var x of fields) {
+ premix.renderRow(body, acc.nimbus, acc.geth, x);
+ }
+ $('
').appendTo(container);
+ }
}
function generateNavigation(txs, nimbus, geth) {
@@ -201,8 +222,8 @@ function generateNavigation(txs, nimbus, geth) {
let list = $('').appendTo(div);
for(var i in txs) {
- let id = i.toString();
- $(`TX #${id}`).appendTo(list);
+ let id = parseInt(i) + 1;
+ $(`TX #${id}`).appendTo(list);
}
list.find('li a').click(function(ev) {
diff --git a/premix/downloader.nim b/premix/downloader.nim
index a18537f90..c28e2fcaf 100644
--- a/premix/downloader.nim
+++ b/premix/downloader.nim
@@ -61,16 +61,16 @@ proc requestReceipts(n: JsonNode): seq[Receipt] =
result.add parseReceipt(rec)
proc requestTxTraces(n: JsonNode): JsonNode =
+ result = newJArray()
let txs = n["transactions"]
- if txs.len > 0:
- result = newJArray()
- 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
+ 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
proc requestBlock*(blockNumber: BlockNumber, flags: set[DownloadFlags] = {}): Block =
var header = request("eth_getBlockByNumber", %[%blockNumber.prefixHex, %true])
diff --git a/premix/js_tracer.nim b/premix/js_tracer.nim
index 4b09e65e6..999c52d04 100644
--- a/premix/js_tracer.nim
+++ b/premix/js_tracer.nim
@@ -1,13 +1,11 @@
const postStateTracer* = """{
- postState: null,
+ postState: {},
// lookupAccount injects the specified account into the postState object.
lookupAccount: function(addr, db){
var acc = toHex(addr);
if (this.postState[acc] === undefined) {
this.postState[acc] = {
- balance: '0x' + db.getBalance(addr).toString(16),
- nonce: db.getNonce(addr),
code: toHex(db.getCode(addr)),
storage: {}
};
@@ -19,9 +17,9 @@ const postStateTracer* = """{
lookupStorage: function(addr, key, db){
var acc = toHex(addr);
var idx = toHex(key);
-
+ this.lookupAccount(addr, db);
if (this.postState[acc].storage[idx] === undefined) {
- this.postState[acc].storage[idx] = "";//toHex(db.getState(addr, key));
+ this.postState[acc].storage[idx] = "";
}
},
diff --git a/premix/parser.nim b/premix/parser.nim
index 753ace1b7..f28654720 100644
--- a/premix/parser.nim
+++ b/premix/parser.nim
@@ -6,7 +6,7 @@ import
import
../nimbus/[transaction, rpc/hexstrings]
-func hexToInt(s: string, T: typedesc[SomeInteger]): T =
+func hexToInt*(s: string, T: typedesc[SomeInteger]): T =
var i = 0
if s[i] == '0' and (s[i+1] in {'x', 'X'}): inc(i, 2)
if s.len - i > sizeof(T) * 2:
diff --git a/premix/premix.nim b/premix/premix.nim
index 57d6f7682..972ff2690 100644
--- a/premix/premix.nim
+++ b/premix/premix.nim
@@ -29,20 +29,53 @@ proc requestTrace(txHash, tracer: JsonNode): JsonNode =
raise newException(ValueError, "Error when retrieving transaction postState")
result = txTrace
-proc requestPostState(n: JsonNode, jsTracer: string): JsonNode =
+proc requestBlockState(postState: JsonNode, thisBlock: Block, addresses: openArray[EthAddress]) =
+ let number = %(thisBlock.header.blockNumber.prefixHex)
+
+ var txTrace = newJObject()
+ for a in addresses:
+ let address = a.prefixHex
+ let trace = request("eth_getProof", %[%address, %[], number])
+ let account = %{
+ "codeHash": trace["codeHash"],
+ "storageRoot": trace["storageHash"],
+ "balance": trace["balance"],
+ "nonce": trace["nonce"],
+ "code": newJString("0x"),
+ "storage": newJObject()
+ }
+ txTrace[address] = account
+ postState.add txTrace
+
+proc hasTracerData(tx: JsonNode, blockNumber: Uint256): bool =
+ let number = %(blockNumber.prefixHex)
+
+ if tx["to"].kind == JNull:
+ let t = parseTransaction(tx)
+ let code = request("eth_getCode", %[%t.getRecipient.prefixHex, number])
+ return code.getStr.len > 2 # "0x"
+
+ let code = request("eth_getCode", %[tx["to"], number])
+ result = code.getStr.len > 2 # "0x"
+
+proc requestPostState(n: JsonNode, jsTracer: string, thisBlock: Block): JsonNode =
let txs = n["transactions"]
result = newJArray()
if txs.len == 0: return
let tracer = jsonTracer(jsTracer)
for tx in txs:
- if tx["to"].kind != JNull:
- result.add newJObject()
- continue
- let
- txHash = tx["hash"]
- txTrace = requestTrace(txHash, tracer)
- result.add txTrace
+ if hasTracerData(tx, thisBlock.header.blockNumber):
+ let
+ txHash = tx["hash"]
+ txTrace = requestTrace(txHash, tracer)
+ result.add txTrace
+ else:
+ let t = parseTransaction(tx)
+ var address: array[2, EthAddress]
+ address[0] = t.getRecipient
+ address[1] = t.getSender
+ requestBlockState(result, thisBlock, address)
proc padding(x: string): JsonNode =
let val = x.substr(2)
@@ -59,45 +92,37 @@ proc requestBlockState(postState: JsonNode, thisBlock: Block) =
storage.add %k
let trace = request("eth_getProof", %[%address, storage, number])
account["codeHash"] = trace["codeHash"]
- account["storageHash"] = trace["storageHash"]
+ account["storageRoot"] = trace["storageHash"]
+ account["nonce"] = trace["nonce"]
+ account["balance"] = trace["balance"]
for x in trace["storageProof"]:
account["storage"][x["key"].getStr] = padding(x["value"].getStr())
proc copyAccount(acc: JsonNode): JsonNode =
result = newJObject()
+ if acc.hasKey("name"):
+ result["name"] = newJString(acc["name"].getStr)
result["balance"] = newJString(acc["balance"].getStr)
- result["nonce"] = newJString(toHex(acc["nonce"].getInt))
+ result["nonce"] = newJString(acc["nonce"].getStr)
result["code"] = newJString(acc["code"].getStr)
var storage = newJObject()
for k, v in acc["storage"]:
storage[k] = newJString(v.getStr)
result["storage"] = storage
+ result["storageRoot"] = newJString(acc["storageRoot"].getStr)
+ result["codeHash"] = newJString(acc["codeHash"].getStr)
proc updateAccount(a, b: JsonNode) =
+ if b.hasKey("name"):
+ a["name"] = newJString(b["name"].getStr)
a["balance"] = newJString(b["balance"].getStr)
- a["nonce"] = newJString(toHex(b["nonce"].getInt))
+ a["nonce"] = newJString(b["nonce"].getStr)
a["code"] = newJString(b["code"].getStr)
var storage = a["storage"]
for k, v in b["storage"]:
storage[k] = newJString(v.getStr)
-
-proc requestBlockState(postState: JsonNode, thisBlock: Block, addresses: seq[EthAddress]) =
- let number = %(thisBlock.header.blockNumber.prefixHex)
-
- var txTrace = newJObject()
- for a in addresses:
- let address = a.prefixHex
- let trace = request("eth_getProof", %[%address, %[], number])
- let account = %{
- "codeHash": trace["codeHash"],
- "storageHash": trace["storageHash"],
- "balance": trace["balance"],
- "nonce": trace["nonce"],
- "code": newJString("0x"),
- "storage": newJObject()
- }
- txTrace[address] = account
- postState.add txTrace
+ a["storageRoot"] = newJString(b["storageRoot"].getStr)
+ a["codeHash"] = newJString(b["codeHash"].getStr)
proc processPostState(postState: JsonNode): JsonNode =
var accounts = newJObject()
@@ -111,8 +136,19 @@ proc processPostState(postState: JsonNode): JsonNode =
result = accounts
+proc removePostStateDup(nimbus: JsonNode) =
+ let postState = nimbus["stateDump"]["after"]
+ var accounts = newJObject()
+ for acc in postState:
+ let address = acc["address"].getStr
+ if accounts.hasKey(address):
+ updateAccount(accounts[address], acc)
+ else:
+ accounts[address] = copyAccount(acc)
+ nimbus["stateDump"]["after"] = accounts
+
proc requestPostState(thisBlock: Block): JsonNode =
- let postState = requestPostState(thisBlock.jsonData, postStateTracer)
+ let postState = requestPostState(thisBlock.jsonData, postStateTracer, thisBlock)
requestBlockState(postState, thisBlock)
var addresses = @[thisBlock.header.coinbase]
@@ -170,6 +206,7 @@ proc main() =
thisBlock = downloader.requestBlock(blockNumber, {DownloadReceipts, DownloadTxTrace})
accounts = requestPostState(thisBlock)
+ removePostStateDup(nimbus)
generatePremixData(nimbus, blockNumber, thisBlock, accounts)
generatePrestate(nimbus, blockNumber, thisBlock)
printDebugInstruction(blockNumber)