Skip to content

Commit

Permalink
Dynamic chain version info from REST APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
tombeynon committed Oct 5, 2022
1 parent a067689 commit d1903f9
Show file tree
Hide file tree
Showing 8 changed files with 208 additions and 233 deletions.
19 changes: 14 additions & 5 deletions chains/chain.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ function Chain(client, data, paramsData, opts) {
...opts
}
const { path, chain, assetlist } = data;
const { params, services, prices } = paramsData
const { params, versions, services, prices } = paramsData

chain.name = chain.chain_name
const coingecko = prices?.coingecko || {}
Expand All @@ -30,10 +30,6 @@ function Chain(client, data, paramsData, opts) {
const health = await apiHealth(type)
return ChainApis(health)
}

function apiUrls(type){
return (chain.apis || {})[type]
}

async function apiHealth(type) {
const healthPath = {}
Expand All @@ -46,6 +42,18 @@ function Chain(client, data, paramsData, opts) {
return type ? {[type]: health[0]} : health
}

function apiUrls(type){
switch (type) {
case 'service':
return serviceApis() || []
case 'private-rpc':
case 'private-rest':
return privateApis(type.replace('private-', '')) || []
default:
return (chain.apis || {})[type] || []
}
}

function serviceApis(){
return (config.serviceApis || []).map(url => {
return { ...url, service: true }
Expand Down Expand Up @@ -79,6 +87,7 @@ function Chain(client, data, paramsData, opts) {
...data,
config,
params,
versions,
services,
prices,
apis,
Expand Down
37 changes: 21 additions & 16 deletions chains/chainApis.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ const IGNORE_ERROR_DIFF = 60 * 60

function ChainApis(health) {
function bestAddress(type) {
let urls = Object.values(health[type] || {})
let urls = availableUrls(type)
if(['rpc', 'rest'].includes(type)){
urls = urls.concat(Object.values(health[`private-${type}`] || {}))
urls = urls.concat(availableUrls(`private-${type}`))
}
const best = _.sample(prepareUrls(urls.filter(el => el.available)))
const best = _.sample(prepareUrls(filterUrls(urls)))
return best && best.address
}

Expand All @@ -23,26 +23,29 @@ function ChainApis(health) {
}

function bestHeight(type) {
let urls
return Math.max(...availableUrls(type).map(el => el.blockHeight).filter(Number.isFinite))
}

function bestUrls(type) {
return prepareUrls(filterUrls(availableUrls(type)))
}

function availableUrls(type) {
return getUrls(type).filter(el => el.available)
}

function getUrls(type) {
if(type){
urls = []
urls = urls.concat(Object.values(health[type] || {}))
return Object.values(health[type] || {})
}else{
urls = Object.values(health).reduce((sum, urls) => {
return Object.values(health).reduce((sum, urls) => {
return sum.concat(Object.values(urls))
}, [])
}
return Math.max(...urls.filter(el => el.available).map(el => el.blockHeight).filter(Number.isFinite))
}

function bestUrls(type) {
let urls
urls = Object.values(health[type] || {}).filter(el => el.available)
return prepareUrls(urls)
}

function prepareUrls(urls){
return filterUrls(urls).map(el => {
return urls.map(el => {
const url = { ...el.url }
url.address = el.finalAddress || url.address
return url
Expand Down Expand Up @@ -79,8 +82,10 @@ function ChainApis(health) {
return {
bestAddress,
bestServiceAddress,
bestUrls,
bestHeight,
bestUrls,
availableUrls,
getUrls,
health
}
}
Expand Down
41 changes: 39 additions & 2 deletions chains/chainMonitor.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import PQueue from 'p-queue';
import got from 'got';
import _ from 'lodash'
import { compareVersions, validate } from 'compare-versions';
import { bignumber, multiply, divide } from 'mathjs'
import { createAgent, debugLog, timeStamp, formatNumber } from '../utils.js';

Expand All @@ -24,12 +25,14 @@ function ChainMonitor() {
const current = await client.json.get('chains:' + chain.path, '$') || {}

let chainParams = await getChainParams(restUrl, chain, current.params || {});
let versionParams = await getVersionParams(chain, apis, current.versions || {})

await client.json.set('chains:' + chain.path, '$', {
...current,
chainId: chain.chainId,
lastUpdated: Date.now(),
params: chainParams || current.params
params: chainParams || current.params,
versions: versionParams || current.versions
});
debugLog(chain.path, 'Chain update complete')
};
Expand All @@ -38,6 +41,40 @@ function ChainMonitor() {
debugLog('Chain update complete')
}

async function getVersionParams(chain, apis, current){
try {
const versions = {
application_version: [],
cosmos_sdk_version: [],
tendermint_version: []
}
await Promise.all(['rest', 'private-rest'].map(async (type) => {
const urls = apis.availableUrls(type)
await Promise.all(urls.map(async (url) => {
try {
const response = await got.get(url.finalAddress + '/cosmos/base/tendermint/v1beta1/node_info', gotOpts)
const data = JSON.parse(response.body)
const { version, cosmos_sdk_version } = data.application_version
const tendermint_version = data.default_node_info?.version || data.node_info?.version
if(validate(version)) versions.application_version.push(version)
if(validate(cosmos_sdk_version)) versions.cosmos_sdk_version.push(cosmos_sdk_version)
if(validate(tendermint_version)) versions.tendermint_version.push(tendermint_version)
} catch (error) {
debugLog(chain.path, url.finalAddress, 'Node update failed:', error.message)
}
}))
}));
// use the lowest available version
return {
application_version: versions.application_version.sort(compareVersions)[0] || current.application_version,
cosmos_sdk_version: versions.cosmos_sdk_version.sort(compareVersions)[0] || current.cosmos_sdk_version,
tendermint_version: versions.tendermint_version.sort(compareVersions)[0] || current.tendermint_version
}
} catch (error) {
timeStamp(chain.path, 'Version update failed', error.message)
}
}

async function getChainParams(restUrl, chain, current) {
const { denom } = chain
try {
Expand Down Expand Up @@ -74,7 +111,7 @@ function ChainMonitor() {
annualProvision: formatNumber(data.annualProvision)
}, (_value, key) => _.snakeCase(key))
} catch (error) {
timeStamp(chain.path, 'Update failed', error.message)
timeStamp(chain.path, 'Params update failed', error.message)
}
}

Expand Down
15 changes: 12 additions & 3 deletions chains/chainsController.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { renderJson } from '../utils.js';

function ChainsController(registry) {
async function chainResponse(chain, summarize) {
const { chain_name, network_type, pretty_name, chain_id, status, explorers } = chain.chain;
const { chain_name, network_type, pretty_name, chain_id, status, explorers, keywords, codebase } = chain.chain;
const baseAsset = chain.baseAsset
const apis = await chain.apis()
const { params, services, prices, assets } = chain
const { params, versions, services, prices, assets } = chain
const response = {
name: chain_name,
path: chain.path,
Expand All @@ -30,11 +30,20 @@ function ChainsController(registry) {
rest: !!apis.bestAddress('rest'),
rpc: !!apis.bestAddress('rpc')
},
versions: {
...versions,
application_version: versions?.application_version || codebase?.recommended_version,
cosmos_sdk_version: versions?.cosmos_sdk_version || codebase?.cosmos_sdk_version,
tendermint_version: versions?.tendermint_version || codebase?.tendermint_version,
cosmwasm_version: codebase?.cosmwasm_version
},
cosmwasm_enabled: codebase?.cosmwasm_enabled,
explorers,
params,
services,
prices,
assets
assets,
keywords
};
if (summarize) {
return response
Expand Down
Loading

0 comments on commit d1903f9

Please sign in to comment.