wdb-migration: fix and test coin selection progress recovery.

This commit is contained in:
Nodari Chkuaselidze 2025-06-04 17:29:06 +04:00
parent cd3dfeb943
commit fb18da4dc6
No known key found for this signature in database
GPG key ID: B018A7BB437D1F05
2 changed files with 94 additions and 5 deletions

View file

@ -1405,9 +1405,16 @@ class MigrateCoinSelection extends AbstractMigration {
await this.decodeProgress(ctx.state.inProgressData);
for (const wid of wids) {
if (wid < this.progress.wid)
if (wid < this.progress.wid) {
this.logger.debug(
'Skipping wallet %d (%d/%d), already migrated.',
wid, this.progress.wid, wids.length);
continue;
}
this.logger.info(
'Migrating wallet %d (%d/%d)',
wid, this.progress.wid, wids.length);
await this.migrateWallet(wid, ctx);
}
@ -1473,7 +1480,7 @@ class MigrateCoinSelection extends AbstractMigration {
this.progress.wid = wid;
this.progress.account = account;
this.progress.hash = hash;
this.progress.index = index;
this.progress.index = index + 1;
ctx.state.inProgressData = this.encodeProgress();
ctx.writeState(parent.root());
@ -1488,7 +1495,7 @@ class MigrateCoinSelection extends AbstractMigration {
this.progress.hash = consensus.ZERO_HASH;
this.progress.index = 0;
ctx.state.inProgressData = this.encodeProgress();
ctx.writeState(parent);
ctx.writeState(parent.root());
await parent.write();
}

View file

@ -1121,7 +1121,7 @@ describe('Wallet Migrations', function() {
};
let walletDB, ldb;
before(async () => {
beforeEach(async () => {
WalletMigrator.migrations = {};
await fs.mkdirp(location);
@ -1133,7 +1133,7 @@ describe('Wallet Migrations', function() {
await walletDB.close();
});
after(async () => {
afterEach(async () => {
WalletMigrator.migrations = migrationsBAK;
await rimraf(location);
});
@ -1164,5 +1164,87 @@ describe('Wallet Migrations', function() {
await walletDB.close();
});
it('should resume the progress of migration if interrupted', async () => {
// patch the db buckets to throw after each write.
const patchDB = () => {
// throw after each bucket write.
const ldbBucket = walletDB.db.bucket;
walletDB.db.bucket = (prefix) => {
const bucket = ldbBucket.call(ldb, prefix);
const bucketBatch = bucket.batch;
bucket.batch = () => {
const batch = bucketBatch.call(bucket);
const originalWrite = batch.write;
batch.write = async () => {
await originalWrite.call(batch);
throw new Error('Interrupt migration');
};
return batch;
};
return bucket;
};
return () => {
walletDB.db.bucket = ldbBucket;
};
};
WalletMigrator.migrations = {
0: class extends Migration {
constructor(options) {
super(options);
this.batchSize = 10;
}
async migrate(b, ctx) {
const unpatch = patchDB();
await super.migrate(b, ctx);
unpatch();
}
}
};
await walletDB.db.open();
const migrator = new WalletMigrator({
walletMigrate: 0,
walletDB: walletDB,
dbVersion: 5
});
let err;
do {
try {
await migrator.migrate();
err = null;
} catch (e) {
if (e.message !== 'Interrupt migration')
throw e;
err = e;
}
} while (err);
await checkEntries(ldb, {
before: data.before,
after: data.after,
throw: true
});
await checkExactEntries(ldb, data.prefixes, {
after: data.after,
throw: true
});
await walletDB.db.close();
});
});
});