Skip to content

Commit

Permalink
Display and decoding of tx logs, changed to abi-decoder for ABI decod…
Browse files Browse the repository at this point in the history
…ing tasks, fixes #29 and #32
  • Loading branch information
peterbitfly committed Nov 23, 2017
1 parent e2bdf4c commit 2ef6974
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 94 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"start": "node ./bin/www"
},
"dependencies": {
"abi-decoder": "^1.0.9",
"async": "^2.1.5",
"bignumber.js": "^4.0.0",
"body-parser": "~1.16.0",
Expand Down
16 changes: 10 additions & 6 deletions routes/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ router.get('/:account', function(req, res, next) {
}, function(lastBlock, callback) {
data.lastBlock = lastBlock.number;
//limits the from block to -1000 blocks ago if block count is greater than 1000
if(data.lastBlock > 0x3E8){
data.fromBlock = data.lastBlock - 0x3e8;
}else{
data.fromBlock = 0x00;
}
if (data.lastBlock > 0x3E8) {
data.fromBlock = data.lastBlock - 0x3e8;
} else {
data.fromBlock = 0x00;
}
web3.eth.getBalance(req.params.account, function(err, balance) {
callback(err, balance);
});
Expand All @@ -49,10 +49,13 @@ router.get('/:account', function(req, res, next) {
if (source) {
data.source = JSON.parse(source);

data.contractState = [];
if (!data.abi) {
return callback();
}
var abi = JSON.parse(data.source.abi);
var contract = web3.eth.contract(abi).at(req.params.account);

data.contractState = [];

async.eachSeries(abi, function(item, eachCallback) {
if (item.type === "function" && item.inputs.length === 0 && item.constant) {
Expand Down Expand Up @@ -128,6 +131,7 @@ router.get('/:account', function(req, res, next) {
}

data.blocks = data.blocks.reverse().splice(0, 100);

res.render('account', { account: data });
});

Expand Down
3 changes: 3 additions & 0 deletions routes/contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ router.post('/verify', function(req, res, next) {
async.waterfall([
function(callback) {
web3.trace.filter({ "fromBlock": "0x00", "toAddress": [ contractAddress ] }, function(err, traces) {
console.log("Received traces");
callback(err, traces);
});
}, function(traces, callback) {
Expand All @@ -55,6 +56,8 @@ router.post('/verify', function(req, res, next) {
}
});


console.log("Processed traces");
if (!creationBytecode) {
callback("Contract creation transaction not found");
} else {
Expand Down
59 changes: 19 additions & 40 deletions routes/tx.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ var router = express.Router();
var async = require('async');
var Web3 = require('web3');
var abi = require('ethereumjs-abi');

var abiDecoder = require('abi-decoder');

router.get('/pending', function(req, res, next) {

Expand Down Expand Up @@ -75,54 +75,34 @@ router.get('/:tx', function(req, res, next) {
return callback({ message: "Transaction hash not found" }, null);
}

web3.trace.transaction(result.hash, function(err, traces) {
callback(err, result, traces);
web3.eth.getTransactionReceipt(result.hash, function(err, receipt) {
callback(err, result, receipt);
});
}, function(tx, receipt, callback) {
web3.trace.transaction(tx.hash, function(err, traces) {
callback(err, tx, receipt, traces);
});
}, function(tx, traces, callback) {
}, function(tx, receipt, traces, callback) {
db.get(tx.to, function(err, value) {
callback(null, tx, traces, value);
callback(null, tx, receipt, traces, value);
});
}
], function(err, tx, traces, source) {
], function(err, tx, receipt, traces, source) {
if (err) {
return next(err);
}

// Try to match the tx to a solidity function call if the contract source is available
if (source) {
tx.source = JSON.parse(source);
var jsonAbi = JSON.parse(tx.source.abi);

var id = tx.input;
if (id.length > 10) {
id = id.substr(0, 10);
}

jsonAbi.forEach(function(item) {
if (item.type === "function" && !item.constant) {

var functionName = item.name;
var functionParams = [];
var functionParamsFull = [];
item.inputs.forEach(function(input) {
functionParams.push(input.type);
});

var signature = "0x" + abi.methodID(functionName, functionParams).toString('hex')

if (signature === id) {
var pl = tx.input.replace("0x", "");
pl = pl.substr(8, pl.length - 8);
var decoded = abi.rawDecode(functionParams, pl);

for(var i = 0; i < functionParams.length; i++) {
item.inputs[i].result = decoded[i];
}

tx.callInfo = item;
}
}
});
try {
var jsonAbi = JSON.parse(tx.source.abi);
abiDecoder.addABI(jsonAbi);
tx.logs = abiDecoder.decodeLogs(receipt.logs);
tx.callInfo = abiDecoder.decodeMethod(tx.input);
} catch (e) {
console.log("Error parsing ABI:", tx.source.abi, e);
}
}
tx.traces = [];
tx.failed = false;
Expand All @@ -139,8 +119,7 @@ router.get('/:tx', function(req, res, next) {
}
});
}
// console.log(tx.traces);

// console.log(tx.traces);
res.render('tx', { tx: tx });
});

Expand Down
89 changes: 51 additions & 38 deletions views/account.pug
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ block content
a(href='#contractState', aria-controls='source', role='tab', data-toggle='tab') Contract State
.tab-content
#transactions.tab-pane.active(role='tabpanel')
h3 Last Transactions
h3 Recent Activity
table.table
thead
tr
Expand All @@ -42,48 +42,61 @@ block content
tbody
for block in account.blocks
for trace in block
tr
td
a(href="/tx/" + trace.transactionHash) #{trace.transactionHash.substr(0, 10)}...
td
a(href="/block/" + trace.blockNumber) #{trace.blockNumber}
td.capitalize
if trace.error
span(style="color: red", data-toggle="tooltip", data-placement="left", title=trace.error).glyphicon.glyphicon-warning-sign
| #{trace.type}
if trace.type === "call"
if trace.type === "reward" && trace.action.author === account.address
tr
td
if trace.action.from === account.address
span.glyphicon.glyphicon-export(style="color: red;")
else
span.glyphicon.glyphicon-import(style="color: green;")
a(href="/block/" + trace.blockNumber) #{trace.blockHash.substr(0, 10)}...
td
a(href="/account/" + trace.action.from) #{nameformatter.format(trace.action.from)}
td
a(href="/account/" + trace.action.to) #{nameformatter.format(trace.action.to)}
td #{ethformatter(trace.action.value)}
else if trace.type === "create"
td
if trace.action.from === account.address
span.glyphicon.glyphicon-export(style="color: red;")
else
span.glyphicon.glyphicon-import(style="color: green;")
td
a(href="/account/" + trace.action.from) #{nameformatter.format(trace.action.from)}
a(href="/block/" + trace.blockNumber) #{trace.blockNumber}
td Mining Reward
td
a(href="/account/" + trace.result.address) #{nameformatter.format(trace.result.address)}
td New Coins
td
a(href="/account/" + trace.action.author) #{nameformatter.format(trace.action.author)}
td #{ethformatter(trace.action.value)}
else if trace.type === "suicide"
td
if trace.action.address === account.address
span.glyphicon.glyphicon-export(style="color: red;")
else
span.glyphicon.glyphicon-import(style="color: green;")
td
a(href="/account/" + trace.action.address) #{nameformatter.format(trace.action.address)}
else if trace.type !== "reward"
tr
td
a(href="/tx/" + trace.transactionHash) #{trace.transactionHash.substr(0, 10)}...
td
a(href="/account/" + trace.action.refundAddress) #{nameformatter.format(trace.action.refundAddress)}
td #{ethformatter(trace.action.balance)}
a(href="/block/" + trace.blockNumber) #{trace.blockNumber}
td.capitalize
if trace.error
span(style="color: red", data-toggle="tooltip", data-placement="left", title=trace.error).glyphicon.glyphicon-warning-sign
| #{trace.type}
if trace.type === "call"
td
if trace.action.from === account.address
span.glyphicon.glyphicon-export(style="color: red;")
else
span.glyphicon.glyphicon-import(style="color: green;")
td
a(href="/account/" + trace.action.from) #{nameformatter.format(trace.action.from)}
td
a(href="/account/" + trace.action.to) #{nameformatter.format(trace.action.to)}
td #{ethformatter(trace.action.value)}
else if trace.type === "create"
td
if trace.action.from === account.address
span.glyphicon.glyphicon-export(style="color: red;")
else
span.glyphicon.glyphicon-import(style="color: green;")
td
a(href="/account/" + trace.action.from) #{nameformatter.format(trace.action.from)}
td
a(href="/account/" + trace.result.address) #{nameformatter.format(trace.result.address)}
td #{ethformatter(trace.action.value)}
else if trace.type === "suicide"
td
if trace.action.address === account.address
span.glyphicon.glyphicon-export(style="color: red;")
else
span.glyphicon.glyphicon-import(style="color: green;")
td
a(href="/account/" + trace.action.address) #{nameformatter.format(trace.action.address)}
td
a(href="/account/" + trace.action.refundAddress) #{nameformatter.format(trace.action.refundAddress)}
td #{ethformatter(trace.action.balance)}

if account.isContract
#code.tab-pane(role='tabpanel')
Expand Down
10 changes: 6 additions & 4 deletions views/block.pug
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,12 @@ block content
tr
td Uncles:
td
each uncle, index in block.uncles
p
a(href="uncle/" + block.hash + "/" + index) #{index + " - " + uncle}

if block.uncles && block.uncles.length > 0
each uncle, index in block.uncles
p
a(href="uncle/" + block.hash + "/" + index) #{index + " - " + uncle}
else
| 0
h4 Transactions
if block.transactions.length === 0
p Block does not contain any transactions.
Expand Down
40 changes: 34 additions & 6 deletions views/tx.pug
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,45 @@ block content
th Type
th Value
tbody
for pa in tx.callInfo.inputs
for pa in tx.callInfo.params
tr
td #{pa.name}
td #{pa.type}
if pa.type === "bytes"
if pa.type === "bytes" && pa.value
td
pre 0x#{pa.result.toString("hex")}
else if pa.type === "uint256"
td.parameter-cell #{pa.result.toString(10)}
pre 0x#{pa.value.toString("hex")}
else if pa.type === "uint256" && pa.value
td.parameter-cell #{pa.value.toString(10)}
else
td.parameter-cell #{JSON.stringify(pa.result, null, 2)}
td.parameter-cell #{JSON.stringify(pa.value, null, 2)}
if tx.logs
tr
td Events:
td
for log in tx.logs
table.table
thead
tr
th Name
th Events
th Address
tbody
tr
td #{log.name}
td
table.table
thead
tr
th Name
th Type
th Value
tbody
for event in log.events
tr
td #{event.name}
td #{event.type}
td #{event.value}
td #{log.address}
tr
td Data:
td
Expand Down

0 comments on commit 2ef6974

Please sign in to comment.