From 9e9f26af40594c8d943858d75829f7ce81107823 Mon Sep 17 00:00:00 2001 From: liangping <18786721@qq.com> Date: Thu, 5 Aug 2021 12:38:58 +0800 Subject: [PATCH] finish block and transaction --- package.json | 1 + src/libs/data/data.js | 33 ++++++-- src/libs/data/index.js | 1 + src/libs/data/stdtx.js | 36 ++++++++ src/libs/data/token.js | 13 +++ src/libs/data/tx.js | 27 ++++++ src/libs/data/wrapstdtx.js | 45 ++++++++++ src/libs/fetch.js | 37 +++++++- src/router/index.js | 30 ++++++- src/store/chains/index.js | 33 ++++++-- src/views/ArrayFieldComponent.vue | 21 ++++- src/views/Block.vue | 95 +++++++++++++++++++++ src/views/ObjectFieldComponent.vue | 61 +++++++++++--- src/views/StakingValidator.vue | 2 +- src/views/Transaction.vue | 130 +++++++++++++++++++++++++++++ yarn.lock | 96 +++++++++++++++++++++ 16 files changed, 628 insertions(+), 33 deletions(-) create mode 100644 src/libs/data/stdtx.js create mode 100644 src/libs/data/token.js create mode 100644 src/libs/data/tx.js create mode 100644 src/libs/data/wrapstdtx.js create mode 100644 src/views/Block.vue create mode 100644 src/views/Transaction.vue diff --git a/package.json b/package.json index 5b7180a3..94c58a08 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@cosmjs/amino": "^0.25.6", "@cosmjs/crypto": "^0.25.6", "@cosmjs/encoding": "^0.25.6", + "@cosmjs/proto-signing": "^0.25.6", "@fullcalendar/common": "5.x", "@fullcalendar/core": "5.x", "@fullcalendar/daygrid": "5.x", diff --git a/src/libs/data/data.js b/src/libs/data/data.js index 5dc58fc8..37186938 100644 --- a/src/libs/data/data.js +++ b/src/libs/data/data.js @@ -12,6 +12,20 @@ export function percent(num) { return parseFloat((num * 100).toFixed(2)) } +export function abbr(string, length = 6) { + if (string && string.length > length) { + return `${string.substring(0, length)}...` + } + return string +} + +export function abbrMessage(msg) { + if (Array.isArray(msg)) { + return msg.map(x => abbrMessage(x)).join() + } + return msg.typeUrl.substring(msg.typeUrl.lastIndexOf('.') + 1) +} + export function isToken(value) { let is = false if (Array.isArray(value)) { @@ -21,15 +35,18 @@ export function isToken(value) { } export function formatToken(token) { - let denom = token.denom.toUpperCase() - if (denom.charAt(0) === 'U') { - denom = denom.substring(1) + if (token) { + let denom = token.denom.toUpperCase() + if (denom.charAt(0) === 'U') { + denom = denom.substring(1) + } + const amount = token.amount / 1000000 + if (amount > 10) { + return `${amount.toFixed()} ${denom}` + } + return `${amount} ${denom}` } - const amount = token.amount / 1000000 - if (amount > 10) { - return `${amount.toFixed()} ${denom}` - } - return `${amount} ${denom}` + return '' } const COUNT_ABBRS = ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'] diff --git a/src/libs/data/index.js b/src/libs/data/index.js index 571884a7..4fb61bfd 100644 --- a/src/libs/data/index.js +++ b/src/libs/data/index.js @@ -9,6 +9,7 @@ export { default as StakingParameters } from './staking-parameters' export { default as Block } from './block' export { default as ValidatorDistribution } from './validator-distribution' export { default as StakingDelegation } from './staking-delegation' +export { default as WrapStdTx } from './wrapstdtx' export * from './data' export default class Test {} diff --git a/src/libs/data/stdtx.js b/src/libs/data/stdtx.js new file mode 100644 index 00000000..de1b5831 --- /dev/null +++ b/src/libs/data/stdtx.js @@ -0,0 +1,36 @@ +import compareVersions from 'compare-versions' +import Token from './token' + +export default class StdTx { + constructor() { + this.type = '' + this.fee = [new Token()] + this.gas = 0 + this.memo = '' + this.messages = [] + this.signatures = [] + this.timeout_height = 0 + } + + static create(element, version = '0.40') { + const self = new StdTx() + if (compareVersions(version, '0.40') < 1) { + self.type = element.type + self.fee = element.value.fee.amount + self.gas = element.value.fee.gas + self.memo = element.value.memo + self.messages = element.value.msg + self.signatures = element.value.signatures + self.timeout_height = 0 + } else { + self.type = element['@type'] + self.fee = element.auth_info.fee.amount + self.gas = element.auth_info.fee.gas_limit + self.memo = element.body.memo + self.messages = element.body.messages + self.signatures = element.signatures + self.timeout_height = element.body.timeout_height + } + return self + } +} diff --git a/src/libs/data/token.js b/src/libs/data/token.js new file mode 100644 index 00000000..060b3743 --- /dev/null +++ b/src/libs/data/token.js @@ -0,0 +1,13 @@ +export default class Token { + constructor() { + this.amount = 0 + this.denom = '' + } + + static create(element) { + const self = new Token() + self.amount = Number(element.amount) + self.denom = element.denom + return self + } +} diff --git a/src/libs/data/tx.js b/src/libs/data/tx.js new file mode 100644 index 00000000..d5d37d9e --- /dev/null +++ b/src/libs/data/tx.js @@ -0,0 +1,27 @@ +import { sha256 } from '@cosmjs/crypto' +import { fromBase64, toHex } from '@cosmjs/encoding' +import Token from './token' + +export default class Tx { + constructor() { + this.hash = '' + this.fee = [new Token()] + this.memo = '' + this.messages = [] + this.signatures = [] + } + + static create(element) { + const self = new Tx() + self.hash = '' + self.fee = element.authInfo.fee.amount + self.memo = element.body.memo + self.messages = element.body.messages + self.signatures = element.signatures + return self + } + + setHash(raw) { + this.hash = toHex(sha256(fromBase64(raw))).toUpperCase() + } +} diff --git a/src/libs/data/wrapstdtx.js b/src/libs/data/wrapstdtx.js new file mode 100644 index 00000000..fa1aab1c --- /dev/null +++ b/src/libs/data/wrapstdtx.js @@ -0,0 +1,45 @@ +import compareVersions from 'compare-versions' +import StdTx from './stdtx' + +export default class WrapStdTx { + constructor() { + this.code = 0 + this.txhash = '' + this.data = '' + this.gas_used = '' + this.gas_wanted = '' + this.height = 0 + this.logs = [] + this.timestamp = '' + this.tx = new StdTx() + this.info = '' + this.raw_log = '' + } + + static create(element, version = '0.40') { + const self = new WrapStdTx() + if (compareVersions(version, '0.40') < 1) { + self.txhash = element.txhash + self.data = element.data + self.gas_used = element.gas_used + self.gas_wanted = element.gas_wanted + self.height = Number(element.height) + self.logs = element.logs + self.timestamp = element.timestamp + self.tx = StdTx.create(element.tx) + } else { + self.code = element.tx_response.code + self.txhash = element.tx_response.txhash + self.data = element.tx_response.data + self.gas_used = element.tx_response.gas_used + self.gas_wanted = element.tx_response.gas_wanted + self.height = Number(element.tx_response.height) + self.info = element.tx_response.info + self.logs = element.tx_response.logs + self.timestamp = element.tx_response.timestamp + self.tx = StdTx.create(element.tx, version) + self.raw_log = element.tx_response.raw_log + } + return self + } +} diff --git a/src/libs/fetch.js b/src/libs/fetch.js index 87f99907..13d6a08e 100644 --- a/src/libs/fetch.js +++ b/src/libs/fetch.js @@ -3,7 +3,7 @@ import store from '@/store' import compareVersions from 'compare-versions' import { Proposal, ProposalTally, Proposer, StakingPool, Votes, Deposit, - Validator, StakingParameters, Block, ValidatorDistribution, StakingDelegation, + Validator, StakingParameters, Block, ValidatorDistribution, StakingDelegation, WrapStdTx, } from './data' function commonProcess(res) { @@ -11,14 +11,34 @@ function commonProcess(res) { } // 头像 -export async function keybase(identity) { +export function keybase(identity) { return fetch(`https://keybase.io/_/api/1.0/user/lookup.json?key_suffix=${identity}&fields=pictures`) .then(res => res.json()) } +async function refetchVersion(chain) { + await fetch(`${chain.api}/node_info`) + .then(res => res.json()) + .then(json => { + const sdk = json.application_version.build_deps.find(e => e.startsWith('github.com/cosmos/cosmos-sdk')) + const re = /(\d+(\.\d+)*)/i + const version = sdk.match(re) + return version[0] + }) +} + const chainAPI = class ChainFetch { getSelectedConfig() { - this.config = store.state.chains.selected + let chain = store.state.chains.selected + const lschains = localStorage.getItem('chains') + if (lschains) { + chain = JSON.parse(lschains)[chain.chain_name] + } + if (!chain.sdk_version) { + chain.sdk_version = refetchVersion(chain) + } + this.config = chain + console.log(this.config) return this.config } @@ -30,6 +50,17 @@ const chainAPI = class ChainFetch { return this.get(`/blocks/${height}`).then(data => Block.create(data)) } + async getTxs(hash) { + const FIELD = 'sdk_version' + const ver = this.getSelectedConfig() ? this.config.sdk_version : '0.41' + console.log(ver, this.config[FIELD]) + // /cosmos/tx/v1beta1/txs/{hash} + if (ver && compareVersions(ver, '0.40') < 1) { + return this.get(`/txs/${hash}`).then(data => WrapStdTx.create(data, ver)) + } + return this.get(`/cosmos/tx/v1beta1/txs/${hash}`).then(data => WrapStdTx.create(data, ver)) + } + async getValidatorDistribution(address) { return this.get(`/distribution/validators/${address}`).then(data => { const ret = ValidatorDistribution.create(commonProcess(data)) diff --git a/src/router/index.js b/src/router/index.js index f8a27683..02698101 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -110,6 +110,34 @@ const router = new VueRouter({ ], }, }, + { + path: '/:chain/block/:height', + name: 'block', + component: () => import('@/views/Block.vue'), + meta: { + pageTitle: 'Block', + breadcrumb: [ + { + text: 'Block', + active: true, + }, + ], + }, + }, + { + path: '/:chain/tx/:hash', + name: 'transaction', + component: () => import('@/views/Transaction.vue'), + meta: { + pageTitle: 'Transaction', + breadcrumb: [ + { + text: 'Transaction', + active: true, + }, + ], + }, + }, { path: '/login', name: 'login', @@ -139,7 +167,7 @@ router.beforeEach((to, from, next) => { if (has > -1) { const chain = store.state.chains.config[c] store.commit('select', { chain_name: c }) - if (chain.sdk_version === undefined) { + if (chain.sdk_version) { fetch(`${chain.api}/node_info`) .then(res => res.json()) .then(json => { diff --git a/src/store/chains/index.js b/src/store/chains/index.js index 27800d07..cc5ab16a 100644 --- a/src/store/chains/index.js +++ b/src/store/chains/index.js @@ -1,9 +1,32 @@ -const chains = {} -const configs = require.context('.', false, /\.json$/) +let chains = {} -configs.keys().forEach(k => { - const c = configs(k) - chains[c.chain_name] = c +const localChains = localStorage.getItem('chains') +if (localChains) { + chains = JSON.parse(localChains) +} else { + const configs = require.context('.', false, /\.json$/) + + configs.keys().forEach(k => { + const c = configs(k) + chains[c.chain_name] = c + }) + localStorage.setItem('chains', JSON.stringify(chains)) +} + +Object.keys(chains).forEach(key => { + const chain = chains[key] + fetch(`${chain.api}/node_info`) + .then(res => res.json()) + .then(json => { + const sdk = json.application_version.build_deps.find(e => e.startsWith('github.com/cosmos/cosmos-sdk')) + const re = /(\d+(\.\d+)*)/i + const version = sdk.match(re) + // eslint-disable-next-line prefer-destructuring + chain.sdk_version = version[0] + localStorage.setItem('chains', JSON.stringify(chains)) + console.log(`${chain.api}/node_info`, localStorage.getItem('chains')) + }) + .catch(e => console.log(`Failed get api vesion of ${key}`, e)) }) export default { diff --git a/src/views/ArrayFieldComponent.vue b/src/views/ArrayFieldComponent.vue index 45e47027..920a1f46 100644 --- a/src/views/ArrayFieldComponent.vue +++ b/src/views/ArrayFieldComponent.vue @@ -1,5 +1,6 @@ @@ -20,7 +24,9 @@ import { BTable } from 'bootstrap-vue' // import fetch from 'node-fetch' -import { isToken, tokenFormatter } from '@/libs/data/data' +import { + abbr, isToken, toDay, tokenFormatter, +} from '@/libs/data/data' // import { Proposal, Proposer } from '@/libs/data' // import { formatToken } from '@/libs/data/data' @@ -31,7 +37,7 @@ export default { }, props: { tablefield: { - type: Array, + type: [Array, Object], default: () => [], }, }, @@ -46,9 +52,16 @@ export default { return isToken(value) }, isArrayText(value) { - const has = String(value).startsWith('[') + const has = String(value).startsWith('[') && String(value).endsWith(']') return has }, + formatText(value) { + const reg = /^\d{4}.\d{1,2}.\d{1,2}T\d{2}:\d{2}:.+Z$/ + if (reg.test(value)) { + return toDay(value) + } + return abbr(value, 40) + }, formatTokens(value) { return tokenFormatter(value) }, diff --git a/src/views/Block.vue b/src/views/Block.vue new file mode 100644 index 00000000..0cc594ee --- /dev/null +++ b/src/views/Block.vue @@ -0,0 +1,95 @@ + + + + + diff --git a/src/views/ObjectFieldComponent.vue b/src/views/ObjectFieldComponent.vue index a8cedb8f..83a920a2 100644 --- a/src/views/ObjectFieldComponent.vue +++ b/src/views/ObjectFieldComponent.vue @@ -1,5 +1,11 @@