Skip to content

Commit

Permalink
feat: import v3 snapshot (#793)
Browse files Browse the repository at this point in the history
* legacy snapshot generator

* prepare genesis block generator

* style: resolve style guide violations

* fix deps

* style: resolve style guide violations

* update comments

* update interfaces

* add `seedAccountInfo` to evm

* add snapshot importer package

* use snapshot importer for creating genesis block

* support snapshot during genesis bootstrap

* set temporary path

* commit dirty lockfile

* style: resolve style guide violations

* shared contract deployer

* style: resolve style guide violations

* seed usernames

* style: resolve style guide violations

* integrity checks

* improve logging

* style: resolve style guide violations

* fix tests

* make importer optional

* fix check

* Update pnpm-lock

* typo

* rename package

* style: resolve style guide violations

* call importer during bootstrap

---------

Co-authored-by: oXtxNt9U <[email protected]>
Co-authored-by: sebastijankuzner <[email protected]>
  • Loading branch information
3 people authored Dec 6, 2024
1 parent d86880a commit 894ca5d
Show file tree
Hide file tree
Showing 45 changed files with 2,479 additions and 1,507 deletions.
4 changes: 2 additions & 2 deletions packages/api-database/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@
"@mainsail/kernel": "workspace:*",
"@mainsail/utils": "workspace:*",
"dayjs": "1.11.10",
"pg": "8.11.3",
"pg": "8.13.1",
"typeorm": "0.3.20"
},
"devDependencies": {
"@types/pg": "8.11.2",
"@types/pg": "8.11.10",
"uvu": "^0.5.6"
},
"engines": {
Expand Down
28 changes: 28 additions & 0 deletions packages/bootstrap/source/bootstrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ export class Bootstrapper {
@optional()
private readonly apiSync?: Contracts.ApiSync.Service;

@inject(Identifiers.Snapshot.Legacy.Importer)
@optional()
private readonly snapshotImporter?: Contracts.Snapshot.LegacyImporter;

@inject(Identifiers.TransactionPool.Worker)
private readonly txPoolWorker!: Contracts.TransactionPool.Worker;

Expand Down Expand Up @@ -109,6 +113,7 @@ export class Bootstrapper {

async #initState(): Promise<void> {
if (this.databaseService.isEmpty()) {
await this.#tryImportSnapshot();
await this.#processGenesisBlock();
} else {
const commit = await this.databaseService.getLastCommit();
Expand Down Expand Up @@ -141,4 +146,27 @@ export class Bootstrapper {
await this.app.terminate(`Failed to process block at height ${commit.block.data.height}`, error);
}
}

async #tryImportSnapshot(): Promise<void> {
const genesisBlock = this.stateStore.getGenesisCommit();
const milestone = this.configuration.getMilestone(0);

// assume snapshot is present if the previous block points to a non-zero hash
if (
genesisBlock.block.header.previousBlock ===
"0000000000000000000000000000000000000000000000000000000000000000"
) {
if (milestone.snapshot) {
throw new Error("previous block set to snapshot but no hash in milestone");
}

return;
}

if (!this.snapshotImporter) {
throw new Error("snapshot importer not loaded");
}

await this.snapshotImporter.run(genesisBlock);
}
}
4 changes: 4 additions & 0 deletions packages/configuration-generator/bin/create-genesis-block.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ async function run() {
symbol: "TѦ",
token: "ARK",
distribute: true,
premine: "0",
snapshot: {
path: "../../snapshot-19a87c96dbe8ad1be06d33e97cd17f5662eb952c29efd3d8bb00c9c75e7582bc.json",
},
});
}

Expand Down
3 changes: 3 additions & 0 deletions packages/configuration-generator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,14 @@
"@mainsail/crypto-transaction-evm-call": "workspace:*",
"@mainsail/crypto-validation": "workspace:*",
"@mainsail/crypto-wif": "workspace:*",
"@mainsail/evm-consensus": "workspace:*",
"@mainsail/evm-contracts": "workspace:*",
"@mainsail/evm-gas-fee": "workspace:*",
"@mainsail/evm-service": "workspace:*",
"@mainsail/kernel": "workspace:*",
"@mainsail/serializer": "workspace:*",
"@mainsail/snapshot-legacy-exporter": "workspace:*",
"@mainsail/snapshot-legacy-importer": "workspace:*",
"@mainsail/utils": "workspace:*",
"@mainsail/validation": "workspace:*",
"bip39": "3.1.0",
Expand Down
13 changes: 12 additions & 1 deletion packages/configuration-generator/source/application-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ import { ServiceProvider as CoreCryptoTransaction } from "@mainsail/crypto-trans
import { ServiceProvider as CoreCryptoTransactionEvmCall } from "@mainsail/crypto-transaction-evm-call";
import { ServiceProvider as CoreCryptoValidation } from "@mainsail/crypto-validation";
import { ServiceProvider as CoreCryptoWif } from "@mainsail/crypto-wif";
import { ServiceProvider as CoreEvmConsensus } from "@mainsail/evm-consensus";
import { ServiceProvider as CoreEvmGasFee } from "@mainsail/evm-gas-fee";
import { ServiceProvider as EvmService } from "@mainsail/evm-service";
import { Application } from "@mainsail/kernel";
import { ServiceProvider as CoreSerializer } from "@mainsail/serializer";
import { ServiceProvider as CoreSnapshotLegacyImporter } from "@mainsail/snapshot-legacy-importer";
import { ServiceProvider as CoreValidation } from "@mainsail/validation";
import { dirSync, setGracefulCleanup } from "tmp";

