Skip to content

Commit

Permalink
Merge pull request #770 from cosmos/billy/454-tx-info
Browse files Browse the repository at this point in the history
Billy/454 tx info closes #454
  • Loading branch information
okwme authored Jun 5, 2018
2 parents f6e3c60 + 87b1375 commit 604b15f
Show file tree
Hide file tree
Showing 15 changed files with 256 additions and 50 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
* Added COSMOS_MOCKED env variable to allow overwriting mocked mode from the command line @faboweb
* User will now be logged out if switching between mocked and live connector @faboweb
* recovery seed form validation & tests @okwme
* added tx view to block explorer @okwme

### Changed

Expand Down
34 changes: 30 additions & 4 deletions app/src/renderer/components/monitor/PageBlock.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template lang="pug">
page(:title="pageBlockTitle")
data-loading(v-if="blockchain.blockLoading")
data-empty(v-else-if="!block.header || !blockMeta")
data-empty(v-else-if="!block || !block.header || !blockMeta")
template(v-else)
div(slot="menu"): tool-bar
router-link(:to="{ name: 'block', params: { block: block.header.height - 1 }}"
Expand Down Expand Up @@ -44,13 +44,23 @@ page(:title="pageBlockTitle")
part(title='Transactions')
data-loading(v-if="blockchain.blockLoading")
data-empty(v-else-if="block.header.num_txs === 0" title="Empty Block" subtitle="There were no transactions in this block.")
list-item(v-else v-for="tx in block.data.txs" :key="tx.id" dt="Transaction" :dd="TODO")
template(
v-else-if="txs.length"
)
li-transaction(
:key="tkey + '-tx'"
v-for="(tx, tkey) in txs"
v-if="isObj(tx)"
:transaction-value="transactionValueify(tx)"
:address="tx.tx.msg.inputs[0].address"
:devMode="config.devMode")
</template>

<script>
import { mapGetters } from "vuex"
import moment from "moment"
import num from "scripts/num"
import LiTransaction from "wallet/LiTransaction"
import DataLoading from "common/NiDataLoading"
import DataEmpty from "common/NiDataEmpty"
import ToolBar from "common/NiToolBar"
Expand All @@ -60,6 +70,7 @@ import Page from "common/NiPage"
export default {
name: "page-block",
components: {
LiTransaction,
DataLoading,
DataEmpty,
ToolBar,
Expand All @@ -68,12 +79,15 @@ export default {
Page
},
computed: {
...mapGetters(["blockchain"]),
...mapGetters(["blockchain", "blockTxInfo", "config"]),
blockchainHeight() {
return this.blockchain.blocks.length > 0
? this.blockchain.blocks[0].header.height
: 0
},
txs() {
return this.blockTxInfo || (this.block.data && this.block.data.txs)
},
block() {
return this.blockchain.block
},
Expand All @@ -96,13 +110,25 @@ export default {
},
nextBlockAvailable() {
return (
this.block.header && this.block.header.height < this.blockchainHeight
this.block &&
this.block.header &&
this.block.header.height < this.blockchainHeight
)
}
},
methods: {
isObj(thing) {
return typeof thing === "object"
},
fetchBlock() {
this.$store.dispatch("getBlock", parseInt(this.$route.params.block))
},
transactionValueify(tv) {
tv = JSON.parse(JSON.stringify(tv))
tv.tx.inputs = tv.tx.msg.inputs
tv.tx.outputs = tv.tx.msg.outputs
tv.time = this.block && this.block.blockHeaderTime
return tv
}
},
mounted() {
Expand Down
1 change: 0 additions & 1 deletion app/src/renderer/components/wallet/PageSend.vue
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ export default {
},
async onSubmit() {
this.$v.$touch()
console.log(this.$v.$error)
if (this.$v.$error) return
this.sending = true
Expand Down
2 changes: 2 additions & 0 deletions app/src/renderer/connectors/lcdClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ Object.assign(Client.prototype, {
},
coinTxs: argReq("GET", "/tx/coin"),

txs: argReq("GET", "/txs"),

// staking
candidate: argReq("GET", "/query/stake/candidate"),
candidates: req("GET", "/query/stake/candidates"),
Expand Down
8 changes: 4 additions & 4 deletions app/src/renderer/connectors/rpcWrapperMock.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const mockValidators = require("../../helpers/json/mock_validators.json")

let state = { blockMetas: [], blocks: [], connected: true }
let state = { blockMetas: {}, blocks: [], connected: true }
createBlockMetas(state)

const RpcClientMock = {
Expand All @@ -18,7 +18,7 @@ const RpcClientMock = {
cb(null, { block: state.blocks.find(b => b.header.height === minHeight) }),
blockchain: ({ minHeight, maxHeight }, cb) =>
cb(null, {
block_metas: state.blockMetas.filter(b => b.height === minHeight)
block_metas: state.blockMetas[minHeight]
}),
status: cb =>
cb(null, {
Expand Down Expand Up @@ -94,7 +94,7 @@ function createBlockMetas(state) {
let time = new Date(now)
time.setMinutes(time.getMinutes() - i)

state.blockMetas.push(createBlockMeta(time, i))
state.blockMetas[i] = createBlockMeta(time, i)
state.blocks.push(createBlock(i))
})
}
Expand All @@ -103,7 +103,7 @@ async function produceBlockHeaders(cb) {
let height = 200
while (state.connected) {
let newBlockHeader = createBlockMeta(Date.now(), ++height)
state.blockMetas.push(newBlockHeader)
state.blockMetas[newBlockHeader.height] = newBlockHeader
cb(null, { data: { value: { header: newBlockHeader } } })
await sleep(1000)
}
Expand Down
14 changes: 14 additions & 0 deletions app/src/renderer/scripts/tx-utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import crypto from "crypto"
import varint from "varint"

export function getTxHash(txstring) {
let txbytes = Buffer.from(txstring, "base64")
let varintlen = new Uint8Array(varint.encode(txbytes.length))
let tmp = new Uint8Array(varintlen.byteLength + txbytes.byteLength)
tmp.set(new Uint8Array(varintlen), 0)
tmp.set(new Uint8Array(txbytes), varintlen.byteLength)
return crypto
.createHash("ripemd160")
.update(Buffer.from(tmp))
.digest("hex")
}
8 changes: 8 additions & 0 deletions app/src/renderer/vuex/getters.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,11 @@ export const connected = state => state.node.connected
export const lastHeader = state => state.node.lastHeader
export const nodeIP = state => state.node.nodeIP
export const mockedConnector = state => state.node.mocked

//blockchain
export const blockTxInfo = state => {
return (
state.blockchain.block.header &&
state.blockchain.blockTxs[state.blockchain.block.header.height]
)
}
102 changes: 80 additions & 22 deletions app/src/renderer/vuex/modules/blockchain.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { getTxHash } from "../../scripts/tx-utils.js"

export default ({ commit, node }) => {
const state = {
blocks: [],
Expand All @@ -7,7 +9,8 @@ export default ({ commit, node }) => {
blockLoading: false,
subscription: false,
syncing: true,
blockMetas: []
blockMetas: {},
blockTxs: {}
}

const mutations = {
Expand All @@ -19,6 +22,9 @@ export default ({ commit, node }) => {
},
setBlockMetaInfo(state, blockMetaInfo) {
state.blockMetaInfo = blockMetaInfo
},
setBlockTxInfo(state, blockTxInfo) {
state.blockTxInfo = blockTxInfo
}
}

Expand All @@ -32,39 +38,91 @@ export default ({ commit, node }) => {
dispatch("subscribeToBlocks")
},
async getBlock({ state, commit, dispatch }, height) {
state.blockLoading = true
state.blockHeight = height
return Promise.all([
dispatch("queryBlock", height).then(block => commit("setBlock", block)),
dispatch("queryBlockInfo", height).then(blockMetaInfo =>
commit("setBlockMetaInfo", blockMetaInfo)
)
]).then(
() => {
state.blockLoading = false
},
() => {
state.blockLoading = false
}
)
try {
state.blockLoading = true
state.blockHeight = height
const [block, blockMetaInfo] = await Promise.all([
dispatch("queryBlock", height),
dispatch("queryBlockInfo", height)
])
commit("setBlock", block)
commit("setBlockMetaInfo", blockMetaInfo)
state.blockLoading = false
const blockTxInfo = await dispatch("queryTxInfo", height)
commit("setBlockTxInfo", blockTxInfo)
} catch (error) {
state.blockLoading = false
return Promise.reject(error)
}
},
async queryBlock({ state, commit }, height) {
return new Promise(resolve => {
queryBlock({ state, commit }, height) {
return new Promise((resolve, reject) => {
node.rpc.block({ height }, (err, data) => {
if (err) {
commit("notifyError", {
title: `Couldn't query block`,
body: err.message
})
resolve({})
resolve(null)
} else {
resolve(data.block)
}
})
})
},
async queryTxInfo({ state, dispatch, commit }, height) {
if (!height) {
commit("notifyError", {
title: `Couldn't query tx`,
body: "No Height Provided"
})
return Promise.resolve()
}
let blockTxInfo = state.blockTxs[height]
if (blockTxInfo) {
return blockTxInfo
}
try {
blockTxInfo = await dispatch("getTxs", {
key: 0,
len: state.block ? state.block.data.txs.length : 0,
txs: state.block ? state.block.data.txs.slice(0) : []
})
state.blockTxs[height] = blockTxInfo
return blockTxInfo
} catch (error) {
return Promise.reject(error)
}
},
async getTxs({ state, commit, dispatch }, { key, len, txs }) {
// this function queries txs recursively. it's called from queryTxInfo as series of synchronous
// calls. it could also be called as a Promise.all to make the calls asynchronous but block with
// many transactions might overload the tx endpoint with too many simultaneous calls.
try {
if (key >= len) return txs
let txstring = atob(txs[key])
let hash = await getTxHash(txs[key])
let data = await node.txs(hash)
data.string = txstring
txs[key] = data
return await dispatch("getTxs", { key: key + 1, len, txs })
} catch (error) {
commit("notifyError", {
title: `Couldn't query block`,
body: error.message
})
return Promise.reject(error)
}
},
async queryBlockInfo({ state, commit }, height) {
let blockMetaInfo = state.blockMetas.find(b => b.header.height === height)
if (!height) {
commit("notifyError", {
title: `Couldn't query block`,
body: "No Height Provided"
})
return Promise.resolve()
}
let blockMetaInfo = state.blockMetas[height]
if (blockMetaInfo) {
return blockMetaInfo
}
Expand All @@ -79,12 +137,12 @@ export default ({ commit, node }) => {
})
resolve(null)
} else {
resolve(data.block_metas[0])
resolve(data.block_metas.length ? data.block_metas[0] : null)
}
}
)
})
blockMetaInfo && state.blockMetas.push(blockMetaInfo)
state.blockMetas[height] = blockMetaInfo
return blockMetaInfo
},
subscribeToBlocks({ state, commit, dispatch }) {
Expand Down
7 changes: 6 additions & 1 deletion app/src/renderer/vuex/modules/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ export default ({ commit, node }) => {
setTransactionTime(state, { blockHeight, blockMetaInfo }) {
state.history = state.history.map(t => {
if (t.height === blockHeight) {
t.time = blockMetaInfo.header.time
// console.log("blockMetaInfo", blockMetaInfo)
t.time = blockMetaInfo && blockMetaInfo.header.time
}
return t
})
Expand Down Expand Up @@ -103,6 +104,10 @@ export default ({ commit, node }) => {
},
async queryTransactionTime({ commit, dispatch }, blockHeight) {
let blockMetaInfo = await dispatch("queryBlockInfo", blockHeight)
// console.log(
// "received blockMetaInfo at height " + blockHeight,
// blockMetaInfo
// )
commit("setTransactionTime", { blockHeight, blockMetaInfo })
},
async loadDenoms({ state, commit }) {
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@
"tendermint-crypto": "github:mappum/js-crypto",
"toml": "2.3.3",
"user-home": "2.0.0",
"varint": "5.0.0",
"vue": "2.5.16",
"vue-directive-tooltip": "1.4.5",
"vue-electron": "1.0.6",
Expand Down
8 changes: 3 additions & 5 deletions test/e2e/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,10 @@ test("wallet", async function(t) {
await login(app, "testkey")

let balanceEl = denom => {
console.log("looking for " + denom.toUpperCase())
// let balanceElemSlector = "div=" + denom.toUpperCase()
let balanceElemSlector = `//div[contains(text(), "${denom.toUpperCase()}")]`
app.client.getHTML("#part-available-balances").then(result => {
console.log(result)
})
// app.client.getHTML("#part-available-balances").then(result => {
// console.log(result)
// })
return app.client.waitForExist(balanceElemSlector, 20000).then(() =>
$(balanceElemSlector)
.$("..")
Expand Down
12 changes: 11 additions & 1 deletion test/unit/specs/components/common/NiModalSearch.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Vuelidate from "vuelidate"

describe("NiModalSearch", () => {
let wrapper, store
let { mount, shallow, localVue } = setup()
let { mount, localVue } = setup()

beforeEach(() => {
let instance = mount(NiModalSearch, { propsData: { type: "transactions" } })
Expand Down Expand Up @@ -55,4 +55,14 @@ describe("NiModalSearch", () => {
.trim()
).toBe("Find")
})

it("should go to block", () => {
wrapper.vm.$router.go("balances")
wrapper.setProps({ type: "blocks" })
store.commit("setSearchVisible", ["blocks", true])
expect(wrapper.vm.$route.name).toBe("balances")
wrapper.vm.query = "1"
wrapper.vm.gotoBlock()
expect(wrapper.vm.$route.name).toBe("block")
})
})
Loading

0 comments on commit 604b15f

Please sign in to comment.