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

Move handling of LastBlock from Midgard to THORNode #2419

Merged
merged 1 commit into from
Oct 8, 2022
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
19 changes: 2 additions & 17 deletions src/renderer/components/header/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import React from 'react'

import * as RD from '@devexperts/remote-data-ts'
import * as FP from 'fp-ts/lib/function'
import * as O from 'fp-ts/lib/Option'
import { useObservableState } from 'observable-hooks'

import { useMidgardContext } from '../../contexts/MidgardContext'
import { useThorchainContext } from '../../contexts/ThorchainContext'
import { liveData } from '../../helpers/rx/liveData'
import { useKeystoreState } from '../../hooks/useKeystoreState'
import { useKeystoreWallets } from '../../hooks/useKeystoreWallets'
import { useNetwork } from '../../hooks/useNetwork'
Expand All @@ -27,7 +25,7 @@ export const Header: React.FC = (): JSX.Element => {
const {
pools: { setSelectedPricePoolAsset: setSelectedPricePool, selectedPricePoolAsset$ },
apiEndpoint$,
thorchainLastblockState$
healthStatus$
} = midgardService

const { network } = useNetwork()
Expand All @@ -39,20 +37,7 @@ export const Header: React.FC = (): JSX.Element => {

const pricePools = usePricePools()

/**
* Midgard status is currently based on requests to check last block
* This request happens on a regular basis and give us a feedback whether Midgard is available
*
* TODO(@veado) Use Midgards `health` endpoint to get a better status
*/
const [midgardStatusRD] = useObservableState(
() =>
FP.pipe(
thorchainLastblockState$,
liveData.map((_) => true)
),
RD.initial
)
const midgardStatusRD = useObservableState(healthStatus$, RD.initial)

const midgardUrlRD = useObservableState(apiEndpoint$, RD.initial)
const { node: thorchainNodeUrl, rpc: thorchainRpcUrl } = useThorchainClientUrl()
Expand Down
6 changes: 6 additions & 0 deletions src/renderer/contexts/ThorchainContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import {
reloadInboundAddresses,
reloadThorchainConstants,
thorchainConstantsState$,
thorchainLastblockState$,
reloadThorchainLastblock,
getLiquidityProviders,
reloadLiquidityProviders
} from '../services/thorchain'
Expand Down Expand Up @@ -58,6 +60,8 @@ export type ThorchainContextValue = {
reloadInboundAddresses: typeof reloadInboundAddresses
thorchainConstantsState$: typeof thorchainConstantsState$
reloadThorchainConstants: typeof reloadThorchainConstants
thorchainLastblockState$: typeof thorchainLastblockState$
reloadThorchainLastblock: typeof reloadThorchainLastblock
getLiquidityProviders: typeof getLiquidityProviders
reloadLiquidityProviders: typeof reloadLiquidityProviders
}
Expand Down Expand Up @@ -89,6 +93,8 @@ const initialContext: ThorchainContextValue = {
reloadInboundAddresses,
reloadThorchainConstants,
thorchainConstantsState$,
thorchainLastblockState$,
reloadThorchainLastblock,
getLiquidityProviders,
reloadLiquidityProviders
}
Expand Down
7 changes: 1 addition & 6 deletions src/renderer/hooks/useMimirHalt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { useObservableState } from 'observable-hooks'
import * as Rx from 'rxjs'
import * as RxOp from 'rxjs/operators'

import { useMidgardContext } from '../contexts/MidgardContext'
import { useThorchainContext } from '../contexts/ThorchainContext'
import { sequenceTRD } from '../helpers/fpHelpers'
import { DEFAULT_MIMIR_HALT } from '../services/thorchain/const'
Expand All @@ -33,11 +32,7 @@ export const getMimirStatus = (mimir = 0, lastHeight = 0) => {
* Note: Same rule as we have for services - Use this hook in top level *views only (but in child components)
*/
export const useMimirHalt = (): { mimirHaltRD: MimirHaltRD; mimirHalt: MimirHalt } => {
const { mimir$ } = useThorchainContext()

const {
service: { thorchainLastblockState$ }
} = useMidgardContext()
const { mimir$, thorchainLastblockState$ } = useThorchainContext()

const [mimirHaltRD] = useObservableState<MimirHaltRD>(
() =>
Expand Down
72 changes: 22 additions & 50 deletions src/renderer/services/midgard/service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import * as RD from '@devexperts/remote-data-ts'
import * as FP from 'fp-ts/function'
import * as O from 'fp-ts/Option'
import { IntlShape } from 'react-intl'
import * as Rx from 'rxjs'
import * as RxOp from 'rxjs/operators'

Expand All @@ -24,11 +23,11 @@ import {
NetworkInfoRD,
NetworkInfoLD,
MidgardUrlLD,
ThorchainLastblockLD,
HealthLD,
ValidateNodeLD,
CheckMidgardUrlHandler,
SelectedPoolAsset
SelectedPoolAsset,
MidgardStatusLD
} from './types'

// `TriggerStream` to reload Midgard
Expand Down Expand Up @@ -80,46 +79,6 @@ const midgardUrl$: MidgardUrlLD = Rx.combineLatest([network$, getMidgardUrl$]).p
RxOp.shareReplay(1)
)

/**
* Get `ThorchainLastblock` data from Midgard
*/
const apiGetThorchainLastblock$ = midgardUrl$.pipe(
liveData.chain((endpoint) =>
FP.pipe(
getMidgardDefaultApi(endpoint).getProxiedLastblock(),
RxOp.map(RD.success),
RxOp.catchError((e: Error) => Rx.of(RD.failure(e)))
)
)
)

// `TriggerStream` to reload data of `ThorchainLastblock`
const { stream$: reloadThorchainLastblock$, trigger: reloadThorchainLastblock } = triggerStream()

/**
* Loads data of `ThorchainLastblock`
*/
const loadThorchainLastblock$ = () =>
apiGetThorchainLastblock$.pipe(
// catch any errors if there any
RxOp.catchError((error: Error) => Rx.of(RD.failure(error))),
RxOp.startWith(RD.pending),
RxOp.retry(MIDGARD_MAX_RETRY)
)

const loadThorchainLastblockInterval$ = Rx.timer(0 /* no delay for first value */, 15 * 1000 /* every 15 sec */)

/**
* State of `ThorchainLastblock`, it will be loaded data by first subscription only
*/
const thorchainLastblockState$: ThorchainLastblockLD = FP.pipe(
Rx.combineLatest([reloadThorchainLastblock$, loadThorchainLastblockInterval$]),
// start request
RxOp.switchMap((_) => loadThorchainLastblock$()),
// cache it to avoid reloading data by every subscription
RxOp.shareReplay(1)
)

/**
* Loads data of `NetworkInfo`
*/
Expand Down Expand Up @@ -175,25 +134,38 @@ const validateNode$ = (): ValidateNodeLD =>
// `TriggerStream` to reload chart data handled on view (not service) level only
export const { stream$: reloadChartDataUI$, trigger: reloadChartDataUI } = triggerStream()

export const checkMidgardUrl$: CheckMidgardUrlHandler = (url: string, intl: IntlShape) =>
export const checkMidgardUrl$: CheckMidgardUrlHandler = (url, intl) =>
FP.pipe(
getMidgardDefaultApi(url).getHealth(),
RxOp.map((result) => {
const { database, inSync } = result
if (database && inSync) return RD.success(url)

return RD.failure(Error(intl.formatMessage({ id: 'midgard.url.error.unhealthy' }, { endpoint: '/health' })))
return RD.failure(
Error(
intl?.formatMessage({ id: 'midgard.url.error.unhealthy' }, { endpoint: '/health' }) || 'Midgard is unhealthy'
)
)
}),
RxOp.catchError((_: Error) =>
Rx.of(RD.failure(Error(`${intl.formatMessage({ id: 'midgard.url.error.invalid' })}`)))
Rx.of(
RD.failure(Error(`${intl?.formatMessage({ id: 'midgard.url.error.invalid' })} || 'Midgard can't be accessed'`))
)
)
)

const healthInterval$ = Rx.timer(0 /* no delay for first value */, 5 * 60 * 1000 /* others are delayed by 5 min */)

const healthStatus$: MidgardStatusLD = FP.pipe(
Rx.combineLatest([midgardUrl$, healthInterval$]),
RxOp.map(([urlRD, _]) => urlRD),
liveData.chain((url) => checkMidgardUrl$(url)),
liveData.map((_) => true)
)

export type MidgardService = {
networkInfo$: NetworkInfoLD
reloadNetworkInfo: FP.Lazy<void>
thorchainLastblockState$: ThorchainLastblockLD
reloadThorchainLastblock: FP.Lazy<void>
setSelectedPoolAsset: (p: SelectedPoolAsset) => void
selectedPoolAsset$: Rx.Observable<SelectedPoolAsset>
reloadChartDataUI: FP.Lazy<void>
Expand All @@ -205,6 +177,7 @@ export type MidgardService = {
pools: ReturnType<typeof createPoolsService>
shares: ReturnType<typeof createSharesService>
actions: ReturnType<typeof createActionsService>
healthStatus$: MidgardStatusLD
validateNode$: () => ValidateNodeLD
}
/**
Expand All @@ -213,8 +186,6 @@ export type MidgardService = {
export const service: MidgardService = {
networkInfo$,
reloadNetworkInfo,
thorchainLastblockState$,
reloadThorchainLastblock,
reloadChartDataUI,
reloadChartDataUI$,
setSelectedPoolAsset,
Expand All @@ -223,6 +194,7 @@ export const service: MidgardService = {
reloadApiEndpoint: reloadMidgardUrl,
setMidgardUrl,
checkMidgardUrl$,
healthStatus$,
validateNode$,
pools: createPoolsService({
midgardUrl$,
Expand Down
8 changes: 2 additions & 6 deletions src/renderer/services/midgard/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { LiveData } from '../../helpers/rx/liveData'
import { AssetWithAmount, DepositType } from '../../types/asgardex'
import {
Network as NetworkInfo,
LastblockItem,
PoolDetail,
Health,
PoolStatsDetail,
Expand Down Expand Up @@ -94,10 +93,6 @@ export type PriceRD = RD.RemoteData<Error, AssetWithAmount>
export type MidgardStatusRD = RD.RemoteData<Error, boolean>
export type MidgardStatusLD = LiveData<Error, boolean>

export type LastblockItems = LastblockItem[]
export type ThorchainLastblockRD = RD.RemoteData<Error, LastblockItems>
export type ThorchainLastblockLD = LiveData<Error, LastblockItems>

export type HaltedChainsRD = RD.RemoteData<Error, Chain[]>
export type HaltedChainsLD = LiveData<Error, Chain[]>

Expand Down Expand Up @@ -159,7 +154,8 @@ export type NetworkInfoLD = LiveData<Error, NetworkInfo>
export type MidgardUrlRD = RD.RemoteData<Error, string>
export type MidgardUrlLD = LiveData<Error, string>

export type CheckMidgardUrlHandler = (url: string, intl: IntlShape) => LiveData<Error, string>
export type CheckMidgardUrlLD = LiveData<Error, string>
export type CheckMidgardUrlHandler = (url: string, intl?: IntlShape) => CheckMidgardUrlLD

export type HealthRD = RD.RemoteData<Error, Health>
export type HealthLD = LiveData<Error, Health>
Expand Down
4 changes: 4 additions & 0 deletions src/renderer/services/thorchain/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ const {
reloadNodeInfos,
reloadThorchainConstants,
thorchainConstantsState$,
thorchainLastblockState$,
reloadThorchainLastblock,
inboundAddressesShared$,
loadInboundAddresses$,
reloadInboundAddresses,
Expand Down Expand Up @@ -77,6 +79,8 @@ export {
reloadNodeInfos,
reloadThorchainConstants,
thorchainConstantsState$,
thorchainLastblockState$,
reloadThorchainLastblock,
mimir$,
reloadMimir,
getLiquidityProviders,
Expand Down
45 changes: 44 additions & 1 deletion src/renderer/services/thorchain/thornode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ import {
NodeInfos,
ClientUrl$,
InboundAddressesLD,
ThorchainConstantsLD
ThorchainConstantsLD,
ThorchainLastblockLD
} from './types'

export const createThornodeService$ = (network$: Network$, clientUrl$: ClientUrl$) => {
Expand Down Expand Up @@ -125,6 +126,46 @@ export const createThornodeService$ = (network$: Network$, clientUrl$: ClientUrl
RxOp.catchError(() => Rx.of(RD.failure(Error('Failed to load THORChain constants'))))
)

/**
* Api call to `lastblock` endpoint
*/
const apiGetThorchainLastblock$ = FP.pipe(
thornodeUrl$,
liveData.chain((basePath) =>
FP.pipe(
new NetworkApi(new Configuration({ basePath })).lastblock({}),
RxOp.map(RD.success),
RxOp.catchError((e: Error) => Rx.of(RD.failure(e)))
)
)
)

// `TriggerStream` to reload data of `ThorchainLastblock`
const { stream$: reloadThorchainLastblock$, trigger: reloadThorchainLastblock } = triggerStream()

/**
* Loads data of `lastblock`
*/
const loadThorchainLastblock$ = () =>
apiGetThorchainLastblock$.pipe(
// catch any errors if there any
RxOp.catchError((error: Error) => Rx.of(RD.failure(error))),
RxOp.startWith(RD.pending)
)

const loadThorchainLastblockInterval$ = Rx.timer(0 /* no delay for first value */, 15 * 1000 /* every 15 sec */)

/**
* State of `ThorchainLastblock`, it will be loaded data by first subscription only
*/
const thorchainLastblockState$: ThorchainLastblockLD = FP.pipe(
Rx.combineLatest([reloadThorchainLastblock$, loadThorchainLastblockInterval$]),
// start request
RxOp.switchMap((_) => loadThorchainLastblock$()),
// cache it to avoid reloading data by every subscription
RxOp.shareReplay(1)
)

const { stream$: reloadNodeInfos$, trigger: reloadNodeInfos } = triggerStream()

const getNodeInfos$: NodeInfosLD = FP.pipe(
Expand Down Expand Up @@ -233,6 +274,8 @@ export const createThornodeService$ = (network$: Network$, clientUrl$: ClientUrl
reloadNodeInfos,
reloadThorchainConstants,
thorchainConstantsState$,
thorchainLastblockState$,
reloadThorchainLastblock,
inboundAddressesShared$,
reloadInboundAddresses,
loadInboundAddresses$,
Expand Down
6 changes: 3 additions & 3 deletions src/renderer/services/thorchain/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ export type InboundAddressesLD = LiveData<Error, InboundAddresses>
export type ThorchainConstantsRD = RD.RemoteData<Error, ConstantsResponse>
export type ThorchainConstantsLD = LiveData<Error, ConstantsResponse>

export type NativeFee = O.Option<BaseAmount>
export type NativeFeeRD = RD.RemoteData<Error, NativeFee>
export type NativeFeeLD = LiveData<Error, NativeFee>
export type LastblockItems = TN.LastBlock[]
export type ThorchainLastblockRD = RD.RemoteData<Error, LastblockItems>
export type ThorchainLastblockLD = LiveData<Error, LastblockItems>

export type Client$ = C.Client$<Client>

Expand Down
7 changes: 5 additions & 2 deletions src/renderer/views/pools/PendingPools.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { ProtocolLimit, IncentivePendulum } from '../../components/pool'
import { Table } from '../../components/uielements/table'
import { useAppContext } from '../../contexts/AppContext'
import { useMidgardContext } from '../../contexts/MidgardContext'
import { useThorchainContext } from '../../contexts/ThorchainContext'
import * as PoolHelpers from '../../helpers/poolHelper'
import { getPoolTableRowsData, RUNE_PRICE_POOL } from '../../helpers/poolHelper'
import { useIncentivePendulum } from '../../hooks/useIncentivePendulum'
Expand All @@ -27,7 +28,8 @@ import { usePoolWatchlist } from '../../hooks/usePoolWatchlist'
import { useProtocolLimit } from '../../hooks/useProtocolLimit'
import * as poolsRoutes from '../../routes/pools'
import { DEFAULT_NETWORK } from '../../services/const'
import { PendingPoolsState, DEFAULT_POOL_FILTERS, ThorchainLastblockRD } from '../../services/midgard/types'
import { PendingPoolsState, DEFAULT_POOL_FILTERS } from '../../services/midgard/types'
import { ThorchainLastblockRD } from '../../services/thorchain/types'
import { PoolDetail } from '../../types/generated/midgard'
import { PoolsComponentProps, PoolTableRowData, PoolTableRowsData } from './Pools.types'
import { getBlocksLeftForPendingPoolAsString, isEmptyPool } from './Pools.utils'
Expand All @@ -45,11 +47,12 @@ export const PendingPools: React.FC<PoolsComponentProps> = ({ haltedChains, mimi

const {
service: {
thorchainLastblockState$,
pools: { pendingPoolsState$, reloadPendingPools, selectedPricePool$ }
}
} = useMidgardContext()

const { thorchainLastblockState$ } = useThorchainContext()

const { setFilter: setPoolFilter, filter: poolFilter } = usePoolFilter('pending')
const { add: addPoolToWatchlist, remove: removePoolFromWatchlist, list: poolWatchList } = usePoolWatchlist()

Expand Down
2 changes: 1 addition & 1 deletion src/renderer/views/pools/Pools.util.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import * as O from 'fp-ts/lib/Option'
import { ASSETS_TESTNET, ERC20_TESTNET } from '../../../shared/mock/assets'
import { AssetUSDTERC20Testnet } from '../../const'
import { eqBaseAmount } from '../../helpers/fp/eq'
import { LastblockItems } from '../../services/midgard/types'
import { LastblockItems } from '../../services/thorchain/types'
import { PoolDetail } from '../../types/generated/midgard'
import { GetPoolsStatusEnum } from '../../types/generated/midgard'
import { PoolTableRowData } from './Pools.types'
Expand Down