Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ async function run() {
chainId: 10000,
initialHeight: 0,
// snapshot: {
// path: "../../snapshot-19a87c96dbe8ad1be06d33e97cd17f5662eb952c29efd3d8bb00c9c75e7582bc.json",
// path: "../../f07a7068c50e2e5591beaa572070933008744425d727c792d328d1d5e2fac306.compressed",
// },
});

Expand Down
4 changes: 4 additions & 0 deletions packages/contracts/source/contracts/snapshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ export interface LegacyImportOptions {

export interface LegacyImportResult {
readonly initialTotalSupply: bigint;
readonly importedValidatorsWithBlsKey: number;
readonly importedValidatorsWithoutBlsKey: number;
readonly importedUsernames: number;
readonly importedVoters: number;
}

export interface ImportedLegacyWallet {
Expand Down
1 change: 1 addition & 0 deletions packages/snapshot-legacy-exporter/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"@mainsail/crypto-key-pair-ecdsa": "workspace:*",
"@mainsail/crypto-validation": "workspace:*",
"@mainsail/kernel": "workspace:*",
"@mainsail/logger-pino": "workspace:*",
"@mainsail/utils": "workspace:*",
"@mainsail/validation": "workspace:*",
"pg": "8.14.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { ServiceProvider as CryptoKeyPairEcdsa } from "@mainsail/crypto-key-pair-ecdsa";
import { ServiceProvider as CryptoValidation } from "@mainsail/crypto-validation";
import { Application } from "@mainsail/kernel";
import { ServiceProvider as Logger } from "@mainsail/logger-pino";

Check warning on line 7 in packages/snapshot-legacy-exporter/source/application-factory.ts

View check run for this annotation

Codecov / codecov/patch

packages/snapshot-legacy-exporter/source/application-factory.ts#L7

Added line #L7 was not covered by tests
import { ServiceProvider as Validation } from "@mainsail/validation";
import { dirSync, setGracefulCleanup } from "tmp";

Expand All @@ -29,6 +30,7 @@
await app.resolve(CryptoValidation).register();
await app.resolve(CryptoKeyPairEcdsa).register();
await app.resolve(CryptoAddressKeccak256).register();
await app.resolve(Logger).register();

Check warning on line 33 in packages/snapshot-legacy-exporter/source/application-factory.ts

View check run for this annotation

Codecov / codecov/patch

packages/snapshot-legacy-exporter/source/application-factory.ts#L33

Added line #L33 was not covered by tests

//
app.bind(InternalIdentifiers.Snapshot.Generator).to(Generator);
Expand Down
4 changes: 4 additions & 0 deletions packages/snapshot-legacy-exporter/source/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@

v3: {
database: "ark_devnet",
// when using podman
// host: "host.containers.internal",
host: "localhost",

Check warning on line 35 in packages/snapshot-legacy-exporter/source/defaults.ts

View check run for this annotation

Codecov / codecov/patch

packages/snapshot-legacy-exporter/source/defaults.ts#L33-L35

Added lines #L33 - L35 were not covered by tests
password: "test_db",
port: 5432,

Check warning on line 37 in packages/snapshot-legacy-exporter/source/defaults.ts

View check run for this annotation

Codecov / codecov/patch

packages/snapshot-legacy-exporter/source/defaults.ts#L37

Added line #L37 was not covered by tests
user: "test_db",
},
},
Expand Down
165 changes: 88 additions & 77 deletions packages/snapshot-legacy-exporter/source/snapshot/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@
import { Contracts, Identifiers } from "@mainsail/contracts";
import { Application, Providers } from "@mainsail/kernel";
import { assert } from "@mainsail/utils";
import { DataSource } from "typeorm";
import { DataSource, EntityManager } from "typeorm";

Check warning on line 10 in packages/snapshot-legacy-exporter/source/snapshot/generator.ts

View check run for this annotation

Codecov / codecov/patch

packages/snapshot-legacy-exporter/source/snapshot/generator.ts#L10

Added line #L10 was not covered by tests
import { PostgresConnectionOptions } from "typeorm/driver/postgres/PostgresConnectionOptions.js";

import { Identifiers as InternalIdentifiers } from "../identifiers.js";
import { LegacyChainTip, LegacySnapshot, LegacyWallet } from "../interfaces.js";

interface DatabaseOptions extends PostgresConnectionOptions {
readonly v3: {
readonly host: string;
readonly port: number;

Check warning on line 19 in packages/snapshot-legacy-exporter/source/snapshot/generator.ts

View check run for this annotation

Codecov / codecov/patch

packages/snapshot-legacy-exporter/source/snapshot/generator.ts#L18-L19

Added lines #L18 - L19 were not covered by tests
readonly user: string;
readonly password: string;
readonly database: string;
Expand All @@ -26,32 +28,8 @@
@inject(InternalIdentifiers.Application)
private app!: Application;

async #connect(): Promise<DataSource> {
const pluginConfig = await this.app
.resolve(Providers.PluginConfiguration)
.discover("@mainsail/snapshot-legacy-exporter", process.cwd());

const options = pluginConfig.get<DatabaseOptions>("database");
assert.defined(options);

const dataSource = new DataSource({
...options,
entities: [],
migrations: [],
migrationsRun: false,
synchronize: false,
});

await dataSource.initialize();

// Link v3 database
await dataSource.query(`
CREATE EXTENSION IF NOT EXISTS dblink;
SELECT dblink_connect('v3_db', 'dbname=${options.v3.database} user=${options.v3.user} password=${options.v3.password}');
`);

return dataSource;
}
@inject(Identifiers.Services.Log.Service)
private readonly logger!: Contracts.Kernel.Logger;

Check warning on line 32 in packages/snapshot-legacy-exporter/source/snapshot/generator.ts

View check run for this annotation

Codecov / codecov/patch

packages/snapshot-legacy-exporter/source/snapshot/generator.ts#L31-L32

Added lines #L31 - L32 were not covered by tests

public async generateStatic(chainTip: LegacyChainTip, wallets: LegacyWallet[]): Promise<void> {
const addressFactory = this.app.get<Contracts.Crypto.AddressFactory>(
Expand All @@ -75,64 +53,97 @@
}

public async generate(): Promise<void> {
// Connect to V3 database
const dataSource = await this.#connect();
console.log("connected!");

const [chainTip] = await dataSource.query(
"SELECT * FROM dblink('v3_db', 'SELECT id, height FROM blocks ORDER BY height DESC LIMIT 1') AS blocks(hash varchar, number bigint);",
);
await this.#runInTransaction(async (entityManager) => {
this.logger.info("connected!");

const [chainTip] = await entityManager.query(
"SELECT * FROM dblink('v3_db', 'SELECT id, height FROM blocks ORDER BY height DESC LIMIT 1') AS blocks(hash varchar, number bigint);",
);

const addressFactory = this.app.get<Contracts.Crypto.AddressFactory>(
Identifiers.Cryptography.Identity.Address.Factory,
);

// Loop all wallets
const limit = 1000;
let offset = 0;

const wallets: LegacyWallet[] = [];
for (;;) {
this.logger.info(`Fetching wallets (offset: ${offset}, limit: ${limit})`);

const chunk: LegacyWallet[] = await entityManager.query(`
SELECT * FROM dblink(
'v3_db',
'
SELECT address, public_key, balance, attributes FROM wallets
ORDER BY balance DESC, address ASC LIMIT ${limit} OFFSET ${offset}
'
) AS wallets("arkAddress" varchar, "publicKey" varchar, balance bigint, attributes jsonb);
`);

for (const wallet of chunk) {
// sanitize
if (wallet.attributes?.["delegate"]) {
delete wallet.attributes?.["delegate"]["lastBlock"];
}

delete wallet.attributes?.["ipfs"]; // ?
delete wallet.attributes?.["business"]; // ?
delete wallet.attributes?.["htlc"]; // ?
delete wallet.attributes?.["entities"]; // ?

wallets.push({
...wallet,
...(wallet.publicKey
? {
ethAddress: await addressFactory.fromPublicKey(wallet.publicKey),
}
: {}),
});
}

Check warning on line 104 in packages/snapshot-legacy-exporter/source/snapshot/generator.ts

View check run for this annotation

Codecov / codecov/patch

packages/snapshot-legacy-exporter/source/snapshot/generator.ts#L56-L104

Added lines #L56 - L104 were not covered by tests

const addressFactory = this.app.get<Contracts.Crypto.AddressFactory>(
Identifiers.Cryptography.Identity.Address.Factory,
);
offset += limit;

Check warning on line 106 in packages/snapshot-legacy-exporter/source/snapshot/generator.ts

View check run for this annotation

Codecov / codecov/patch

packages/snapshot-legacy-exporter/source/snapshot/generator.ts#L106

Added line #L106 was not covered by tests

// Loop all wallets
const limit = 1000;
let offset = 0;

const wallets: LegacyWallet[] = [];
for (;;) {
const chunk: LegacyWallet[] = await dataSource.query(`
SELECT * FROM dblink(
'v3_db',
'
SELECT address, public_key, balance, attributes FROM wallets -- WHERE attributes ?| array[''vote'', ''delegate'', ''username'']
ORDER BY balance DESC, address ASC LIMIT ${limit} OFFSET ${offset}
'
) AS wallets("arkAddress" varchar, "publicKey" varchar, balance bigint, attributes jsonb);
`);

for (const wallet of chunk) {
// sanitize
if (wallet.attributes?.["delegate"]) {
delete wallet.attributes?.["delegate"]["lastBlock"];
if (chunk.length === 0) {
break;

Check warning on line 109 in packages/snapshot-legacy-exporter/source/snapshot/generator.ts

View check run for this annotation

Codecov / codecov/patch

packages/snapshot-legacy-exporter/source/snapshot/generator.ts#L108-L109

Added lines #L108 - L109 were not covered by tests
}
}

Check warning on line 111 in packages/snapshot-legacy-exporter/source/snapshot/generator.ts

View check run for this annotation

Codecov / codecov/patch

packages/snapshot-legacy-exporter/source/snapshot/generator.ts#L111

Added line #L111 was not covered by tests

delete wallet.attributes?.["ipfs"]; // ?
delete wallet.attributes?.["business"]; // ?
delete wallet.attributes?.["htlc"]; // ?
delete wallet.attributes?.["entities"]; // ?
await this.#writeSnapshot(chainTip, wallets);
});
}

Check warning on line 115 in packages/snapshot-legacy-exporter/source/snapshot/generator.ts

View check run for this annotation

Codecov / codecov/patch

packages/snapshot-legacy-exporter/source/snapshot/generator.ts#L113-L115

Added lines #L113 - L115 were not covered by tests

wallets.push({
...wallet,
...(wallet.publicKey
? {
ethAddress: await addressFactory.fromPublicKey(wallet.publicKey),
}
: {}),
});
}
async #runInTransaction(callback: (entityManager: EntityManager) => Promise<void>): Promise<void> {
const pluginConfig = await this.app
.resolve(Providers.PluginConfiguration)
.discover("@mainsail/snapshot-legacy-exporter", process.cwd());

const options = pluginConfig.get<DatabaseOptions>("database");
assert.defined(options);

Check warning on line 123 in packages/snapshot-legacy-exporter/source/snapshot/generator.ts

View check run for this annotation

Codecov / codecov/patch

packages/snapshot-legacy-exporter/source/snapshot/generator.ts#L117-L123

Added lines #L117 - L123 were not covered by tests

offset += limit;
const dataSource = new DataSource({
...options,
entities: [],
migrations: [],
migrationsRun: false,
synchronize: false,
});

Check warning on line 131 in packages/snapshot-legacy-exporter/source/snapshot/generator.ts

View check run for this annotation

Codecov / codecov/patch

packages/snapshot-legacy-exporter/source/snapshot/generator.ts#L125-L131

Added lines #L125 - L131 were not covered by tests

if (chunk.length === 0) {
break;
}
}
await dataSource.initialize();

Check warning on line 133 in packages/snapshot-legacy-exporter/source/snapshot/generator.ts

View check run for this annotation

Codecov / codecov/patch

packages/snapshot-legacy-exporter/source/snapshot/generator.ts#L133

Added line #L133 was not covered by tests

try {
await this.#writeSnapshot(chainTip, wallets);
await dataSource.transaction("REPEATABLE READ", async (entityManager) => {
// Link v3 database
await entityManager.query(`
CREATE EXTENSION IF NOT EXISTS dblink;
SELECT dblink_connect('v3_db', 'host=${options.v3.host} port=${options.v3.port} dbname=${options.v3.database} user=${options.v3.user} password=${options.v3.password}');
`);

await callback(entityManager);
});
} catch (ex) {
this.logger.error(ex);

Check warning on line 146 in packages/snapshot-legacy-exporter/source/snapshot/generator.ts

View check run for this annotation

Codecov / codecov/patch

packages/snapshot-legacy-exporter/source/snapshot/generator.ts#L136-L146

Added lines #L136 - L146 were not covered by tests
} finally {
await dataSource.destroy();
}
Expand All @@ -159,7 +170,7 @@
const jsonString = JSON.stringify(snapshot);
const compressedBuffer = await promisify(brotliCompress)(jsonString);
await writeFile(path, compressedBuffer);
console.log(`Wrote ${snapshot.wallets.length} wallets to '${path}'`);
this.logger.info(`Wrote ${snapshot.wallets.length} wallets to '${path}'`);

Check warning on line 173 in packages/snapshot-legacy-exporter/source/snapshot/generator.ts

View check run for this annotation

Codecov / codecov/patch

packages/snapshot-legacy-exporter/source/snapshot/generator.ts#L173

Added line #L173 was not covered by tests
}
}

Expand Down
Loading
Loading