add contract logs
This commit is contained in:
parent
386deadd10
commit
daed2fdbd4
|
@ -76,6 +76,13 @@ export const processLogs = {
|
||||||
failure: (error) => action(PROCESS_LOGS[FAILURE], {error})
|
failure: (error) => action(PROCESS_LOGS[FAILURE], {error})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const CONTRACT_LOGS = createRequestTypes('CONTRACT_LOGS');
|
||||||
|
export const contractLogs = {
|
||||||
|
request: () => action(CONTRACT_LOGS[REQUEST]),
|
||||||
|
success: (contractLogs) => action(CONTRACT_LOGS[SUCCESS], {contractLogs}),
|
||||||
|
failure: (error) => action(CONTRACT_LOGS[FAILURE], {error})
|
||||||
|
};
|
||||||
|
|
||||||
export const CONTRACTS = createRequestTypes('CONTRACTS');
|
export const CONTRACTS = createRequestTypes('CONTRACTS');
|
||||||
export const contracts = {
|
export const contracts = {
|
||||||
request: () => action(CONTRACTS[REQUEST]),
|
request: () => action(CONTRACTS[REQUEST]),
|
||||||
|
|
|
@ -56,6 +56,10 @@ export function fetchProcessLogs(payload) {
|
||||||
return get(`/process-logs/${payload.processName}`);
|
return get(`/process-logs/${payload.processName}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function fetchContractLogs() {
|
||||||
|
return get(`/contracts/logs`);
|
||||||
|
}
|
||||||
|
|
||||||
export function fetchContracts() {
|
export function fetchContracts() {
|
||||||
return get('/contracts');
|
return get('/contracts');
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {
|
||||||
} from "tabler-react";
|
} from "tabler-react";
|
||||||
|
|
||||||
import ContractContainer from '../containers/ContractContainer';
|
import ContractContainer from '../containers/ContractContainer';
|
||||||
|
import ContractLoggerContainer from '../containers/ContractLoggerContainer';
|
||||||
import ContractProfileContainer from '../containers/ContractProfileContainer';
|
import ContractProfileContainer from '../containers/ContractProfileContainer';
|
||||||
|
|
||||||
const ContractLayout = (props) => (
|
const ContractLayout = (props) => (
|
||||||
|
@ -48,11 +49,20 @@ const ContractLayout = (props) => (
|
||||||
>
|
>
|
||||||
Profile
|
Profile
|
||||||
</List.GroupItem>
|
</List.GroupItem>
|
||||||
|
<List.GroupItem
|
||||||
|
className="d-flex align-items-center"
|
||||||
|
to={`/embark/contracts/${props.match.params.contractName}/logger`}
|
||||||
|
icon="chevrons-right"
|
||||||
|
RootComponent={withRouter(NavLink)}
|
||||||
|
>
|
||||||
|
Logger
|
||||||
|
</List.GroupItem>
|
||||||
</List.Group>
|
</List.Group>
|
||||||
</div>
|
</div>
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
<Grid.Col md={9}>
|
<Grid.Col md={9}>
|
||||||
<Switch>
|
<Switch>
|
||||||
|
<Route exact path="/embark/contracts/:contractName/logger" component={ContractLoggerContainer} />
|
||||||
<Route exact path="/embark/contracts/:contractName/profiler" component={ContractProfileContainer} />
|
<Route exact path="/embark/contracts/:contractName/profiler" component={ContractProfileContainer} />
|
||||||
<ContractContainer />
|
<ContractContainer />
|
||||||
</Switch>
|
</Switch>
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
Page,
|
||||||
|
Grid, Table
|
||||||
|
} from "tabler-react";
|
||||||
|
|
||||||
|
const ContractLogger = ({contractName, contractLogs}) => (
|
||||||
|
<Page.Content title={contractName + ' Logger'}>
|
||||||
|
<Grid.Row>
|
||||||
|
<Grid.Col>
|
||||||
|
<Table
|
||||||
|
responsive
|
||||||
|
className="card-table table-vcenter text-nowrap"
|
||||||
|
headerItems={[
|
||||||
|
{content: "Function name"},
|
||||||
|
{content: "Params"},
|
||||||
|
{content: "Transaction hash"},
|
||||||
|
{content: "Gas Used"},
|
||||||
|
{content: "Block number"},
|
||||||
|
{content: "Status"}
|
||||||
|
]}
|
||||||
|
bodyItems={
|
||||||
|
contractLogs.map((log) => {
|
||||||
|
return ([
|
||||||
|
{content: log.functionName},
|
||||||
|
{content: log.paramString},
|
||||||
|
{content: log.transactionHash},
|
||||||
|
{content: log.gasUsed},
|
||||||
|
{content: log.blockNumber},
|
||||||
|
{content: log.status}
|
||||||
|
]);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Grid.Col>
|
||||||
|
</Grid.Row>
|
||||||
|
</Page.Content>
|
||||||
|
);
|
||||||
|
|
||||||
|
ContractLogger.propTypes = {
|
||||||
|
contractName: PropTypes.string.isRequired,
|
||||||
|
contractLogs: PropTypes.array.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ContractLogger;
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
import React, {Component} from 'react';
|
||||||
|
import {connect} from 'react-redux';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import {withRouter} from 'react-router-dom';
|
||||||
|
import {contractLogs as contractLogsAction} from '../actions';
|
||||||
|
|
||||||
|
import ContractLogger from '../components/ContractLogger';
|
||||||
|
// import DataWrapper from "../components/DataWrapper";
|
||||||
|
import {getContractLogsByContract} from "../reducers/selectors";
|
||||||
|
|
||||||
|
class ContractProfileContainer extends Component {
|
||||||
|
componentDidMount() {
|
||||||
|
if (this.props.contractLogs.length === 0) {
|
||||||
|
this.props.fetchContractLogs(this.props.match.params.contractName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<ContractLogger contractLogs={this.props.contractLogs} contractName={this.props.match.params.contractName}/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapStateToProps(state, props) {
|
||||||
|
return {
|
||||||
|
contractLogs: getContractLogsByContract(state, props.match.params.contractName)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ContractProfileContainer.propTypes = {
|
||||||
|
contractLogs: PropTypes.array,
|
||||||
|
fetchContractLogs: PropTypes.func,
|
||||||
|
match: PropTypes.object
|
||||||
|
};
|
||||||
|
|
||||||
|
export default withRouter(connect(
|
||||||
|
mapStateToProps,
|
||||||
|
{
|
||||||
|
fetchContractLogs: contractLogsAction.request
|
||||||
|
}
|
||||||
|
)(ContractProfileContainer));
|
|
@ -11,6 +11,7 @@ const entitiesDefaultState = {
|
||||||
processLogs: [],
|
processLogs: [],
|
||||||
contracts: [],
|
contracts: [],
|
||||||
contractProfiles: [],
|
contractProfiles: [],
|
||||||
|
contractLogs: [],
|
||||||
commands: [],
|
commands: [],
|
||||||
messages: [],
|
messages: [],
|
||||||
messageChannels: [],
|
messageChannels: [],
|
||||||
|
@ -27,6 +28,9 @@ const sorter = {
|
||||||
processLogs: function(a, b) {
|
processLogs: function(a, b) {
|
||||||
return a.timestamp - b.timestamp;
|
return a.timestamp - b.timestamp;
|
||||||
},
|
},
|
||||||
|
contractLogs: function(a, b) {
|
||||||
|
return a.timestamp - b.timestamp;
|
||||||
|
},
|
||||||
messages: function(a, b) {
|
messages: function(a, b) {
|
||||||
return a.time - b.time;
|
return a.time - b.time;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,11 @@ export function getProcessLogsByProcess(state, processName) {
|
||||||
return state.entities.processLogs.filter((processLog => processLog.name === processName));
|
return state.entities.processLogs.filter((processLog => processLog.name === processName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getContractLogsByContract(state, contractName) {
|
||||||
|
return state.entities.contractLogs;
|
||||||
|
// return state.entities.processLogs.filter((processLog => processLog.name === processName));
|
||||||
|
}
|
||||||
|
|
||||||
export function getContracts(state) {
|
export function getContracts(state) {
|
||||||
return state.entities.contracts;
|
return state.entities.contracts;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import {eventChannel} from 'redux-saga';
|
||||||
import {all, call, fork, put, takeEvery, take} from 'redux-saga/effects';
|
import {all, call, fork, put, takeEvery, take} from 'redux-saga/effects';
|
||||||
|
|
||||||
const {account, accounts, block, blocks, transaction, transactions, processes, commands, processLogs,
|
const {account, accounts, block, blocks, transaction, transactions, processes, commands, processLogs,
|
||||||
contracts, contract, contractProfile, messageSend, messageVersion, messageListen} = actions;
|
contracts, contract, contractProfile, messageSend, messageVersion, messageListen, contractLogs} = actions;
|
||||||
|
|
||||||
function *doRequest(entity, apiFn, payload) {
|
function *doRequest(entity, apiFn, payload) {
|
||||||
const {response, error} = yield call(apiFn, payload);
|
const {response, error} = yield call(apiFn, payload);
|
||||||
|
@ -24,6 +24,7 @@ export const fetchTransactions = doRequest.bind(null, transactions, api.fetchTra
|
||||||
export const fetchProcesses = doRequest.bind(null, processes, api.fetchProcesses);
|
export const fetchProcesses = doRequest.bind(null, processes, api.fetchProcesses);
|
||||||
export const postCommand = doRequest.bind(null, commands, api.postCommand);
|
export const postCommand = doRequest.bind(null, commands, api.postCommand);
|
||||||
export const fetchProcessLogs = doRequest.bind(null, processLogs, api.fetchProcessLogs);
|
export const fetchProcessLogs = doRequest.bind(null, processLogs, api.fetchProcessLogs);
|
||||||
|
export const fetchContractLogs = doRequest.bind(null, contractLogs, api.fetchContractLogs);
|
||||||
export const fetchContracts = doRequest.bind(null, contracts, api.fetchContracts);
|
export const fetchContracts = doRequest.bind(null, contracts, api.fetchContracts);
|
||||||
export const fetchContract = doRequest.bind(null, contract, api.fetchContract);
|
export const fetchContract = doRequest.bind(null, contract, api.fetchContract);
|
||||||
export const fetchContractProfile = doRequest.bind(null, contractProfile, api.fetchContractProfile);
|
export const fetchContractProfile = doRequest.bind(null, contractProfile, api.fetchContractProfile);
|
||||||
|
@ -64,6 +65,10 @@ export function *watchFetchProcessLogs() {
|
||||||
yield takeEvery(actions.PROCESS_LOGS[actions.REQUEST], fetchProcessLogs);
|
yield takeEvery(actions.PROCESS_LOGS[actions.REQUEST], fetchProcessLogs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function *watchFetchContractLogs() {
|
||||||
|
yield takeEvery(actions.CONTRACT_LOGS[actions.REQUEST], fetchContractLogs);
|
||||||
|
}
|
||||||
|
|
||||||
export function *watchFetchContract() {
|
export function *watchFetchContract() {
|
||||||
yield takeEvery(actions.CONTRACT[actions.REQUEST], fetchContract);
|
yield takeEvery(actions.CONTRACT[actions.REQUEST], fetchContract);
|
||||||
}
|
}
|
||||||
|
@ -146,6 +151,7 @@ export default function *root() {
|
||||||
fork(watchFetchAccount),
|
fork(watchFetchAccount),
|
||||||
fork(watchFetchProcesses),
|
fork(watchFetchProcesses),
|
||||||
fork(watchFetchProcessLogs),
|
fork(watchFetchProcessLogs),
|
||||||
|
fork(watchFetchContractLogs),
|
||||||
fork(watchListenToProcessLogs),
|
fork(watchListenToProcessLogs),
|
||||||
fork(watchFetchBlock),
|
fork(watchFetchBlock),
|
||||||
fork(watchFetchTransactions),
|
fork(watchFetchTransactions),
|
||||||
|
|
|
@ -8,44 +8,44 @@ let receipts = {};
|
||||||
|
|
||||||
const {canonicalHost, defaultHost} = require('../utils/host');
|
const {canonicalHost, defaultHost} = require('../utils/host');
|
||||||
|
|
||||||
const parseRequest = function(reqBody){
|
const parseRequest = function(reqBody) {
|
||||||
let jsonO;
|
let jsonO;
|
||||||
try {
|
try {
|
||||||
jsonO = JSON.parse(reqBody);
|
jsonO = JSON.parse(reqBody);
|
||||||
} catch(e){
|
} catch (e) {
|
||||||
return; // Request is not a json. Do nothing
|
return; // Request is not a json. Do nothing
|
||||||
}
|
}
|
||||||
if(jsonO.method === "eth_sendTransaction"){
|
if (jsonO.method === "eth_sendTransaction") {
|
||||||
commList[jsonO.id] = {
|
commList[jsonO.id] = {
|
||||||
type: 'contract-log',
|
type: 'contract-log',
|
||||||
address: jsonO.params[0].to,
|
address: jsonO.params[0].to,
|
||||||
data: jsonO.params[0].data
|
data: jsonO.params[0].data
|
||||||
};
|
};
|
||||||
} else if(jsonO.method === "eth_getTransactionReceipt"){
|
} else if (jsonO.method === "eth_getTransactionReceipt") {
|
||||||
if(transactions[jsonO.params[0]]){
|
if (transactions[jsonO.params[0]]) {
|
||||||
transactions[jsonO.params[0]].receiptId = jsonO.id;
|
transactions[jsonO.params[0]].receiptId = jsonO.id;
|
||||||
receipts[jsonO.id] = transactions[jsonO.params[0]].commListId;
|
receipts[jsonO.id] = transactions[jsonO.params[0]].commListId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const parseResponse = function(ipc, resBody){
|
const parseResponse = function(ipc, resBody) {
|
||||||
let jsonO;
|
let jsonO;
|
||||||
try {
|
try {
|
||||||
jsonO = JSON.parse(resBody);
|
jsonO = JSON.parse(resBody);
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
return; // Response is not a json. Do nothing
|
return; // Response is not a json. Do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
if(commList[jsonO.id]){
|
if (commList[jsonO.id]) {
|
||||||
commList[jsonO.id].transactionHash = jsonO.result;
|
commList[jsonO.id].transactionHash = jsonO.result;
|
||||||
transactions[jsonO.result] = {commListId: jsonO.id};
|
transactions[jsonO.result] = {commListId: jsonO.id};
|
||||||
} else if(receipts[jsonO.id] && jsonO.result && jsonO.result.blockNumber){
|
} else if (receipts[jsonO.id] && jsonO.result && jsonO.result.blockNumber) {
|
||||||
commList[receipts[jsonO.id]].blockNumber = jsonO.result.blockNumber;
|
commList[receipts[jsonO.id]].blockNumber = jsonO.result.blockNumber;
|
||||||
commList[receipts[jsonO.id]].gasUsed = jsonO.result.gasUsed;
|
commList[receipts[jsonO.id]].gasUsed = jsonO.result.gasUsed;
|
||||||
commList[receipts[jsonO.id]].status = jsonO.result.status;
|
commList[receipts[jsonO.id]].status = jsonO.result.status;
|
||||||
|
|
||||||
if(ipc.connected && !ipc.connecting){
|
if (ipc.connected && !ipc.connecting) {
|
||||||
ipc.request('log', commList[receipts[jsonO.id]]);
|
ipc.request('log', commList[receipts[jsonO.id]]);
|
||||||
} else {
|
} else {
|
||||||
ipc.connecting = true;
|
ipc.connecting = true;
|
||||||
|
@ -60,7 +60,7 @@ const parseResponse = function(ipc, resBody){
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.serve = function(ipc, host, port, ws){
|
exports.serve = function(ipc, host, port, ws) {
|
||||||
let proxy = httpProxy.createProxyServer({
|
let proxy = httpProxy.createProxyServer({
|
||||||
target: {
|
target: {
|
||||||
host: canonicalHost(host),
|
host: canonicalHost(host),
|
||||||
|
@ -69,16 +69,16 @@ exports.serve = function(ipc, host, port, ws){
|
||||||
ws: ws
|
ws: ws
|
||||||
});
|
});
|
||||||
|
|
||||||
proxy.on('error', function (e) {
|
proxy.on('error', function(e) {
|
||||||
console.error(__("Error forwarding requests to blockchain/simulator"), e.message);
|
console.error(__("Error forwarding requests to blockchain/simulator"), e.message);
|
||||||
});
|
});
|
||||||
|
|
||||||
proxy.on('proxyRes', (proxyRes) => {
|
proxy.on('proxyRes', (proxyRes) => {
|
||||||
let resBody = [];
|
let resBody = [];
|
||||||
proxyRes.on('data', (b) => resBody.push(b));
|
proxyRes.on('data', (b) => resBody.push(b));
|
||||||
proxyRes.on('end', function () {
|
proxyRes.on('end', function() {
|
||||||
resBody = Buffer.concat(resBody).toString();
|
resBody = Buffer.concat(resBody).toString();
|
||||||
if(resBody){
|
if (resBody) {
|
||||||
parseResponse(ipc, resBody);
|
parseResponse(ipc, resBody);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -86,23 +86,25 @@ exports.serve = function(ipc, host, port, ws){
|
||||||
|
|
||||||
let server = http.createServer((req, res) => {
|
let server = http.createServer((req, res) => {
|
||||||
let reqBody = [];
|
let reqBody = [];
|
||||||
req.on('data', (b) => { reqBody.push(b); })
|
req.on('data', (b) => {
|
||||||
|
reqBody.push(b);
|
||||||
|
})
|
||||||
.on('end', () => {
|
.on('end', () => {
|
||||||
reqBody = Buffer.concat(reqBody).toString();
|
reqBody = Buffer.concat(reqBody).toString();
|
||||||
if(reqBody){
|
if (reqBody) {
|
||||||
parseRequest(reqBody);
|
parseRequest(reqBody);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if(!ws){
|
if (!ws) {
|
||||||
proxy.web(req, res);
|
proxy.web(req, res);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if(ws){
|
if (ws) {
|
||||||
const WsParser = require('simples/lib/parsers/ws'); // npm install simples
|
const WsParser = require('simples/lib/parsers/ws'); // npm install simples
|
||||||
|
|
||||||
server.on('upgrade', function (req, socket, head) {
|
server.on('upgrade', function(req, socket, head) {
|
||||||
proxy.ws(req, socket, head);
|
proxy.ws(req, socket, head);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -115,7 +117,7 @@ exports.serve = function(ipc, host, port, ws){
|
||||||
proxy.on('proxyReqWs', (proxyReq, req, socket) => {
|
proxy.on('proxyReqWs', (proxyReq, req, socket) => {
|
||||||
var parser = new WsParser(0, false);
|
var parser = new WsParser(0, false);
|
||||||
socket.pipe(parser);
|
socket.pipe(parser);
|
||||||
parser.on('frame', function (frame) {
|
parser.on('frame', function(frame) {
|
||||||
parseRequest(frame.data);
|
parseRequest(frame.data);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -2,13 +2,16 @@ const utils = require('../../utils/utils.js');
|
||||||
|
|
||||||
class ConsoleListener {
|
class ConsoleListener {
|
||||||
constructor(embark, options) {
|
constructor(embark, options) {
|
||||||
|
this.embark = embark;
|
||||||
this.logger = embark.logger;
|
this.logger = embark.logger;
|
||||||
this.ipc = options.ipc;
|
this.ipc = options.ipc;
|
||||||
this.events = embark.events;
|
this.events = embark.events;
|
||||||
this.addressToContract = [];
|
this.addressToContract = [];
|
||||||
|
this.logs = [];
|
||||||
this.contractsConfig = embark.config.contractsConfig;
|
this.contractsConfig = embark.config.contractsConfig;
|
||||||
this.contractsDeployed = false;
|
this.contractsDeployed = false;
|
||||||
this._listenForLogRequests();
|
this._listenForLogRequests();
|
||||||
|
this._registerAPI();
|
||||||
|
|
||||||
this.events.on("contractsDeployed", () => {
|
this.events.on("contractsDeployed", () => {
|
||||||
this.contractsDeployed = true;
|
this.contractsDeployed = true;
|
||||||
|
@ -81,12 +84,25 @@ class ConsoleListener {
|
||||||
gasUsed = utils.hexToNumber(gasUsed);
|
gasUsed = utils.hexToNumber(gasUsed);
|
||||||
blockNumber = utils.hexToNumber(blockNumber);
|
blockNumber = utils.hexToNumber(blockNumber);
|
||||||
|
|
||||||
|
this.logs.push(Object.assign({}, request, {name, functionName, paramString}));
|
||||||
|
|
||||||
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}`);
|
||||||
} else {
|
} else {
|
||||||
this.logger.info(JSON.stringify(request));
|
this.logger.info(JSON.stringify(request));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_registerAPI() {
|
||||||
|
const apiRoute = '/embark-api/contracts/logs';
|
||||||
|
this.embark.registerAPICall(
|
||||||
|
'get',
|
||||||
|
apiRoute,
|
||||||
|
(req, res) => {
|
||||||
|
res.send(JSON.stringify(this.logs));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = ConsoleListener;
|
module.exports = ConsoleListener;
|
||||||
|
|
Loading…
Reference in New Issue