Skip to content
This repository has been archived by the owner on Oct 10, 2023. It is now read-only.

Commit

Permalink
Persistent thornode (api|rpc) urls (#2409)
Browse files Browse the repository at this point in the history
  • Loading branch information
veado authored Oct 3, 2022
1 parent dc3f676 commit 10ee942
Show file tree
Hide file tree
Showing 12 changed files with 152 additions and 55 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
## Add

- [Header] Add wallet selector [#1576](https://github.com/thorchain/asgardex-electron/issues/1576)
- Store Midgard url persistently #2393(https://github.com/thorchain/asgardex-electron/pull/2393)
- [Settings] Persistent data of editable endpoints (Midgard, THORNode API|RPC) [#2387](https://github.com/thorchain/asgardex-electron/issues/2387), [#2393](https://github.com/thorchain/asgardex-electron/pull/2393), [#2408](https://github.com/thorchain/asgardex-electron/pull/2408)

## Update

Expand Down
9 changes: 6 additions & 3 deletions src/renderer/contexts/ThorchainContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import {
client$,
clientState$,
clientUrl$,
setClientUrl,
setThornodeRpcUrl,
setThornodeApiUrl,
address$,
addressUI$,
balances$,
Expand All @@ -30,7 +31,8 @@ export type ThorchainContextValue = {
client$: typeof client$
clientState$: typeof clientState$
clientUrl$: typeof clientUrl$
setClientUrl: typeof setClientUrl
setThornodeRpcUrl: typeof setThornodeRpcUrl
setThornodeApiUrl: typeof setThornodeApiUrl
address$: typeof address$
addressUI$: typeof addressUI$
reloadBalances: typeof reloadBalances
Expand All @@ -56,7 +58,8 @@ const initialContext: ThorchainContextValue = {
client$,
clientState$,
clientUrl$,
setClientUrl,
setThornodeRpcUrl,
setThornodeApiUrl,
address$,
addressUI$,
reloadBalances,
Expand Down
17 changes: 9 additions & 8 deletions src/renderer/hooks/useThorchainClientUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ import * as RxOp from 'rxjs/operators'

import { Network } from '../../shared/api/types'
import { useThorchainContext } from '../contexts/ThorchainContext'
import { INITIAL_CLIENT_URL } from '../services/thorchain/const'
import { DEFAULT_CLIENT_URL } from '../services/thorchain/const'
import { Configuration, HealthApi } from '../types/generated/thornode'
import { useNetwork } from './useNetwork'

export const useThorchainClientUrl = () => {
const { clientUrl$, setClientUrl } = useThorchainContext()
const { clientUrl$, setThornodeRpcUrl, setThornodeApiUrl } = useThorchainContext()
const { network } = useNetwork()
const intl = useIntl()

Expand All @@ -27,19 +27,20 @@ export const useThorchainClientUrl = () => {
RxOp.map(([clientUrl, network]) => clientUrl[network]),
RxOp.shareReplay(1)
),
INITIAL_CLIENT_URL[network]
DEFAULT_CLIENT_URL[network]
)

// To update `useObservableState` properly
// to push latest `network` into `nodeUrl`
useEffect(() => networkUpdated(network), [network, networkUpdated])

const setRpc = (url: string) => setClientUrl({ url, network, type: 'rpc' })
const setNode = (url: string) => setClientUrl({ url, network, type: 'node' })
const setRpc = (url: string) => setThornodeRpcUrl(url, network)
const setNode = (url: string) => setThornodeApiUrl(url, network)

const checkNode$ = (url: string) =>
FP.pipe(
// Check `ping` endpoint
// Check `ping` endpoint of THORNode REST API
// https://thornode.ninerealms.com/thorchain/doc/
new HealthApi(new Configuration({ basePath: url })).ping(),
RxOp.map((result) => {
const { ping } = result
Expand All @@ -56,7 +57,7 @@ export const useThorchainClientUrl = () => {

const checkRpc$ = (url: string) =>
FP.pipe(
// Check `health` endpoint
// Check `health` endpoint of THORNode RPC API
// https://docs.tendermint.com/v0.34/rpc/#/Info/health
RxAjax.ajax(`${url}/health`),
RxOp.map(({ response }) => {
Expand All @@ -70,7 +71,7 @@ export const useThorchainClientUrl = () => {
}),

RxOp.catchError((_: Error) =>
Rx.of(RD.failure(Error(`${intl.formatMessage({ id: 'thornode.url.error.invalid' })}`)))
Rx.of(RD.failure(Error(`${intl.formatMessage({ id: 'setting.thornode.rpc.error.url' })}`)))
)
)

Expand Down
6 changes: 3 additions & 3 deletions src/renderer/services/midgard/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const getMidgardUrl$ = FP.pipe(
RxOp.map(([storage]) =>
FP.pipe(
storage,
O.map(({ midgardUrls }) => midgardUrls),
O.map(({ midgard: midgardUrls }) => midgardUrls),
O.getOrElse(() => DEFAULT_MIDGARD_URLS)
)
),
Expand All @@ -58,7 +58,7 @@ const getMidgardUrl$ = FP.pipe(
const getMidgardUrl = (): ApiUrls =>
FP.pipe(
getStorageState(),
O.map(({ midgardUrls }) => midgardUrls),
O.map(({ midgard: midgardUrls }) => midgardUrls),
O.getOrElse(() => DEFAULT_MIDGARD_URLS)
)

Expand All @@ -67,7 +67,7 @@ const getMidgardUrl = (): ApiUrls =>
*/
const setMidgardUrl = (url: string, network: Network) => {
const midgardUrls = { ...getMidgardUrl(), [network]: url }
modifyStorage(O.some({ midgardUrls }))
modifyStorage(O.some({ midgard: midgardUrls }))
}

/**
Expand Down
79 changes: 66 additions & 13 deletions src/renderer/services/thorchain/common.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,72 @@
import * as RD from '@devexperts/remote-data-ts'
import { Client, ClientUrl, getChainId } from '@xchainjs/xchain-thorchain'
import { Network as ClientNetwork } from '@xchainjs/xchain-client'
import { Client, getChainId } from '@xchainjs/xchain-thorchain'
import { THORChain } from '@xchainjs/xchain-util'
import * as FP from 'fp-ts/lib/function'
import * as O from 'fp-ts/lib/Option'
import * as Rx from 'rxjs'
import * as RxOp from 'rxjs/operators'

import { Network } from '../../../shared/api/types'
import { toClientNetwork } from '../../../shared/utils/client'
import { ApiUrls, Network } from '../../../shared/api/types'
import { DEFAULT_THORNODE_API_URLS, DEFAULT_THORNODE_RPC_URLS } from '../../../shared/thorchain/const'
import { isError } from '../../../shared/utils/guard'
import { observableState } from '../../helpers/stateHelper'
import { triggerStream } from '../../helpers/stateHelper'
import { clientNetwork$ } from '../app/service'
import * as C from '../clients'
import { getStorageState, getStorageState$, modifyStorage } from '../storage/common'
import { keystoreService } from '../wallet/keystore'
import { getPhrase } from '../wallet/util'
import { INITIAL_CHAIN_IDS, INITIAL_CLIENT_URL } from './const'
import { Client$, ClientState, ClientState$, NodeUrlType } from './types'
import { INITIAL_CHAIN_IDS, DEFAULT_CLIENT_URL } from './const'
import { Client$, ClientState, ClientState$, ClientUrl$ } from './types'

const { get$: clientUrl$, get: getClientUrl, set: _setClientUrl } = observableState<ClientUrl>(INITIAL_CLIENT_URL)
// `TriggerStream` to reload ClientUrl
const { stream$: reloadClientUrl$, trigger: reloadClientUrl } = triggerStream()

const setClientUrl = ({ url, network, type }: { url: string; network: Network; type: NodeUrlType }) => {
// TODO(@veado) Store data persistent on disc
const current = getClientUrl()
const cNetwork = toClientNetwork(network)
_setClientUrl({ ...current, [cNetwork]: { ...current[cNetwork], [type]: url } })
/**
* Stream of ClientUrl (from storage)
*/
const clientUrl$: ClientUrl$ = FP.pipe(
Rx.combineLatest([getStorageState$, reloadClientUrl$]),
RxOp.map(([storage]) =>
FP.pipe(
storage,
O.map(({ thornodeApi, thornodeRpc }) => ({
[ClientNetwork.Testnet]: {
node: thornodeApi.testnet,
rpc: thornodeRpc.testnet
},
[ClientNetwork.Stagenet]: {
node: thornodeApi.stagenet,
rpc: thornodeRpc.stagenet
},
[ClientNetwork.Mainnet]: {
node: thornodeApi.mainnet,
rpc: thornodeRpc.mainnet
}
})),
O.getOrElse(() => DEFAULT_CLIENT_URL)
)
)
)

const setThornodeRpcUrl = (url: string, network: Network) => {
const current = FP.pipe(
getStorageState(),
O.map(({ thornodeRpc }) => thornodeRpc),
O.getOrElse(() => DEFAULT_THORNODE_RPC_URLS)
)
const updated: ApiUrls = { ...current, [network]: url }
modifyStorage(O.some({ thornodeRpc: updated }))
}

const setThornodeApiUrl = (url: string, network: Network) => {
const current = FP.pipe(
getStorageState(),
O.map(({ thornodeApi }) => thornodeApi),
O.getOrElse(() => DEFAULT_THORNODE_API_URLS)
)
const updated: ApiUrls = { ...current, [network]: url }
modifyStorage(O.some({ thornodeApi: updated }))
}

/**
Expand Down Expand Up @@ -89,4 +132,14 @@ const addressUI$: C.WalletAddress$ = C.addressUI$(client$, THORChain)
*/
const explorerUrl$: C.ExplorerUrl$ = C.explorerUrl$(client$)

export { client$, clientState$, clientUrl$, setClientUrl, address$, addressUI$, explorerUrl$ }
export {
client$,
clientState$,
clientUrl$,
reloadClientUrl,
setThornodeRpcUrl,
setThornodeApiUrl,
address$,
addressUI$,
explorerUrl$
}
35 changes: 14 additions & 21 deletions src/renderer/services/thorchain/const.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as RD from '@devexperts/remote-data-ts'
import { Network } from '@xchainjs/xchain-client'
import { ChainIds, ClientUrl, getDefaultClientUrl } from '@xchainjs/xchain-thorchain'
import { ChainIds, ClientUrl } from '@xchainjs/xchain-thorchain'

import { envOrDefault } from '../../../shared/utils/env'
import { DEFAULT_THORNODE_API_URLS, DEFAULT_THORNODE_RPC_URLS } from '../../../shared/thorchain/const'
import { InteractState, MimirHalt } from './types'

export const INITIAL_INTERACT_STATE: InteractState = {
Expand Down Expand Up @@ -47,24 +47,17 @@ export const INITIAL_CHAIN_IDS: ChainIds = {
[Network.Testnet]: 'unkown-testnet-chain-id'
}

const getInitClientUrl = (): ClientUrl => {
const { node: nodeTestnet, rpc: rpcTestnet } = getDefaultClientUrl()[Network.Testnet]
const { node: nodeStagenet, rpc: rpcStagenet } = getDefaultClientUrl()[Network.Stagenet]
const { node: nodeMainnet, rpc: rpcMainnet } = getDefaultClientUrl()[Network.Mainnet]
return {
[Network.Testnet]: {
node: envOrDefault(process.env.REACT_APP_TESTNET_THORNODE_API, nodeTestnet),
rpc: envOrDefault(process.env.REACT_APP_TESTNET_THORNODE_RPC, rpcTestnet)
},
[Network.Stagenet]: {
node: envOrDefault(process.env.REACT_APP_STAGENET_THORNODE_API, nodeStagenet),
rpc: envOrDefault(process.env.REACT_APP_STAGENET_THORNODE_RPC, rpcStagenet)
},
[Network.Mainnet]: {
node: envOrDefault(process.env.REACT_APP_MAINNET_THORNODE_API, nodeMainnet),
rpc: envOrDefault(process.env.REACT_APP_MAINNET_THORNODE_RPC, rpcMainnet)
}
export const DEFAULT_CLIENT_URL: ClientUrl = {
[Network.Testnet]: {
node: DEFAULT_THORNODE_API_URLS.testnet,
rpc: DEFAULT_THORNODE_RPC_URLS.testnet
},
[Network.Stagenet]: {
node: DEFAULT_THORNODE_API_URLS.stagenet,
rpc: DEFAULT_THORNODE_RPC_URLS.stagenet
},
[Network.Mainnet]: {
node: DEFAULT_THORNODE_API_URLS.mainnet,
rpc: DEFAULT_THORNODE_RPC_URLS.mainnet
}
}

export const INITIAL_CLIENT_URL: ClientUrl = getInitClientUrl()
16 changes: 14 additions & 2 deletions src/renderer/services/thorchain/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,17 @@ import { THORChain } from '@xchainjs/xchain-util'

import { network$ } from '../app/service'
import { reloadBalances, balances$, getBalanceByAddress$, reloadBalances$, resetReloadBalances } from './balances'
import { client$, clientState$, address$, addressUI$, explorerUrl$, clientUrl$, setClientUrl } from './common'
import {
client$,
clientState$,
address$,
addressUI$,
explorerUrl$,
clientUrl$,
reloadClientUrl,
setThornodeRpcUrl,
setThornodeApiUrl
} from './common'
import { createFeesService } from './fees'
import { createInteractService$ } from './interact'
import {
Expand All @@ -27,7 +37,9 @@ export {
client$,
clientState$,
clientUrl$,
setClientUrl,
reloadClientUrl,
setThornodeRpcUrl,
setThornodeApiUrl,
address$,
addressUI$,
explorerUrl$,
Expand Down
1 change: 0 additions & 1 deletion src/renderer/services/thorchain/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ export type Client$ = C.Client$<Client>
export type ClientState = C.ClientState<Client>
export type ClientState$ = C.ClientState$<Client>

export type NodeUrlType = keyof NodeUrl
export type ClientUrl$ = Rx.Observable<ClientUrl>
export type ClientUrlLD = LiveData<Error, ClientUrl>
export type ClientUrlRD = RD.RemoteData<Error, ClientUrl>
Expand Down
8 changes: 7 additions & 1 deletion src/shared/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,13 @@ export type StorageVersion = { version: string }
export type ApiUrls = Record<Network, string>
export type UserNodesStorage = Readonly<Record<Network, Address[]> & StorageVersion>
export type CommonStorage = Readonly<
{ locale: Locale; ethDerivationMode: EthHDMode; midgardUrls: ApiUrls } & StorageVersion
{
locale: Locale
ethDerivationMode: EthHDMode
midgard: ApiUrls
thornodeRpc: ApiUrls
thornodeApi: ApiUrls
} & StorageVersion
>

/**
Expand Down
5 changes: 4 additions & 1 deletion src/shared/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { StoreFilesContent, UserNodesStorage } from './api/types'
import { DEFAULT_ETH_HD_MODE } from './ethereum/const'
import { DEFAULT_LOCALE } from './i18n/const'
import { DEFAULT_MIDGARD_URLS } from './midgard/const'
import { DEFAULT_THORNODE_API_URLS, DEFAULT_THORNODE_RPC_URLS } from './thorchain/const'

export enum ExternalUrl {
DOCS = 'https://docs.thorchain.org',
Expand Down Expand Up @@ -45,7 +46,9 @@ export const DEFAULT_STORAGES: StoreFilesContent = {
version: COMMON_STORAGE_VERSION,
ethDerivationMode: DEFAULT_ETH_HD_MODE,
locale: DEFAULT_LOCALE,
midgardUrls: DEFAULT_MIDGARD_URLS
midgard: DEFAULT_MIDGARD_URLS,
thornodeApi: DEFAULT_THORNODE_API_URLS,
thornodeRpc: DEFAULT_THORNODE_RPC_URLS
},
userNodes: USER_NODES_STORAGE_DEFAULT,
pools: POOLS_STORAGE_DEFAULT
Expand Down
12 changes: 11 additions & 1 deletion src/shared/mock/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,21 @@ export const apiHDWallet: ApiHDWallet = {
const commonStorageData: CommonStorage = {
locale: Locale.EN,
ethDerivationMode: 'metamask',
midgardUrls: {
midgard: {
mainnet: 'midgard-url-mainnet',
stagenet: 'midgard-url-stagenet',
testnet: 'midgard-url-testnet'
},
thornodeRpc: {
mainnet: 'thornode-rpc-mainnet',
stagenet: 'thornode-rpc-stagenet',
testnet: 'thornode-rpc-testnet'
},
thornodeApi: {
mainnet: 'thornode-api-mainnet',
stagenet: 'thornode-api-stagenet',
testnet: 'thornode-api-testnet'
},
version: '1'
}

Expand Down
17 changes: 17 additions & 0 deletions src/shared/thorchain/const.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { ApiUrls } from '../api/types'
import { envOrDefault } from '../utils/env'

// expose env (needed to access ENVs by `envOrDefault`) in `main` thread)
require('dotenv').config()

export const DEFAULT_THORNODE_RPC_URLS: ApiUrls = {
mainnet: envOrDefault(process.env.REACT_APP_MAINNET_THORNODE_RPC, 'https://rpc.ninerealms.com'),
stagenet: envOrDefault(process.env.REACT_APP_STAGENET_THORNODE_RPC, 'https://stagenet-rpc.ninerealms.com'),
testnet: envOrDefault(process.env.REACT_APP_TESTNET_THORNODE_RPC, 'https://rpc.ninerealms.com')
}

export const DEFAULT_THORNODE_API_URLS: ApiUrls = {
mainnet: envOrDefault(process.env.REACT_APP_MAINNET_THORNODE_API, 'https://thornode.ninerealms.com'),
stagenet: envOrDefault(process.env.REACT_APP_STAGENET_THORNODE_API, 'https://stagenet-thornode.ninerealms.com'),
testnet: envOrDefault(process.env.REACT_APP_TESTNET_THORNODE_API, 'https://testnet.thornode.thorchain.info')
}

0 comments on commit 10ee942

Please sign in to comment.