diff --git a/api/resolvers/blockHeight.js b/api/resolvers/blockHeight.js
new file mode 100644
index 00000000..4fd270d9
--- /dev/null
+++ b/api/resolvers/blockHeight.js
@@ -0,0 +1,37 @@
+import lndService from 'ln-service'
+import lnd from '../lnd'
+
+const cache = new Map()
+const expiresIn = 1000 * 30 // 30 seconds in milliseconds
+
+async function fetchBlockHeight () {
+ let blockHeight = 0
+ try {
+ const height = await lndService.getHeight({ lnd })
+ blockHeight = height.current_block_height
+ } catch (err) {
+ console.error('fetchBlockHeight', err)
+ }
+ cache.set('block', { height: blockHeight, createdAt: Date.now() })
+ return blockHeight
+}
+
+async function getBlockHeight () {
+ if (cache.has('block')) {
+ const { height, createdAt } = cache.get('block')
+ const expired = createdAt + expiresIn < Date.now()
+ if (expired) fetchBlockHeight().catch(console.error) // update cache
+ return height // serve stale block height (this on the SSR critical path)
+ } else {
+ fetchBlockHeight().catch(console.error)
+ }
+ return 0
+}
+
+export default {
+ Query: {
+ blockHeight: async (parent, opts, ctx) => {
+ return await getBlockHeight()
+ }
+ }
+}
diff --git a/api/resolvers/index.js b/api/resolvers/index.js
index aaf74143..f0b311ac 100644
--- a/api/resolvers/index.js
+++ b/api/resolvers/index.js
@@ -14,6 +14,7 @@ import referrals from './referrals'
import price from './price'
import { GraphQLJSONObject as JSONObject } from 'graphql-type-json'
import admin from './admin'
+import blockHeight from './blockHeight'
import { GraphQLScalarType, Kind } from 'graphql'
const date = new GraphQLScalarType({
@@ -44,4 +45,4 @@ const date = new GraphQLScalarType({
})
export default [user, item, message, wallet, lnurl, notifications, invite, sub,
- upload, search, growth, rewards, referrals, price, admin, { JSONObject }, { Date: date }]
+ upload, search, growth, rewards, referrals, price, admin, blockHeight, { JSONObject }, { Date: date }]
diff --git a/api/ssrApollo.js b/api/ssrApollo.js
index af3a1dd0..74b55523 100644
--- a/api/ssrApollo.js
+++ b/api/ssrApollo.js
@@ -9,6 +9,7 @@ import lnd from './lnd'
import search from './search'
import { ME } from '../fragments/users'
import { PRICE } from '../fragments/price'
+import { BLOCK_HEIGHT } from '../fragments/blockHeight'
import { getServerSession } from 'next-auth/next'
import { getAuthOptions } from '../pages/api/auth/[...nextauth]'
@@ -92,6 +93,10 @@ export function getGetServerSideProps (
query: PRICE, variables: { fiatCurrency: me?.fiatCurrency }
})
+ const { data: { blockHeight } } = await client.query({
+ query: BLOCK_HEIGHT, variables: {}
+ })
+
let error = null; let data = null; let props = {}
if (query) {
try {
@@ -122,6 +127,7 @@ export function getGetServerSideProps (
...props,
me,
price,
+ blockHeight,
ssrData: data
}
}
diff --git a/api/typeDefs/blockHeight.js b/api/typeDefs/blockHeight.js
new file mode 100644
index 00000000..3ccebbff
--- /dev/null
+++ b/api/typeDefs/blockHeight.js
@@ -0,0 +1,7 @@
+import { gql } from 'graphql-tag'
+
+export default gql`
+ extend type Query {
+ blockHeight: Int!
+ }
+`
diff --git a/api/typeDefs/index.js b/api/typeDefs/index.js
index 65451e7e..fb7b39d2 100644
--- a/api/typeDefs/index.js
+++ b/api/typeDefs/index.js
@@ -15,6 +15,7 @@ import rewards from './rewards'
import referrals from './referrals'
import price from './price'
import admin from './admin'
+import blockHeight from './blockHeight'
const common = gql`
type Query {
@@ -34,4 +35,4 @@ const common = gql`
`
export default [common, user, item, itemForward, message, wallet, lnurl, notifications, invite,
- sub, upload, growth, rewards, referrals, price, admin]
+ sub, upload, growth, rewards, referrals, price, admin, blockHeight]
diff --git a/components/block-height.js b/components/block-height.js
new file mode 100644
index 00000000..6007ac98
--- /dev/null
+++ b/components/block-height.js
@@ -0,0 +1,29 @@
+import { createContext, useContext } from 'react'
+import { useQuery } from '@apollo/client'
+import { SSR } from '../lib/constants'
+import { BLOCK_HEIGHT } from '../fragments/blockHeight'
+
+export const BlockHeightContext = createContext({
+ height: 0
+})
+
+export const useBlockHeight = () => useContext(BlockHeightContext)
+
+export const BlockHeightProvider = ({ blockHeight, children }) => {
+ const { data } = useQuery(BLOCK_HEIGHT, {
+ ...(SSR
+ ? {}
+ : {
+ pollInterval: 30000,
+ nextFetchPolicy: 'cache-and-network'
+ })
+ })
+ const value = {
+ height: data?.blockHeight ?? blockHeight ?? 0
+ }
+ return (
+