From d548915efc836536e4b961ccabc3a3ca4fb9e60a Mon Sep 17 00:00:00 2001 From: Tom Kirkpatrick Date: Wed, 4 Jul 2018 20:32:19 +0200 Subject: [PATCH] feat(api): redundant block explorer api backends Call out to 3 different block explorers to get the current block height and use the result from whichever responds quickest. Fix #463 --- app/api/index.js | 32 +++++++++++++++++++++++++++----- app/reducers/lnd.js | 4 ++-- webpack.config.renderer.dev.js | 10 ++++++++++ webpack.config.renderer.prod.js | 4 +++- 4 files changed, 42 insertions(+), 8 deletions(-) diff --git a/app/api/index.js b/app/api/index.js index 63b95429..27e1dfd2 100644 --- a/app/api/index.js +++ b/app/api/index.js @@ -29,11 +29,33 @@ export function requestTickers(ids) { } export function requestBlockHeight() { - const BASE_URL = `${scheme}testnet-api.smartbit.com.au/v1/blockchain/blocks?limit=1` - return axios({ - method: 'get', - url: BASE_URL - }).then(response => response.data) + const sources = [ + { + baseUrl: `${scheme}testnet-api.smartbit.com.au/v1/blockchain/blocks?limit=1`, + path: 'blocks[0].height' + }, + { + baseUrl: `${scheme}tchain.api.btc.com/v3/block/latest`, + path: 'data.height' + }, + { + baseUrl: `${scheme}api.blockcypher.com/v1/btc/test3`, + path: 'height' + } + ] + const fetchData = (baseUrl, path) => { + return axios({ + method: 'get', + timeout: 5000, + url: baseUrl + }) + .then(response => path.split('.').reduce((a, b) => a[b], response.data)) + .catch(() => null) + } + + const promises = [] + sources.forEach(source => promises.push(fetchData(source.baseUrl, source.path))) + return Promise.race(promises) } export function requestSuggestedNodes() { diff --git a/app/reducers/lnd.js b/app/reducers/lnd.js index e63a8bd6..5ee4595b 100644 --- a/app/reducers/lnd.js +++ b/app/reducers/lnd.js @@ -84,8 +84,8 @@ export function receiveBlockHeight(blockHeight) { // Fetch current block height export const fetchBlockHeight = () => async dispatch => { dispatch(getBlockHeight()) - const blockData = await requestBlockHeight() - dispatch(receiveBlockHeight(blockData.blocks[0].height)) + const blockHeight = await requestBlockHeight() + dispatch(receiveBlockHeight(blockHeight)) } // ------------------------------------ diff --git a/webpack.config.renderer.dev.js b/webpack.config.renderer.dev.js index 4a5695ae..c98452c7 100644 --- a/webpack.config.renderer.dev.js +++ b/webpack.config.renderer.dev.js @@ -298,6 +298,16 @@ export default merge.smart(baseConfig, { target: 'https://testnet-api.smartbit.com.au', pathRewrite: { '^/proxy/testnet-api.smartbit.com.au': '' }, changeOrigin: true + }, + '/proxy/tchain.api.btc.com': { + target: 'https://tchain.api.btc.com', + pathRewrite: { '^/proxy/tchain.api.btc.com': '' }, + changeOrigin: true + }, + '/proxy/api.blockcypher.com': { + target: 'https://api.blockcypher.com', + pathRewrite: { '^/proxy/api.blockcypher.com': '' }, + changeOrigin: true } }, historyApiFallback: { diff --git a/webpack.config.renderer.prod.js b/webpack.config.renderer.prod.js index f295db31..baeacb21 100644 --- a/webpack.config.renderer.prod.js +++ b/webpack.config.renderer.prod.js @@ -159,7 +159,9 @@ export default merge.smart(baseConfig, { "'self'", 'https://api.coinmarketcap.com', 'https://zap.jackmallers.com', - 'https://testnet-api.smartbit.com.au' + 'https://testnet-api.smartbit.com.au', + 'https://tchain.api.btc.com', + 'https://api.blockcypher.com' ], 'script-src': ["'self'"], 'font-src': [