Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Billy/454 tx info #770

Merged
merged 25 commits into from
Jun 5, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jolesbi this is what you were looking for, right?

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"),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🥇


// 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