diff --git a/package-lock.json b/package-lock.json index 1d57189ac..8c0b7475a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28984,6 +28984,7 @@ "dotenv": "^17.2.3", "inquirer": "^9.3.0", "kleur": "^4.1.5", + "loglevel": "^1.8.1", "mina-fungible-token": "^1.1.0", "reflect-metadata": "^0.1.13", "spectaql": "3.0.5", diff --git a/packages/cli/package.json b/packages/cli/package.json index 3f30a7a27..d82d43526 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -25,6 +25,7 @@ "dotenv": "^17.2.3", "inquirer": "^9.3.0", "kleur": "^4.1.5", + "loglevel": "^1.8.1", "mina-fungible-token": "^1.1.0", "reflect-metadata": "^0.1.13", "spectaql": "3.0.5", diff --git a/packages/cli/src/commands/circuitSummary.ts b/packages/cli/src/commands/circuitSummary.ts new file mode 100644 index 000000000..306f657fd --- /dev/null +++ b/packages/cli/src/commands/circuitSummary.ts @@ -0,0 +1,19 @@ +import { CommandModule } from "yargs"; + +export const circuitSummaryCommand: CommandModule = { + command: "summary", + describe: + "Print a summary of the circuit sizes of runtime and protocol circuits", + builder: (yarg) => yarg, + handler: async () => { + try { + const { default: circuitSummary } = + await import("../scripts/circuitSummary"); + await circuitSummary(); + process.exit(0); + } catch (error) { + console.error("Failed to generate circuit summary:", error); + process.exit(1); + } + }, +}; diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index 7f60b14b9..eece25a14 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -10,6 +10,7 @@ import { wizardCommand } from "./commands/wizard"; import { settlementCommand } from "./commands/settlement/settlement"; import { lightnetCommand } from "./commands/lightnet/lightnet"; import { bridgeCommand } from "./commands/bridge/bridge"; +import { circuitSummaryCommand } from "./commands/circuitSummary"; process.removeAllListeners("warning"); process.env.NODE_NO_WARNINGS = "1"; @@ -25,6 +26,7 @@ await yargs(hideBin(process.argv)) .command(settlementCommand) .command(lightnetCommand) .command(bridgeCommand) + .command(circuitSummaryCommand) .demandCommand( 1, "You must specify a command. Use --help to see available commands." diff --git a/packages/cli/src/scripts/circuitSummary.ts b/packages/cli/src/scripts/circuitSummary.ts new file mode 100644 index 000000000..cd3aa81e6 --- /dev/null +++ b/packages/cli/src/scripts/circuitSummary.ts @@ -0,0 +1,90 @@ +import "reflect-metadata"; +import { container } from "tsyringe"; +import loglevel from "loglevel"; + +import { loadUserModules } from "../utils/loadUserModules"; + +export default async function (): Promise { + console.log("Analyzing circuit sizes..."); + const { PrivateKey } = await import("o1js"); + process.env.PROTOKIT_TRANSACTION_FEE_RECIPIENT_PUBLIC_KEY = + PrivateKey.random().toPublicKey().toBase58(); + + const { Runtime } = await import("@proto-kit/module"); + const { Protocol, RuntimeVerificationKeyRootService, ContractArgsRegistry } = + await import("@proto-kit/protocol"); + const { AppChain, Sequencer, CircuitAnalysisModule } = + await import("@proto-kit/sequencer"); + const { + CompileRegistry, + ChildVerificationKeyService, + MOCK_VERIFICATION_KEY, + } = await import("@proto-kit/common"); + + const { runtime, protocol } = await loadUserModules(); + + const appChain = AppChain.from({ + Runtime: Runtime.from(runtime.modules), + Protocol: Protocol.from({ + ...protocol.modules, + ...protocol.settlementModules, + }), + Sequencer: Sequencer.from({}), + }); + + appChain.configure({ + Runtime: runtime.config, + Protocol: { + ...protocol.config, + ...protocol.settlementModulesConfig, + }, + Sequencer: {}, + }); + + loglevel.setLevel("SILENT"); + + const chainContainer = container.createChildContainer(); + await appChain.start(false, chainContainer); + + appChain.protocol.dependencyContainer + .resolve(RuntimeVerificationKeyRootService) + .setRoot(0n); + + if (protocol.settlementModules !== undefined) { + const { SignedSettlementPermissions } = + await import("@proto-kit/sequencer"); + + const compileRegistry = + appChain.protocol.dependencyContainer.resolve(CompileRegistry); + const dummyVk = MOCK_VERIFICATION_KEY; + compileRegistry.addArtifactsRaw({ + BlockProver: { verificationKey: dummyVk }, + BridgeContract: { verificationKey: dummyVk }, + }); + + const childVkService = appChain.protocol.dependencyContainer.resolve( + ChildVerificationKeyService + ); + childVkService.setCompileRegistry(compileRegistry); + + const permissions = new SignedSettlementPermissions(); + const argsRegistry = + appChain.protocol.dependencyContainer.resolve(ContractArgsRegistry); + argsRegistry.addArgs("SettlementContract", { + signedSettlements: true, + BridgeContractPermissions: permissions.bridgeContractMina(), + }); + } + try { + const analysisModule = appChain.protocol.dependencyContainer.resolve( + CircuitAnalysisModule + ); + + loglevel.setLevel("INFO"); + await analysisModule.printSummary(); + } finally { + loglevel.setLevel("SILENT"); + await appChain.close(); + loglevel.setLevel("INFO"); + } +} diff --git a/packages/cli/src/scripts/explorer/start.ts b/packages/cli/src/scripts/explorer/start.ts index b84105c93..d07e0785f 100644 --- a/packages/cli/src/scripts/explorer/start.ts +++ b/packages/cli/src/scripts/explorer/start.ts @@ -1,5 +1,6 @@ import { spawn } from "child_process"; +export const EXPLORER_CONTAINER_NAME = "protokit-explorer"; const DEFAULT_EXPLORER_IMAGE = "ghcr.io/proto-kit/explorer:latest"; async function pullDockerImage(image: string): Promise { @@ -35,7 +36,14 @@ async function runDockerContainer(args: { const { port = 5003, explorerImage } = args; console.log(`\nExplorer is running at http://localhost:${port}\n`); - const dockerArgs = ["run", "--rm", "-p", `${port}:3000`]; + const dockerArgs = [ + "run", + "--rm", + "--name", + EXPLORER_CONTAINER_NAME, + "-p", + `${port}:3000`, + ]; if (args.indexerUrl !== undefined) { dockerArgs.push("-e", `NEXT_PUBLIC_INDEXER_URL=${args.indexerUrl}`);