Expand All @@ -40,10 +42,16 @@ export const makeApplication = async (configurationPath: string, options: Record
const app = new Application(new Container());
app.bind(Identifiers.Application.Name).toConstantValue(options.name);
app.bind(Identifiers.Services.EventDispatcher.Service).toConstantValue({});
app.bind(Identifiers.Services.Log.Service).toConstantValue({});
app.bind(Identifiers.Services.Log.Service).toConstantValue({
debug: (message: string) => console.log(message),
info: (message: string) => console.log(message),
warning: (message: string) => console.log(message),
});
// Used for evm instance
const fsExtra = await import("fs-extra/esm");
app.bind(Identifiers.Services.Filesystem.Service).toConstantValue({
existsSync: () => true,
readJSONSync: (file: string, options?: Record<string, any>) => fsExtra.readJSONSync(file, options),
});
setGracefulCleanup();
app.rebind("path.data").toConstantValue(dirSync().name);
Expand All @@ -62,14 +70,17 @@ export const makeApplication = async (configurationPath: string, options: Record
await app.resolve(CoreCryptoWif).register();
await app.resolve(CoreCryptoBlock).register();
await app.resolve(CoreEvmGasFee).register();
await app.resolve(CoreEvmConsensus).register();
await app.resolve(CoreCryptoTransaction).register();
await app.resolve(CoreCryptoTransactionEvmCall).register();
await app.resolve(CoreSnapshotLegacyImporter).register();
await app.resolve(EvmService).register();

// @ts-ignore
app.get<Contracts.Crypto.Configuration>(Identifiers.Cryptography.Configuration).setConfig({
milestones: [
{
evmSpec: Contracts.Evm.SpecId.SHANGHAI,
height: 0,
timeouts: {
blockPrepareTime: 4000,
Expand Down
36 changes: 34 additions & 2 deletions packages/configuration-generator/source/configuration-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,13 @@ export class ConfigurationGenerator {
};

const genesisWalletMnemonic = this.mnemonicGenerator.generate();
const validatorsMnemonics = this.mnemonicGenerator.generateMany(internalOptions.validators);
let validatorsMnemonics = this.mnemonicGenerator.generateMany(internalOptions.validators);

const tasks: Task[] = [
{
task: async () => {
if (!internalOptions.overwriteConfig && pathExistsSync(this.configurationPath)) {
throw new Error(`${this.configurationPath} already exists.`);
// throw new Error(`${this.configurationPath} already exists.`);
}

ensureDirSync(this.configurationPath);
Expand Down Expand Up @@ -139,6 +139,38 @@ export class ConfigurationGenerator {
network: {},
});

if (options.snapshot) {
const importer = this.app.get<Contracts.Snapshot.LegacyImporter>(
Identifiers.Snapshot.Legacy.Importer,
);
await importer.prepare(options.snapshot.path);

milestones[0].snapshot = { hash: importer.snapshotHash };

if (importer.validators) {
const importedValidatorMnemonics: string[] = [];
// create fake mnemonics for testing
const consensusKeyPairFactory = this.app.getTagged<Contracts.Crypto.KeyPairFactory>(
Identifiers.Cryptography.Identity.KeyPair.Factory,
"type",
"consensus",
);

for (const validator of importer.validators) {
const validatorMnemonic = this.mnemonicGenerator.generateDeterministic(
validator.username,
);
importedValidatorMnemonics.push(validatorMnemonic);

const consensusKeyPair = await consensusKeyPairFactory.fromMnemonic(validatorMnemonic);
validator.blsPublicKey = consensusKeyPair.publicKey;
}

// imported validators are already sorted by descending balance
validatorsMnemonics = importedValidatorMnemonics.slice(0, internalOptions.validators);
}
}

const genesisBlock = await this.genesisBlockGenerator.generate(
genesisWalletMnemonic,
validatorsMnemonics,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ describe<{
{
reward: "0",
address: { bech32m: "ark" },
block: { version: 1, maxPayload: 2097152, maxTransactions: 150 },
block: { version: 1, maxGasLimit: 30_000_000, maxPayload: 2097152, maxTransactions: 150 },
blockTime: 8000,
height: 0,
evmSpec: Contracts.Evm.SpecId.SHANGHAI,
// @ts-ignore
gas: {
maximumGasLimit: 2000000,
Expand Down
Loading

0 comments on commit 894ca5d

Please sign in to comment.