From 1bb8507b8692b8465982dba5ad78ef27405ecc56 Mon Sep 17 00:00:00 2001 From: oXtxNt9U <120286271+oXtxNt9U@users.noreply.github.com> Date: Wed, 11 Dec 2024 16:16:21 +0900 Subject: [PATCH] restore contracts --- packages/api-sync/source/restore.ts | 33 +++++++++++++++++-- packages/api-sync/source/service.ts | 5 +++ .../source/application-factory.ts | 4 ++- .../source/contracts/evm/contract-service.ts | 2 +- packages/evm-consensus/source/deployer.ts | 16 +++++++-- packages/evm-consensus/source/identifiers.ts | 1 + packages/evm-consensus/source/index.ts | 4 ++- 7 files changed, 57 insertions(+), 8 deletions(-) diff --git a/packages/api-sync/source/restore.ts b/packages/api-sync/source/restore.ts index 5df8be212..e09acb688 100644 --- a/packages/api-sync/source/restore.ts +++ b/packages/api-sync/source/restore.ts @@ -5,7 +5,7 @@ import { } from "@mainsail/api-database"; import { inject, injectable, tagged } from "@mainsail/container"; import { Contracts, Identifiers } from "@mainsail/contracts"; -import { Identifiers as EvmConsensusIdentifiers } from "@mainsail/evm-consensus"; +import { Identifiers as EvmConsensusIdentifiers, Deployer } from "@mainsail/evm-consensus"; import { UsernamesAbi } from "@mainsail/evm-contracts"; import { Utils } from "@mainsail/kernel"; import { chunk, validatorSetPack } from "@mainsail/utils"; @@ -16,6 +16,7 @@ interface RestoreContext { readonly entityManager: ApiDatabaseContracts.RepositoryDataSource; readonly blockRepository: ApiDatabaseContracts.BlockRepository; readonly configurationRepository: ApiDatabaseContracts.ConfigurationRepository; + readonly contractRepository: ApiDatabaseContracts.ContractRepository; readonly stateRepository: ApiDatabaseContracts.StateRepository; readonly transactionRepository: ApiDatabaseContracts.TransactionRepository; readonly transactionTypeRepository: ApiDatabaseContracts.TransactionTypeRepository; @@ -86,6 +87,9 @@ export class Restore { @inject(ApiDatabaseIdentifiers.ConfigurationRepositoryFactory) private readonly configurationRepositoryFactory!: ApiDatabaseContracts.ConfigurationRepositoryFactory; + @inject(ApiDatabaseIdentifiers.ContractRepositoryFactory) + private readonly contractRepositoryFactory!: ApiDatabaseContracts.ContractRepositoryFactory; + @inject(ApiDatabaseIdentifiers.ReceiptRepositoryFactory) private readonly receiptRepositoryFactory!: ApiDatabaseContracts.ReceiptRepositoryFactory; @@ -134,6 +138,7 @@ export class Restore { addressToPublicKey: {}, blockRepository: this.blockRepositoryFactory(entityManager), configurationRepository: this.configurationRepositoryFactory(entityManager), + contractRepository: this.contractRepositoryFactory(entityManager), entityManager, lastHeight: 0, mostRecentCommit, @@ -184,7 +189,10 @@ export class Restore { // 8) Write `state` table await this.#ingestState(context); - // 9) Update validator ranks + // 9) Write `contracts` table + await this.#ingestContracts(context); + + // 10) Update validator ranks await this.#updateValidatorRanks(context); restoredHeight = context.lastHeight; @@ -553,6 +561,27 @@ export class Restore { .execute(); } + async #ingestContracts(context: RestoreContext): Promise { + const deploymentEvents = this.app + .get(EvmConsensusIdentifiers.Internal.Deployer) + .getDeploymentEvents(); + + await context.contractRepository + .createQueryBuilder() + .insert() + .orIgnore() + .values( + deploymentEvents.map((event) => ({ + activeImplementation: event.activeImplementation ?? event.address, + address: event.address, + implementations: event.implementations, + name: event.name, + proxy: event.proxy, + })), + ) + .execute(); + } + async #updateValidatorRanks(context: RestoreContext): Promise { await context.entityManager.query("SELECT update_validator_ranks();", []); } diff --git a/packages/api-sync/source/service.ts b/packages/api-sync/source/service.ts index 03227bd3a..9c182e2dc 100644 --- a/packages/api-sync/source/service.ts +++ b/packages/api-sync/source/service.ts @@ -46,6 +46,9 @@ export class Sync implements Contracts.ApiSync.Service { @inject(ApiDatabaseIdentifiers.BlockRepositoryFactory) private readonly blockRepositoryFactory!: ApiDatabaseContracts.BlockRepositoryFactory; + @inject(ApiDatabaseIdentifiers.ContractRepositoryFactory) + private readonly contractRepositoryFactory!: ApiDatabaseContracts.ContractRepositoryFactory; + @inject(ApiDatabaseIdentifiers.ConfigurationRepositoryFactory) private readonly configurationRepositoryFactory!: ApiDatabaseContracts.ConfigurationRepositoryFactory; @@ -494,6 +497,7 @@ export class Sync implements Contracts.ApiSync.Service { await this.dataSource.transaction("REPEATABLE READ", async (entityManager) => { const blockRepository = this.blockRepositoryFactory(entityManager); + const contractRepository = this.contractRepositoryFactory(entityManager); const stateRepository = this.stateRepositoryFactory(entityManager); const transactionRepository = this.transactionRepositoryFactory(entityManager); const receiptRepository = this.receiptRepositoryFactory(entityManager); @@ -504,6 +508,7 @@ export class Sync implements Contracts.ApiSync.Service { await Promise.all( [ blockRepository, + contractRepository, stateRepository, transactionRepository, receiptRepository, diff --git a/packages/configuration-generator/source/application-factory.ts b/packages/configuration-generator/source/application-factory.ts index cbe5da881..c1cb9c826 100644 --- a/packages/configuration-generator/source/application-factory.ts +++ b/packages/configuration-generator/source/application-factory.ts @@ -41,7 +41,9 @@ 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.EventDispatcher.Service).toConstantValue({ + dispatch: () => {}, + }); app.bind(Identifiers.Services.Log.Service).toConstantValue({ debug: (message: string) => console.log(message), info: (message: string) => console.log(message), diff --git a/packages/contracts/source/contracts/evm/contract-service.ts b/packages/contracts/source/contracts/evm/contract-service.ts index 775d6893f..de9086dab 100644 --- a/packages/contracts/source/contracts/evm/contract-service.ts +++ b/packages/contracts/source/contracts/evm/contract-service.ts @@ -5,7 +5,7 @@ import { ValidatorWallet } from "../state/wallets.js"; export interface DeployerContract { readonly name: string; readonly address: string; - readonly proxy: "UUPS" | undefined; + readonly proxy?: "UUPS"; readonly implementations: { address: string; abi: Record }[]; readonly activeImplementation?: string; } diff --git a/packages/evm-consensus/source/deployer.ts b/packages/evm-consensus/source/deployer.ts index 54cbfcce8..7c58a6c19 100644 --- a/packages/evm-consensus/source/deployer.ts +++ b/packages/evm-consensus/source/deployer.ts @@ -162,7 +162,7 @@ export class Deployer { `Deployed Consensus PROXY contract from ${this.deployerAddress} to ${proxyResult.receipt.deployedContractAddress}`, ); - void this.events.dispatch(Events.DeployerEvent.ContractCreated, { + this.#emitContractDeployed({ activeImplementation: consensusContractAddress, address: proxyResult.receipt.deployedContractAddress!, implementations: [{ abi: ConsensusAbi.abi, address: consensusContractAddress }], @@ -243,7 +243,7 @@ export class Deployer { `Deployed Usernames PROXY contract from ${this.deployerAddress} to ${proxyResult.receipt.deployedContractAddress}`, ); - void this.events.dispatch(Events.DeployerEvent.ContractCreated, { + this.#emitContractDeployed({ activeImplementation: usernamesContractAddress, address: proxyResult.receipt.deployedContractAddress!, implementations: [{ abi: UsernamesAbi.abi, address: usernamesContractAddress }], @@ -282,7 +282,7 @@ export class Deployer { `Deployed MultiPayments contract from ${this.deployerAddress} to ${result.receipt.deployedContractAddress}`, ); - void this.events.dispatch(Events.DeployerEvent.ContractCreated, { + this.#emitContractDeployed({ address: result.receipt.deployedContractAddress!, implementations: [{ abi: MultiPaymentAbi.abi, address: result.receipt.deployedContractAddress! }], name: "multi-payments", @@ -290,4 +290,14 @@ export class Deployer { return result.receipt.deployedContractAddress!; } + + public getDeploymentEvents(): Contracts.Evm.DeployerContract[] { + return this.#deploymentEvents; + } + + #deploymentEvents: Contracts.Evm.DeployerContract[] = []; + #emitContractDeployed(event: Contracts.Evm.DeployerContract): void { + this.#deploymentEvents.push(event); + void this.events.dispatch(Events.DeployerEvent.ContractCreated, event); + } } diff --git a/packages/evm-consensus/source/identifiers.ts b/packages/evm-consensus/source/identifiers.ts index ce3ab1b5b..8a655afd3 100644 --- a/packages/evm-consensus/source/identifiers.ts +++ b/packages/evm-consensus/source/identifiers.ts @@ -6,6 +6,7 @@ export const Identifiers = { }, }, Internal: { + Deployer: Symbol.for("Evm.Consensus"), Addresses: { Deployer: Symbol.for("Evm.Consensus"), }, diff --git a/packages/evm-consensus/source/index.ts b/packages/evm-consensus/source/index.ts index 37dfe815f..06d9c192b 100644 --- a/packages/evm-consensus/source/index.ts +++ b/packages/evm-consensus/source/index.ts @@ -29,7 +29,9 @@ export class ServiceProvider extends Providers.ServiceProvider { const genesisBlock = this.app.config("crypto.genesisBlock"); Utils.assert.defined(genesisBlock); - await this.app.resolve(Deployer).deploy({ + this.app.bind(EvmConsensusIdentifiers.Internal.Deployer).to(Deployer).inSingletonScope(); + + await this.app.get(EvmConsensusIdentifiers.Internal.Deployer).deploy({ generatorAddress: genesisBlock.block.generatorAddress, timestamp: genesisBlock.block.timestamp, totalAmount: genesisBlock.block.totalAmount,