mirror of https://github.com/embarklabs/embark.git
Show TX reason when there is a failure (#1970)
* feat(@embark/transactions-logger): show reason of failure in tx log * feat(@embark/ui): show tx failure reason in cockpit contract logs
This commit is contained in:
parent
918a00c24c
commit
637e4f965d
|
@ -1,6 +1,6 @@
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {Row, Col, Table, FormGroup, Label, Input, Form} from 'reactstrap';
|
import {Row, Col, Table, FormGroup, Label, Input, Form, UncontrolledTooltip} from 'reactstrap';
|
||||||
import DebugButton from './DebugButton';
|
import DebugButton from './DebugButton';
|
||||||
|
|
||||||
import "./ContractLog.scss";
|
import "./ContractLog.scss";
|
||||||
|
@ -149,7 +149,13 @@ class ContractLog extends React.Component {
|
||||||
<td>{log.events.join(', ')}</td>
|
<td>{log.events.join(', ')}</td>
|
||||||
<td>{log.gasUsed}</td>
|
<td>{log.gasUsed}</td>
|
||||||
<td>{log.blockNumber}</td>
|
<td>{log.blockNumber}</td>
|
||||||
<td>{log.status}</td>
|
<td id={'tx-status-' + index}>
|
||||||
|
{log.status}
|
||||||
|
{log.reason && <sup>?</sup>}
|
||||||
|
{log.reason && <UncontrolledTooltip placement="bottom" target={'tx-status-' + index}>
|
||||||
|
Reason of the failure: {log.reason}
|
||||||
|
</UncontrolledTooltip>}
|
||||||
|
</td>
|
||||||
<td>{log.transactionHash}</td>
|
<td>{log.transactionHash}</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
|
|
|
@ -47,7 +47,8 @@
|
||||||
"embark-i18n": "^4.1.1",
|
"embark-i18n": "^4.1.1",
|
||||||
"embark-utils": "^4.1.1",
|
"embark-utils": "^4.1.1",
|
||||||
"ethereumjs-tx": "1.3.7",
|
"ethereumjs-tx": "1.3.7",
|
||||||
"ethereumjs-util": "6.0.0"
|
"ethereumjs-util": "6.0.0",
|
||||||
|
"web3": "1.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"embark-solo": "^4.1.1",
|
"embark-solo": "^4.1.1",
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
const async = require('async');
|
const async = require('async');
|
||||||
import {__} from 'embark-i18n';
|
import {__} from 'embark-i18n';
|
||||||
|
const Web3 = require('Web3');
|
||||||
|
|
||||||
const {blockchain: blockchainConstants} = require('embark-core/constants');
|
const {blockchain: blockchainConstants} = require('embark-core/constants');
|
||||||
import {dappPath, getAddressToContract, getTransactionParams, hexToNumber} from 'embark-utils';
|
import {dappPath, getAddressToContract, getTransactionParams, hexToNumber} from 'embark-utils';
|
||||||
|
@ -59,6 +60,16 @@ class TransactionLogger {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get web3() {
|
||||||
|
return (async () => {
|
||||||
|
if (!this._web3) {
|
||||||
|
const provider = await this.events.request2("blockchain:client:provider", "ethereum");
|
||||||
|
this._web3 = new Web3(provider);
|
||||||
|
}
|
||||||
|
return this._web3;
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
||||||
_getContractsList(callback) {
|
_getContractsList(callback) {
|
||||||
this.events.request("contracts:list", (err, contractsList) => {
|
this.events.request("contracts:list", (err, contractsList) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -86,7 +97,7 @@ class TransactionLogger {
|
||||||
this.events.on('blockchain:proxy:response', this._onLogRequest.bind(this));
|
this.events.on('blockchain:proxy:response', this._onLogRequest.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
_onLogRequest(args) {
|
async _onLogRequest(args) {
|
||||||
const method = args.reqData.method;
|
const method = args.reqData.method;
|
||||||
if (!this.contractsDeployed || !LISTENED_METHODS.includes(method)) {
|
if (!this.contractsDeployed || !LISTENED_METHODS.includes(method)) {
|
||||||
return;
|
return;
|
||||||
|
@ -161,20 +172,36 @@ class TransactionLogger {
|
||||||
}
|
}
|
||||||
|
|
||||||
let {transactionHash, blockNumber, gasUsed, status} = args.respData.result;
|
let {transactionHash, blockNumber, gasUsed, status} = args.respData.result;
|
||||||
|
let reason;
|
||||||
|
if (status !== '0x0' && status !== '0x1') {
|
||||||
|
status = !status ? '0x0' : '0x1';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status === '0x0') {
|
||||||
|
const web3 = await this.web3;
|
||||||
|
const tx = await web3.eth.getTransaction(transactionHash);
|
||||||
|
if (tx) {
|
||||||
|
const code = await web3.eth.call(tx, tx.blockNumber);
|
||||||
|
// Convert to Ascii and remove the useless bytes around the revert message
|
||||||
|
reason = web3.utils.hexToAscii('0x' + code.substring(138)).toString().replace(/[^\x20-\x7E]/g, '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gasUsed = hexToNumber(gasUsed);
|
gasUsed = hexToNumber(gasUsed);
|
||||||
blockNumber = hexToNumber(blockNumber);
|
blockNumber = hexToNumber(blockNumber);
|
||||||
const log = Object.assign({}, args, {name, functionName, paramString, gasUsed, blockNumber});
|
const log = Object.assign({}, args, {name, functionName, paramString, gasUsed, blockNumber, reason, status, transactionHash});
|
||||||
|
|
||||||
this.events.emit('contracts:log', log);
|
this.events.emit('contracts:log', log);
|
||||||
this.logger.info(`Blockchain>`.underline + ` ${name}.${functionName}(${paramString})`.bold + ` | ${transactionHash} | gas:${gasUsed} | blk:${blockNumber} | status:${status}`);
|
this.logger.info(`Blockchain>`.underline + ` ${name}.${functionName}(${paramString})`.bold + ` | ${transactionHash} | gas:${gasUsed} | blk:${blockNumber} | status:${status}${reason ? ` | reason: "${reason}"` : ''}`);
|
||||||
this.events.emit('blockchain:tx', {
|
this.events.emit('blockchain:tx', {
|
||||||
name: name,
|
name,
|
||||||
functionName: functionName,
|
functionName,
|
||||||
paramString: paramString,
|
paramString,
|
||||||
transactionHash: transactionHash,
|
transactionHash,
|
||||||
gasUsed: gasUsed,
|
gasUsed,
|
||||||
blockNumber: blockNumber,
|
blockNumber,
|
||||||
status: status
|
status,
|
||||||
|
reason
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,8 +211,7 @@ class TransactionLogger {
|
||||||
'ws',
|
'ws',
|
||||||
apiRoute,
|
apiRoute,
|
||||||
(ws, _req) => {
|
(ws, _req) => {
|
||||||
// FIXME this will be broken probably in the cokcpit because we don't send the same data as before
|
this.events.on('contracts:log', (log) => {
|
||||||
this.events.on('contracts:log', function(log) {
|
|
||||||
ws.send(JSON.stringify(log), () => {
|
ws.send(JSON.stringify(log), () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue