feature: decode raw transactions in tx decoder

This commit is contained in:
Andre Medeiros 2019-03-15 09:14:31 -04:00 committed by Iuri Matias
parent 5e4a80edec
commit b15467f64a
6 changed files with 77 additions and 27 deletions

View File

@ -103,6 +103,13 @@ export const transaction = {
failure: (error) => action(TRANSACTION[FAILURE], {error})
};
export const DECODED_TRANSACTION = createRequestTypes('DECODED_TRANSACTION');
export const decodedTransaction = {
request: (hash) => action(DECODED_TRANSACTION[REQUEST], {hash}),
success: (transaction) => action(DECODED_TRANSACTION[SUCCESS], {transaction}),
failure: (error) => action(DECODED_TRANSACTION[FAILURE], {error})
};
export const PROCESSES = createRequestTypes('PROCESSES');
export const processes = {
request: () => action(PROCESSES[REQUEST]),

View File

@ -6,8 +6,8 @@ import {withRouter} from 'react-router-dom';
import TransactionDecoder from '../components/TransactionDecoder';
import PageHead from '../components/PageHead';
import { Row, Col } from 'reactstrap';
import { transaction as transactionAction } from '../actions';
import {getTransaction} from "../reducers/selectors";
import { decodedTransaction as decodedTransactionAction } from '../actions';
import {getDecodedTransaction} from "../reducers/selectors";
const getQueryParams = (props) => {
return qs.parse(props.location.search, {
@ -19,7 +19,7 @@ class TransactionDecoderContainer extends Component {
componentDidMount() {
const { hash } = getQueryParams(this.props);
if (hash) {
this.props.fetchTransaction(hash);
this.props.fetchDecodedTransaction(hash);
}
}
@ -28,7 +28,7 @@ class TransactionDecoderContainer extends Component {
const prevHash = getQueryParams(prevProps).hash;
if (hash && hash !== prevHash) {
this.props.fetchTransaction(hash);
this.props.fetchDecodedTransaction(hash);
}
}
@ -48,13 +48,13 @@ class TransactionDecoderContainer extends Component {
}
TransactionDecoderContainer.propTypes = {
fetchTransaction: PropTypes.func,
fetchDecodedTransaction: PropTypes.func,
transaction: PropTypes.object
};
function mapStateToProps(state, props) {
function mapStateToProps(state) {
return {
transaction: getTransaction(state, getQueryParams(props).hash),
transaction: getDecodedTransaction(state),
error: state.errorMessage,
loading: state.loading
};
@ -62,6 +62,6 @@ function mapStateToProps(state, props) {
export default withRouter(connect(
mapStateToProps,
{
fetchTransaction: transactionAction.request
fetchDecodedTransaction: decodedTransactionAction.request
}
)(TransactionDecoderContainer));

View File

@ -3,7 +3,7 @@ import {REQUEST, SUCCESS, FAILURE, CONTRACT_COMPILE, FILES, LOGOUT, AUTHENTICATE
FETCH_CREDENTIALS, UPDATE_BASE_ETHER, CHANGE_THEME, FETCH_THEME, EXPLORER_SEARCH, DEBUGGER_INFO,
SIGN_MESSAGE, VERIFY_MESSAGE, TOGGLE_BREAKPOINT, UPDATE_PREVIEW_URL,
UPDATE_DEPLOYMENT_PIPELINE, WEB3_CONNECT, WEB3_DEPLOY, WEB3_ESTIMAGE_GAS, FETCH_EDITOR_TABS,
SAVE_FILE, SAVE_FOLDER, REMOVE_FILE} from "../actions";
SAVE_FILE, SAVE_FOLDER, REMOVE_FILE, DECODED_TRANSACTION} from "../actions";
import {EMBARK_PROCESS_NAME, DARK_THEME, DEPLOYMENT_PIPELINES, DEFAULT_HOST, ELEMENTS_LIMIT} from '../constants';
const BN_FACTOR = 10000;
@ -376,6 +376,16 @@ function editorTabs(state = [], action) {
return state;
}
function decodedTransaction(state = {}, action) {
if (action.type === DECODED_TRANSACTION[SUCCESS] && action.transaction) {
return action.transaction;
}
if (action.type === DECODED_TRANSACTION[FAILURE]) {
return action.error;
}
return state;
}
function previewUrl(state= `${window.location.protocol}//${window.location.host}/`, action) {
if (action.type === UPDATE_PREVIEW_URL) {
return action.payload;
@ -419,7 +429,8 @@ const rootReducer = combineReducers({
theme,
editorTabs,
previewUrl,
editorOperationStatus
editorOperationStatus,
decodedTransaction
});
export default rootReducer;

View File

@ -28,6 +28,10 @@ export function getTransaction(state, hash) {
return state.entities.transactions.find((transaction) => transaction.hash === hash);
}
export function getDecodedTransaction(state) {
return state.decodedTransaction;
}
export function getTransactionsByAccount(state, address) {
return state.entities.transactions.filter((transaction) => transaction.from === address);
}

View File

@ -81,6 +81,7 @@ export const toggleBreakpoint = doRequest.bind(null, actions.toggleBreakpoint, a
export const authenticate = doRequest.bind(null, actions.authenticate, api.authenticate);
export const initRegularTxs = doRequest.bind(null, actions.initRegularTxs, api.regularTxs);
export const stopRegularTxs = doRequest.bind(null, actions.stopRegularTxs, api.regularTxs);
export const decodeTransaction = doRequest.bind(null, actions.decodedTransaction, api.fetchTransaction);
export const fetchCredentials = doRequest.bind(null, actions.fetchCredentials, storage.fetchCredentials);
export const saveCredentials = doRequest.bind(null, actions.saveCredentials, storage.saveCredentials);
@ -103,6 +104,10 @@ export function *watchFetchTransaction() {
yield takeEvery(actions.TRANSACTION[actions.REQUEST], fetchTransaction);
}
export function *watchDecodeTransaction() {
yield takeEvery(actions.DECODED_TRANSACTION[actions.REQUEST], decodeTransaction);
}
export function *watchFetchTransactions() {
yield takeEvery(actions.TRANSACTIONS[actions.REQUEST], fetchTransactions);
}
@ -557,6 +562,7 @@ export default function *root() {
fork(watchListenToContractEvents),
fork(watchFetchBlock),
fork(watchFetchTransactions),
fork(watchDecodeTransaction),
fork(watchPostCommand),
fork(watchPostCommandSuggestions),
fork(watchFetchVersions),

View File

@ -1,11 +1,12 @@
const Web3 = require('web3');
const async = require('async');
const Provider = require('./provider.js');
const Transaction = require('ethereumjs-tx');
const ethUtil = require('ethereumjs-util');
const utils = require('../../utils/utils');
const constants = require('../../constants');
const embarkJsUtils = require('embarkjs').Utils;
const {bigNumberify} = require('ethers/utils/bignumber');
const RLP = require('ethers/utils/rlp');
const WEB3_READY = 'blockchain:ready';
@ -420,10 +421,12 @@ class BlockchainConnector {
'/embark-api/blockchain/transactions/:hash',
(req, res) => {
self.getTransactionByHash(req.params.hash, (err, transaction) => {
if (err) {
self.logger.error(err);
}
res.send(transaction);
if (!err) return res.send(transaction);
self.getTransactionByRawTransactionHash(req.params.hash, (err, transaction) => {
if(err) return res.send({ error: "Could not find or decode transaction hash" });
res.send(transaction);
});
});
}
);
@ -645,20 +648,39 @@ class BlockchainConnector {
}
getTransactionByRawTransactionHash(hash, cb) {
const rawData = Buffer.from(ethUtil.stripHexPrefix(hash), 'hex');
const tx = new Transaction(rawData, 'hex');
let rawData, decoded;
try {
rawData = Buffer.from(ethUtil.stripHexPrefix(hash), 'hex');
decoded = RLP.decode(rawData);
} catch(e) {
return cb("could not decode transaction");
}
const [
nonce,
gasPrice,
gasLimit,
to,
value,
data,
v,
r,
s
] = decoded;
const transaction = {
from: `0x${tx.getSenderAddress().toString('hex').toLowerCase()}`,
gasPrice: tx.gasPrice.toString('utf8'),
input: `0x${tx.input.toString('hex').toLowerCase()}`,
nonce: tx.nonce.toString('utf8'),
v: `0x${tx.v.toString('hex').toLowerCase()}`,
r: `0x${tx.r.toString('hex').toLowerCase()}`,
s: `0x${tx.s.toString('hex').toLowerCase()}`,
value: tx.value.toString('utf8'),
to: `0x${tx.to.toString('hex').toLowerCase()}`,
hash
nonce: bigNumberify(nonce).toNumber(),
gasPrice: bigNumberify(gasPrice).toNumber(),
gasLimit: bigNumberify(gasLimit).toNumber(),
data: data,
v: `0x${v.toString('hex').toLowerCase()}`,
r: `0x${r.toString('hex').toLowerCase()}`,
s: `0x${s.toString('hex').toLowerCase()}`,
value: value.toString('utf8'),
to: `0x${to.toString('hex').toLowerCase()}`
};
cb(null, transaction);
}