Skip to content

Commit 5c0ec49

Browse files
authored
feat(Health): roll transactionAnchorRetryInfo into health collection (#878)
add a health check on the number of times it takes to get a transaction into the blockchain References #878, #832
1 parent 3224967 commit 5c0ec49

File tree

6 files changed

+96
-3
lines changed

6 files changed

+96
-3
lines changed

src/Health/Health.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { HealthController, HealthControllerConfiguration } from './HealthControl
1212
import { HealthDAO } from './HealthDAO'
1313
import { HealthService, HealthServiceConfiguration } from './HealthService'
1414
import { IPFS, IPFSConfiguration } from './IPFS'
15+
import { IPFSDirectoryHashDAO } from './IPFSDirectoryHashDAO'
1516
import { Router } from './Router'
1617

1718
export interface HealthConfiguration
@@ -60,6 +61,13 @@ export class Health {
6061
},
6162
})
6263

64+
const ipfsDirectoryHasDAO = new IPFSDirectoryHashDAO({
65+
dependencies: {
66+
ipfsDirectoryHashInfoCollection: this.ipfsDirectoryHashInfoCollection,
67+
},
68+
})
69+
await ipfsDirectoryHasDAO.start()
70+
6371
const bitcoinCore = new BitcoinCore({
6472
host: this.configuration.bitcoinUrl,
6573
port: this.configuration.bitcoinPort,
@@ -78,6 +86,7 @@ export class Health {
7886
dependencies: {
7987
logger: this.logger,
8088
healthDAO,
89+
ipfsDirectoryHasDAO,
8190
bitcoinCore,
8291
ipfs,
8392
},

src/Health/HealthController.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { childWithFileName } from 'Helpers/Logging'
66
import { IPFSHashFailure, ClaimIPFSHashPair } from 'Interfaces'
77

88
import { BlockchainInfo, WalletInfo, NetworkInfo, IPFSInfo, EstimatedSmartFeeInfo, HealthDAO } from './HealthDAO'
9+
import { TransactionAnchorRetryInfo, IPFSDirectoryHashDAO } from './IPFSDirectoryHashDAO'
910

1011
import { IPFS } from './IPFS'
1112

@@ -15,6 +16,10 @@ enum LogTypes {
1516
error = 'error',
1617
}
1718

19+
export interface HealthError {
20+
readonly error: string
21+
}
22+
1823
export interface HealthControllerConfiguration {
1924
readonly lowWalletBalanceInBitcoin: number
2025
readonly feeEstimateMinTargetBlock: number
@@ -40,6 +45,7 @@ export const isFailureHard = (failureType: string) => failureType === 'HARD'
4045

4146
export interface Dependencies {
4247
readonly healthDAO: HealthDAO
48+
readonly ipfsDirectoryHasDAO: IPFSDirectoryHashDAO
4349
readonly bitcoinCore: BitcoinCore
4450
readonly logger: Pino.Logger
4551
readonly ipfs: IPFS
@@ -53,6 +59,7 @@ export interface Arguments {
5359
export class HealthController {
5460
private readonly configuration: HealthControllerConfiguration
5561
private readonly healthDAO: HealthDAO
62+
private readonly ipfsDirectoryHashDAO: IPFSDirectoryHashDAO
5663
private readonly bitcoinCore: BitcoinCore
5764
private readonly logger: Pino.Logger
5865
private readonly ipfs: IPFS
@@ -61,6 +68,7 @@ export class HealthController {
6168
dependencies: {
6269
logger,
6370
healthDAO,
71+
ipfsDirectoryHasDAO,
6472
bitcoinCore,
6573
ipfs,
6674
},
@@ -119,6 +127,14 @@ export class HealthController {
119127
return estimatedSmartFeeInfo
120128
}
121129

130+
private async getTransactionAnchorRetryInfo(): Promise<TransactionAnchorRetryInfo | HealthError> {
131+
try {
132+
return await this.ipfsDirectoryHashDAO.getTransactionAnchorRetryInfo()
133+
} catch (e) {
134+
return { error: 'Error retrieving transactionAnchorRetryReport' }
135+
}
136+
}
137+
122138
private async checkIPFSConnection(): Promise<IPFSInfo> {
123139
try {
124140
const ipfsConnection = await this.ipfs.getVersion()
@@ -134,6 +150,13 @@ export class HealthController {
134150
return ipfsInfo
135151
}
136152

153+
private async updateTransactionAnchorRetryInfo(
154+
transactionAnchorRetryInfo: TransactionAnchorRetryInfo,
155+
): Promise<TransactionAnchorRetryInfo> {
156+
await this.healthDAO.updateTransactionAnchorRetryInfo(transactionAnchorRetryInfo)
157+
return transactionAnchorRetryInfo
158+
}
159+
137160
public async updateIPFSFailures(ipfsHashFailures: ReadonlyArray<IPFSHashFailure>) {
138161
this.logger.debug({ ipfsHashFailures }, 'Updating IPFS Failure Count by failureType')
139162
await ipfsHashFailures.map(
@@ -185,4 +208,13 @@ export class HealthController {
185208
this.updateIPFSInfo,
186209
this.log(LogTypes.trace)('refreshed IPFS info'),
187210
)
211+
212+
public refreshTransactionAnchorRetryInfo = pipeP(
213+
this.log(LogTypes.trace)('refreshing transaction anchor retry info'),
214+
this.getTransactionAnchorRetryInfo,
215+
this.log(LogTypes.trace)('new info gathered, saving transaction anchor retry info'),
216+
this.updateTransactionAnchorRetryInfo,
217+
this.log(LogTypes.trace)('refreshed transaction anchor retry info'),
218+
)
219+
188220
}

src/Health/HealthDAO.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Collection, Db } from 'mongodb'
2+
import { TransactionAnchorRetryInfo } from './IPFSDirectoryHashDAO'
23

34
export interface BlockchainInfo {
45
readonly blocks: number
@@ -42,6 +43,8 @@ type updateIPFSInfo = (x: IPFSInfo) => Promise<void>
4243

4344
type updateEstimatedSmartFeeInfo = (x: EstimatedSmartFeeInfo) => Promise<void>
4445

46+
type updateTransactionAnchorRetryInfo = (x: TransactionAnchorRetryInfo) => Promise<void>
47+
4548
export interface Dependencies {
4649
readonly db: Db
4750
}
@@ -121,6 +124,18 @@ export class HealthDAO {
121124
)
122125
}
123126

127+
readonly updateTransactionAnchorRetryInfo: updateTransactionAnchorRetryInfo = async transactionAnchorRetryInfo => {
128+
await this.collection.updateOne(
129+
{ name: 'transactionAnchorRetryInfo' },
130+
{
131+
$set: {
132+
transactionAnchorRetryInfo,
133+
},
134+
},
135+
{ upsert: true },
136+
)
137+
}
138+
124139
readonly increaseHardIPFSFailure = async (): Promise<void> => {
125140
await this.collection.updateOne(
126141
{ name: 'ipfsDownloadRetries' },

src/Health/HealthService.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Interval } from '@po.et/poet-js'
22
import * as Pino from 'pino'
33

44
import { childWithFileName } from 'Helpers/Logging'
5+
import { secondsToMiliseconds } from 'Helpers/Time'
56
import { Messaging } from 'Messaging/Messaging'
67

78
import { ExchangeConfiguration } from './ExchangeConfiguration'
@@ -39,7 +40,7 @@ export class HealthService {
3940
this.logger = childWithFileName(logger, __filename)
4041
this.configuration = configuration
4142
this.messaging = messaging
42-
this.interval = new Interval(this.getHealth, this.configuration.healthIntervalInSeconds * 1000)
43+
this.interval = new Interval(this.getHealth, secondsToMiliseconds(this.configuration.healthIntervalInSeconds))
4344
this.exchange = exchange
4445
}
4546

src/Health/IPFSDirectoryHashDAO.ts

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Collection } from 'mongodb'
2+
import { isNil } from 'ramda'
23

34
export interface UpdateAnchorAttemptInfo {
45
readonly ipfsDirectoryHash: string
@@ -7,6 +8,19 @@ export interface UpdateAnchorAttemptInfo {
78

89
type updateAnchorAttemptsInfo = (x: UpdateAnchorAttemptInfo) => Promise<void>
910

11+
export interface AnchorRetryDAOResult {
12+
readonly _id: number
13+
readonly count: number
14+
}
15+
16+
export interface TransactionAnchorRetryEntry {
17+
readonly attempts: number
18+
readonly count: number
19+
}
20+
21+
export type TransactionAnchorRetryInfo = ReadonlyArray<TransactionAnchorRetryEntry>
22+
export type getTransactionAnchorRetryInfo = () => Promise<TransactionAnchorRetryInfo>
23+
1024
export interface Dependencies {
1125
readonly ipfsDirectoryHashInfoCollection: Collection
1226
}
@@ -26,6 +40,11 @@ export class IPFSDirectoryHashDAO {
2640
this.ipfsDirectoryHashInfoCollection = ipfsDirectoryHashInfoCollection
2741
}
2842

43+
readonly start = async (): Promise<void> => {
44+
await this.ipfsDirectoryHashInfoCollection.createIndex({ ipofsDirectoryHash: 1 }, { unique: true })
45+
await this.ipfsDirectoryHashInfoCollection.createIndex({ txId: 1, attempts: 1 })
46+
}
47+
2948
readonly updateAnchorAttemptsInfo: updateAnchorAttemptsInfo = async anchorAttemptInfo => {
3049
await this.ipfsDirectoryHashInfoCollection.updateOne(
3150
{
@@ -35,9 +54,25 @@ export class IPFSDirectoryHashDAO {
3554
{
3655
$set: { txId: anchorAttemptInfo.txId },
3756
$inc: { attempts: 1 },
38-
$setOnInsert: { attempts: 1 },
3957
},
4058
{ upsert: true },
4159
)
4260
}
43-
}
61+
62+
readonly getTransactionAnchorRetryInfo: getTransactionAnchorRetryInfo = async () => {
63+
const cursorArray = await this.ipfsDirectoryHashInfoCollection.aggregate([
64+
{ $match: { attempts: { $ne: 1 } } },
65+
{ $group: { _id: '$attempts', count: { $sum: 1} } },
66+
]).toArray()
67+
68+
if (isNil(cursorArray)) return []
69+
70+
return cursorArray.map(
71+
(item: AnchorRetryDAOResult) => (
72+
{
73+
attempts: item._id,
74+
count: item.count,
75+
}
76+
),
77+
)
78+
}}

src/Health/Router.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export class Router {
5151
await this.controller.refreshNetworkInfo()
5252
await this.controller.refreshIPFSInfo()
5353
await this.controller.refreshEstimatedSmartFee()
54+
await this.controller.refreshTransactionAnchorRetryInfo()
5455
} catch (error) {
5556
logger.error({ error }, 'Failed to getHealthInfo')
5657
}

0 commit comments

Comments
 (0)