Skip to content

Commit 2571c79

Browse files
Merge pull request #533 from hop-protocol/feat/latency-optimization
Feat/latency optimization
2 parents b84ce57 + eafe2d7 commit 2571c79

14 files changed

+419
-778
lines changed

packages/hop-node/src/cli/bondWithdrawal.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ async function main (source: any) {
6464

6565
const txParams: SendBondWithdrawalTxParams = {
6666
transferId: dbTransfer.transferId,
67-
sender: dbTransfer.sender!,
6867
recipient: dbTransfer.recipient!,
6968
amount: dbTransfer.amount!,
7069
transferNonce: dbTransfer.transferNonce!,

packages/hop-node/src/cli/dbDump.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ async function main (source: any) {
7979
output.push(item || { transferRootId })
8080
}
8181
const filtered = output.map((x: any) => {
82-
const { transferRootId, transferRootHash, totalAmount, bonded, comitted, committedAt, confirmed, rootSetTimestamp, allSettled } = x
82+
const { transferRootId, transferRootHash, totalAmount, bonded, comitted, committedAt, confirmed, rootSetTimestamp } = x
8383
return {
8484
transferRootId,
8585
transferRootHash,
@@ -88,8 +88,7 @@ async function main (source: any) {
8888
comitted,
8989
committedAt,
9090
confirmed,
91-
rootSetTimestamp,
92-
allSettled
91+
rootSetTimestamp
9392
}
9493
})
9594
items = filtered

packages/hop-node/src/cli/settle.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ root
1212
.option('--source-chain <slug>', 'Source chain', parseString)
1313
.option('--token <slug>', 'Token', parseString)
1414
.option('--transfer-root-hash <id>', 'Transfer root hash', parseString)
15-
.option('--transfer-id <id>', 'Transfer ID', parseString)
1615
.option('--bonder <address>', 'Bonder address', parseString)
1716
.option('--use-db [boolean]', 'Use the DB to construct the roots', parseBool)
1817
.option(
@@ -23,15 +22,15 @@ root
2322
.action(actionHandler(main))
2423

2524
async function main (source: any) {
26-
let { sourceChain: chain, token, transferRootHash, transferId, bonder, useDb, dry: dryMode } = source
25+
let { sourceChain: chain, token, transferRootHash, bonder, useDb, dry: dryMode } = source
2726
if (!chain) {
2827
throw new Error('source chain is required')
2928
}
3029
if (!token) {
3130
throw new Error('token is required')
3231
}
33-
if (!(transferRootHash || transferId)) {
34-
throw new Error('transferRootHash or transferId is required')
32+
if (!transferRootHash) {
33+
throw new Error('transferRootHash is required')
3534
}
3635

3736
if (typeof useDb === 'undefined') {
@@ -44,11 +43,7 @@ async function main (source: any) {
4443
}
4544

4645
if (useDb) {
47-
if (transferRootHash) {
48-
await watcher.checkTransferRootHash(transferRootHash, bonder)
49-
} else {
50-
await watcher.checkTransferId(transferId)
51-
}
46+
await watcher.checkTransferRootHash(transferRootHash, bonder)
5247
} else {
5348
const transferRoot: any = await getTransferRoot(chain, token, transferRootHash)
5449
const destinationChainId: number = transferRoot.destinationChainId

packages/hop-node/src/db/BaseDb.ts

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import spread from 'lodash/spread'
99
import sub from 'subleveldown'
1010
import wait from 'src/utils/wait'
1111
import { EventEmitter } from 'events'
12+
import { Migration } from 'src/db/migrations'
1213
import { Mutex } from 'async-mutex'
1314
import { TenSecondsMs } from 'src/constants'
1415
import { config as globalConfig } from 'src/config'
@@ -36,6 +37,10 @@ type QueueItem = {
3637
cb: any
3738
}
3839

40+
type MigrationIndexEntry = {
41+
index: number
42+
}
43+
3944
// this are options that leveldb createReadStream accepts
4045
export type KeyFilter = {
4146
gt?: string
@@ -59,8 +64,9 @@ class BaseDb extends EventEmitter {
5964
batchSize: number = 10
6065
batchTimeLimit: number = 2 * 1000
6166
batchQueue: QueueItem[] = []
67+
private readonly dbMigrationKey: string = '_dbMigrationIndex'
6268

63-
constructor (prefix: string, _namespace?: string) {
69+
constructor (prefix: string, _namespace?: string, migrations?: Migration[]) {
6470
super()
6571
if (!prefix) {
6672
throw new Error('db prefix is required')
@@ -121,7 +127,7 @@ class BaseDb extends EventEmitter {
121127
})
122128

123129
this.pollBatchQueue()
124-
this._migration()
130+
this._migrate(migrations)
125131
.then(() => {
126132
this.ready = true
127133
this.logger.debug('db ready')
@@ -132,15 +138,36 @@ class BaseDb extends EventEmitter {
132138
})
133139
}
134140

135-
// To add a migration, implement the shouldMigrate and migration functions in the child class.
136141
// Migrations are memory intensive. Ensure there is no unintentional memory overflow.
137142
// * Use stream instead of storing all entries at once
138143
// * Bypass the mutex
139-
async _migration (): Promise<void> {
140-
// Check if migration is needed
141-
if (!this.shouldMigrate()) return
144+
// This may take minutes or hours to complete
145+
private async _migrate (migrations?: Migration[]): Promise<void> {
146+
if (!migrations?.length) {
147+
this.logger.debug('no migrations to process')
148+
return
149+
}
150+
151+
const currentMigrationIndex = await this.getMigrationIndex() ?? 0
152+
const lastMigrationIndex = migrations.length - 1
153+
if (currentMigrationIndex > lastMigrationIndex) {
154+
this.logger.debug(`no migration required, currentMigrationIndex: ${currentMigrationIndex}`)
155+
return
156+
}
157+
158+
this.logger.debug(`processing migrations from ${currentMigrationIndex} to ${lastMigrationIndex}`)
159+
for (let i = currentMigrationIndex; i <= lastMigrationIndex; i++) {
160+
const migration: Migration = migrations[i]
161+
this.logger.debug(`processing migration ${i}`)
162+
await this._processMigration(migration)
163+
await this.putMigrationIndex(i + 1)
164+
this.logger.debug(`completed migration ${i}`)
165+
}
166+
this.logger.debug('migrations complete')
167+
}
142168

143-
// Perform migration
169+
private async _processMigration (migration: Migration): Promise<void> {
170+
let migrationCount = 0
144171
return await new Promise((resolve, reject) => {
145172
const s = this.db.createReadStream({})
146173
s.on('data', async (key: any, value: any) => {
@@ -154,15 +181,15 @@ class BaseDb extends EventEmitter {
154181
return
155182
}
156183

157-
// Call the child class migration function
158184
try {
159-
await this.migration(key, value)
185+
await this._migrateEntry(migration, key, value)
186+
migrationCount++
160187
} catch (err) {
161188
s.emit('error', err)
162189
}
163190
})
164191
.on('end', () => {
165-
this.logger.debug('DB migration complete')
192+
this.logger.debug(`DB migration complete. migrated ${migrationCount} entries`)
166193
s.destroy()
167194
resolve()
168195
})
@@ -174,15 +201,29 @@ class BaseDb extends EventEmitter {
174201
})
175202
}
176203

177-
shouldMigrate (): boolean {
178-
// Optional
179-
// Must return true in child class to perform migration
180-
return false
204+
// Ensure that these DB reads and writes do not use the mutex since a migration is memory-intensive
205+
private async _migrateEntry (migration: Migration, key: string, value: any): Promise<void> {
206+
const { key: migrationKey, value: migrationValue, migratedValue } = migration
207+
if (
208+
value?.[migrationKey] === undefined ||
209+
value?.[migrationKey] === migrationValue
210+
) {
211+
const { value: updatedValue } = await this._getUpdateData(key, value)
212+
updatedValue[migrationKey] = migratedValue
213+
return this.db.put(key, updatedValue)
214+
}
215+
}
216+
217+
private async getMigrationIndex (): Promise<number | undefined> {
218+
const migrationEntry: MigrationIndexEntry = await this.getById(this.dbMigrationKey)
219+
return migrationEntry?.index
181220
}
182221

183-
async migration (key: string, value: any): Promise<void> {
184-
// Optional
185-
// Must be implemented in child class to perform migration
222+
private async putMigrationIndex (updatedMigrationIndex: number): Promise<void> {
223+
const data: MigrationIndexEntry = {
224+
index: updatedMigrationIndex
225+
}
226+
return this._updateSingle(this.dbMigrationKey, data)
186227
}
187228

188229
protected async tilReady (): Promise<boolean> {

0 commit comments

Comments
 (0)