moonwall 1.0.0-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +681 -0
- package/README.md +54 -0
- package/config_schema.json +811 -0
- package/dist/api/constants/accounts.d.ts +36 -0
- package/dist/api/constants/accounts.d.ts.map +1 -0
- package/dist/api/constants/accounts.js +67 -0
- package/dist/api/constants/chain.d.ts +134 -0
- package/dist/api/constants/chain.d.ts.map +1 -0
- package/dist/api/constants/chain.js +149 -0
- package/dist/api/constants/index.d.ts +4 -0
- package/dist/api/constants/index.d.ts.map +1 -0
- package/dist/api/constants/index.js +3 -0
- package/dist/api/constants/smartContract.d.ts +29 -0
- package/dist/api/constants/smartContract.d.ts.map +1 -0
- package/dist/api/constants/smartContract.js +118 -0
- package/dist/api/testing/blocks.d.ts +59 -0
- package/dist/api/testing/blocks.d.ts.map +1 -0
- package/dist/api/testing/blocks.js +147 -0
- package/dist/api/testing/contracts.d.ts +5 -0
- package/dist/api/testing/contracts.d.ts.map +1 -0
- package/dist/api/testing/contracts.js +32 -0
- package/dist/api/testing/ethers.d.ts +3 -0
- package/dist/api/testing/ethers.d.ts.map +1 -0
- package/dist/api/testing/ethers.js +38 -0
- package/dist/api/testing/events.d.ts +12 -0
- package/dist/api/testing/events.d.ts.map +1 -0
- package/dist/api/testing/events.js +23 -0
- package/dist/api/testing/extrinsics.d.ts +5 -0
- package/dist/api/testing/extrinsics.d.ts.map +1 -0
- package/dist/api/testing/extrinsics.js +10 -0
- package/dist/api/testing/index.d.ts +9 -0
- package/dist/api/testing/index.d.ts.map +1 -0
- package/dist/api/testing/index.js +8 -0
- package/dist/api/testing/jumping.d.ts +8 -0
- package/dist/api/testing/jumping.d.ts.map +1 -0
- package/dist/api/testing/jumping.js +78 -0
- package/dist/api/testing/providers.d.ts +18 -0
- package/dist/api/testing/providers.d.ts.map +1 -0
- package/dist/api/testing/providers.js +34 -0
- package/dist/api/testing/viem.d.ts +139 -0
- package/dist/api/testing/viem.d.ts.map +1 -0
- package/dist/api/testing/viem.js +247 -0
- package/dist/api/types/config.d.ts +609 -0
- package/dist/api/types/config.d.ts.map +1 -0
- package/dist/api/types/config.js +1 -0
- package/dist/api/types/context.d.ts +125 -0
- package/dist/api/types/context.d.ts.map +1 -0
- package/dist/api/types/context.js +1 -0
- package/dist/api/types/contracts.d.ts +66 -0
- package/dist/api/types/contracts.d.ts.map +1 -0
- package/dist/api/types/contracts.js +1 -0
- package/dist/api/types/eth.d.ts +3 -0
- package/dist/api/types/eth.d.ts.map +1 -0
- package/dist/api/types/eth.js +1 -0
- package/dist/api/types/foundations.d.ts +11 -0
- package/dist/api/types/foundations.d.ts.map +1 -0
- package/dist/api/types/foundations.js +1 -0
- package/dist/api/types/helpers.d.ts +7 -0
- package/dist/api/types/helpers.d.ts.map +1 -0
- package/dist/api/types/helpers.js +1 -0
- package/dist/api/types/index.d.ts +8 -0
- package/dist/api/types/index.d.ts.map +1 -0
- package/dist/api/types/index.js +7 -0
- package/dist/api/types/runner.d.ts +490 -0
- package/dist/api/types/runner.d.ts.map +1 -0
- package/dist/api/types/runner.js +1 -0
- package/dist/cli/cmds/components/LogViewer.d.ts +17 -0
- package/dist/cli/cmds/components/LogViewer.d.ts.map +1 -0
- package/dist/cli/cmds/components/LogViewer.js +171 -0
- package/dist/cli/cmds/entrypoint.d.ts +6 -0
- package/dist/cli/cmds/entrypoint.d.ts.map +1 -0
- package/dist/cli/cmds/entrypoint.js +192 -0
- package/dist/cli/cmds/interactiveCmds/chopsticksIntCmds.d.ts +2 -0
- package/dist/cli/cmds/interactiveCmds/chopsticksIntCmds.d.ts.map +1 -0
- package/dist/cli/cmds/interactiveCmds/chopsticksIntCmds.js +117 -0
- package/dist/cli/cmds/interactiveCmds/devIntCmds.d.ts +2 -0
- package/dist/cli/cmds/interactiveCmds/devIntCmds.d.ts.map +1 -0
- package/dist/cli/cmds/interactiveCmds/devIntCmds.js +103 -0
- package/dist/cli/cmds/interactiveCmds/index.d.ts +4 -0
- package/dist/cli/cmds/interactiveCmds/index.d.ts.map +1 -0
- package/dist/cli/cmds/interactiveCmds/index.js +3 -0
- package/dist/cli/cmds/interactiveCmds/zombieIntCmds.d.ts +2 -0
- package/dist/cli/cmds/interactiveCmds/zombieIntCmds.d.ts.map +1 -0
- package/dist/cli/cmds/interactiveCmds/zombieIntCmds.js +32 -0
- package/dist/cli/cmds/main.d.ts +2 -0
- package/dist/cli/cmds/main.d.ts.map +1 -0
- package/dist/cli/cmds/main.js +336 -0
- package/dist/cli/cmds/runNetwork.d.ts +3 -0
- package/dist/cli/cmds/runNetwork.d.ts.map +1 -0
- package/dist/cli/cmds/runNetwork.js +292 -0
- package/dist/cli/cmds/runTests.d.ts +12 -0
- package/dist/cli/cmds/runTests.d.ts.map +1 -0
- package/dist/cli/cmds/runTests.js +257 -0
- package/dist/cli/internal/cmdFunctions/downloader.d.ts +4 -0
- package/dist/cli/internal/cmdFunctions/downloader.d.ts.map +1 -0
- package/dist/cli/internal/cmdFunctions/downloader.js +49 -0
- package/dist/cli/internal/cmdFunctions/fetchArtifact.d.ts +10 -0
- package/dist/cli/internal/cmdFunctions/fetchArtifact.d.ts.map +1 -0
- package/dist/cli/internal/cmdFunctions/fetchArtifact.js +145 -0
- package/dist/cli/internal/cmdFunctions/index.d.ts +5 -0
- package/dist/cli/internal/cmdFunctions/index.d.ts.map +1 -0
- package/dist/cli/internal/cmdFunctions/index.js +4 -0
- package/dist/cli/internal/cmdFunctions/initialisation.d.ts +20 -0
- package/dist/cli/internal/cmdFunctions/initialisation.d.ts.map +1 -0
- package/dist/cli/internal/cmdFunctions/initialisation.js +150 -0
- package/dist/cli/internal/cmdFunctions/tempLogs.d.ts +3 -0
- package/dist/cli/internal/cmdFunctions/tempLogs.d.ts.map +1 -0
- package/dist/cli/internal/cmdFunctions/tempLogs.js +37 -0
- package/dist/cli/internal/commandParsers.d.ts +59 -0
- package/dist/cli/internal/commandParsers.d.ts.map +1 -0
- package/dist/cli/internal/commandParsers.js +305 -0
- package/dist/cli/internal/deriveTestIds.d.ts +8 -0
- package/dist/cli/internal/deriveTestIds.d.ts.map +1 -0
- package/dist/cli/internal/deriveTestIds.js +123 -0
- package/dist/cli/internal/effect/index.d.ts +6 -0
- package/dist/cli/internal/effect/index.d.ts.map +1 -0
- package/dist/cli/internal/effect/index.js +5 -0
- package/dist/cli/internal/fileCheckers.d.ts +11 -0
- package/dist/cli/internal/fileCheckers.d.ts.map +1 -0
- package/dist/cli/internal/fileCheckers.js +165 -0
- package/dist/cli/internal/foundations/index.d.ts +4 -0
- package/dist/cli/internal/foundations/index.d.ts.map +1 -0
- package/dist/cli/internal/foundations/index.js +4 -0
- package/dist/cli/internal/index.d.ts +12 -0
- package/dist/cli/internal/index.d.ts.map +1 -0
- package/dist/cli/internal/index.js +11 -0
- package/dist/cli/internal/launcherCommon.d.ts +4 -0
- package/dist/cli/internal/launcherCommon.d.ts.map +1 -0
- package/dist/cli/internal/launcherCommon.js +130 -0
- package/dist/cli/internal/localNode.d.ts +16 -0
- package/dist/cli/internal/localNode.d.ts.map +1 -0
- package/dist/cli/internal/localNode.js +362 -0
- package/dist/cli/internal/logging.d.ts +2 -0
- package/dist/cli/internal/logging.d.ts.map +1 -0
- package/dist/cli/internal/logging.js +26 -0
- package/dist/cli/internal/node.d.ts +33 -0
- package/dist/cli/internal/node.d.ts.map +1 -0
- package/dist/cli/internal/node.js +228 -0
- package/dist/cli/internal/processHelpers.d.ts +17 -0
- package/dist/cli/internal/processHelpers.d.ts.map +1 -0
- package/dist/cli/internal/processHelpers.js +56 -0
- package/dist/cli/internal/providerFactories.d.ts +48 -0
- package/dist/cli/internal/providerFactories.d.ts.map +1 -0
- package/dist/cli/internal/providerFactories.js +442 -0
- package/dist/cli/internal/testIdParser.d.ts +34 -0
- package/dist/cli/internal/testIdParser.d.ts.map +1 -0
- package/dist/cli/internal/testIdParser.js +167 -0
- package/dist/cli/lib/binariesHelpers.d.ts +15 -0
- package/dist/cli/lib/binariesHelpers.d.ts.map +1 -0
- package/dist/cli/lib/binariesHelpers.js +99 -0
- package/dist/cli/lib/configReader.d.ts +8 -0
- package/dist/cli/lib/configReader.d.ts.map +1 -0
- package/dist/cli/lib/configReader.js +115 -0
- package/dist/cli/lib/contractFunctions.d.ts +2 -0
- package/dist/cli/lib/contractFunctions.d.ts.map +1 -0
- package/dist/cli/lib/contractFunctions.js +2 -0
- package/dist/cli/lib/globalContext.d.ts +46 -0
- package/dist/cli/lib/globalContext.d.ts.map +1 -0
- package/dist/cli/lib/globalContext.js +710 -0
- package/dist/cli/lib/governanceProcedures.d.ts +27 -0
- package/dist/cli/lib/governanceProcedures.d.ts.map +1 -0
- package/dist/cli/lib/governanceProcedures.js +458 -0
- package/dist/cli/lib/handlers/index.d.ts +5 -0
- package/dist/cli/lib/handlers/index.d.ts.map +1 -0
- package/dist/cli/lib/handlers/index.js +5 -0
- package/dist/cli/lib/repoDefinitions/index.d.ts +6 -0
- package/dist/cli/lib/repoDefinitions/index.d.ts.map +1 -0
- package/dist/cli/lib/repoDefinitions/index.js +21 -0
- package/dist/cli/lib/repoDefinitions/moonbeam.d.ts +4 -0
- package/dist/cli/lib/repoDefinitions/moonbeam.d.ts.map +1 -0
- package/dist/cli/lib/repoDefinitions/moonbeam.js +30 -0
- package/dist/cli/lib/repoDefinitions/polkadot.d.ts +4 -0
- package/dist/cli/lib/repoDefinitions/polkadot.d.ts.map +1 -0
- package/dist/cli/lib/repoDefinitions/polkadot.js +11 -0
- package/dist/cli/lib/repoDefinitions/tanssi.d.ts +4 -0
- package/dist/cli/lib/repoDefinitions/tanssi.d.ts.map +1 -0
- package/dist/cli/lib/repoDefinitions/tanssi.js +14 -0
- package/dist/cli/lib/rpcFunctions.d.ts +2 -0
- package/dist/cli/lib/rpcFunctions.d.ts.map +1 -0
- package/dist/cli/lib/rpcFunctions.js +26 -0
- package/dist/cli/lib/runnerContext.d.ts +32 -0
- package/dist/cli/lib/runnerContext.d.ts.map +1 -0
- package/dist/cli/lib/runnerContext.js +156 -0
- package/dist/cli/lib/shardManager.d.ts +40 -0
- package/dist/cli/lib/shardManager.d.ts.map +1 -0
- package/dist/cli/lib/shardManager.js +80 -0
- package/dist/cli/lib/upgradeProcedures.d.ts +5 -0
- package/dist/cli/lib/upgradeProcedures.d.ts.map +1 -0
- package/dist/cli/lib/upgradeProcedures.js +221 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +3 -0
- package/dist/contracts/contractInteraction.d.ts +17 -0
- package/dist/contracts/contractInteraction.d.ts.map +1 -0
- package/dist/contracts/contractInteraction.js +170 -0
- package/dist/contracts/index.d.ts +2 -0
- package/dist/contracts/index.d.ts.map +1 -0
- package/dist/contracts/index.js +1 -0
- package/dist/foundations/chopsticks/handler.d.ts +3 -0
- package/dist/foundations/chopsticks/handler.d.ts.map +1 -0
- package/dist/foundations/chopsticks/handler.js +93 -0
- package/dist/foundations/chopsticks/helpers.d.ts +27 -0
- package/dist/foundations/chopsticks/helpers.d.ts.map +1 -0
- package/dist/foundations/chopsticks/helpers.js +133 -0
- package/dist/foundations/dev/handler.d.ts +3 -0
- package/dist/foundations/dev/handler.d.ts.map +1 -0
- package/dist/foundations/dev/handler.js +136 -0
- package/dist/foundations/dev/helpers.d.ts +27 -0
- package/dist/foundations/dev/helpers.d.ts.map +1 -0
- package/dist/foundations/dev/helpers.js +161 -0
- package/dist/foundations/read-only/handler.d.ts +3 -0
- package/dist/foundations/read-only/handler.d.ts.map +1 -0
- package/dist/foundations/read-only/handler.js +32 -0
- package/dist/foundations/zombie/handler.d.ts +3 -0
- package/dist/foundations/zombie/handler.d.ts.map +1 -0
- package/dist/foundations/zombie/handler.js +92 -0
- package/dist/foundations/zombie/helpers.d.ts +16 -0
- package/dist/foundations/zombie/helpers.d.ts.map +1 -0
- package/dist/foundations/zombie/helpers.js +97 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +47 -0
- package/dist/internal/common.d.ts +3 -0
- package/dist/internal/common.d.ts.map +1 -0
- package/dist/internal/common.js +41 -0
- package/dist/internal/index.d.ts +4 -0
- package/dist/internal/index.d.ts.map +1 -0
- package/dist/internal/index.js +3 -0
- package/dist/internal/logger.d.ts +24 -0
- package/dist/internal/logger.d.ts.map +1 -0
- package/dist/internal/logger.js +66 -0
- package/dist/internal/logging.d.ts +7 -0
- package/dist/internal/logging.d.ts.map +1 -0
- package/dist/internal/logging.js +36 -0
- package/dist/moondebug.d.ts +3 -0
- package/dist/moondebug.d.ts.map +1 -0
- package/dist/moondebug.js +2 -0
- package/dist/services/cache/FileLock.d.ts +11 -0
- package/dist/services/cache/FileLock.d.ts.map +1 -0
- package/dist/services/cache/FileLock.js +68 -0
- package/dist/services/cache/StartupCacheService.d.ts +23 -0
- package/dist/services/cache/StartupCacheService.d.ts.map +1 -0
- package/dist/services/cache/StartupCacheService.js +159 -0
- package/dist/services/cache/index.d.ts +3 -0
- package/dist/services/cache/index.d.ts.map +1 -0
- package/dist/services/cache/index.js +2 -0
- package/dist/services/chopsticks/ChopsticksMultiChain.d.ts +158 -0
- package/dist/services/chopsticks/ChopsticksMultiChain.d.ts.map +1 -0
- package/dist/services/chopsticks/ChopsticksMultiChain.js +282 -0
- package/dist/services/chopsticks/ChopsticksService.d.ts +313 -0
- package/dist/services/chopsticks/ChopsticksService.d.ts.map +1 -0
- package/dist/services/chopsticks/ChopsticksService.js +77 -0
- package/dist/services/chopsticks/chopsticksConfigParser.d.ts +40 -0
- package/dist/services/chopsticks/chopsticksConfigParser.d.ts.map +1 -0
- package/dist/services/chopsticks/chopsticksConfigParser.js +201 -0
- package/dist/services/chopsticks/index.d.ts +5 -0
- package/dist/services/chopsticks/index.d.ts.map +1 -0
- package/dist/services/chopsticks/index.js +4 -0
- package/dist/services/chopsticks/launchChopsticksEffect.d.ts +225 -0
- package/dist/services/chopsticks/launchChopsticksEffect.d.ts.map +1 -0
- package/dist/services/chopsticks/launchChopsticksEffect.js +623 -0
- package/dist/services/config/configAccessors.d.ts +41 -0
- package/dist/services/config/configAccessors.d.ts.map +1 -0
- package/dist/services/config/configAccessors.js +149 -0
- package/dist/services/config/index.d.ts +2 -0
- package/dist/services/config/index.d.ts.map +1 -0
- package/dist/services/config/index.js +1 -0
- package/dist/services/errors.d.ts +72 -0
- package/dist/services/errors.d.ts.map +1 -0
- package/dist/services/errors.js +31 -0
- package/dist/services/index.d.ts +7 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +6 -0
- package/dist/services/network/NodeReadinessService.d.ts +35 -0
- package/dist/services/network/NodeReadinessService.d.ts.map +1 -0
- package/dist/services/network/NodeReadinessService.js +120 -0
- package/dist/services/network/PortDiscoveryService.d.ts +22 -0
- package/dist/services/network/PortDiscoveryService.d.ts.map +1 -0
- package/dist/services/network/PortDiscoveryService.js +77 -0
- package/dist/services/network/RpcPortDiscoveryService.d.ts +25 -0
- package/dist/services/network/RpcPortDiscoveryService.d.ts.map +1 -0
- package/dist/services/network/RpcPortDiscoveryService.js +136 -0
- package/dist/services/network/index.d.ts +4 -0
- package/dist/services/network/index.d.ts.map +1 -0
- package/dist/services/network/index.js +3 -0
- package/dist/services/process/ProcessManagerService.d.ts +49 -0
- package/dist/services/process/ProcessManagerService.d.ts.map +1 -0
- package/dist/services/process/ProcessManagerService.js +162 -0
- package/dist/services/process/index.d.ts +3 -0
- package/dist/services/process/index.d.ts.map +1 -0
- package/dist/services/process/index.js +2 -0
- package/dist/services/process/launchNodeEffect.d.ts +40 -0
- package/dist/services/process/launchNodeEffect.d.ts.map +1 -0
- package/dist/services/process/launchNodeEffect.js +86 -0
- package/dist/util/functions/index.d.ts +3 -0
- package/dist/util/functions/index.d.ts.map +1 -0
- package/dist/util/functions/index.js +4 -0
- package/dist/util/index.d.ts +4 -0
- package/dist/util/index.d.ts.map +1 -0
- package/dist/util/index.js +2 -0
- package/package.json +157 -0
|
@@ -0,0 +1,623 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Effect-based Chopsticks launcher with manual cleanup support
|
|
3
|
+
*
|
|
4
|
+
* This module provides a programmatic way to launch chopsticks instances
|
|
5
|
+
* using the Effect pattern, replacing the previous CLI subprocess approach.
|
|
6
|
+
*
|
|
7
|
+
* Like launchNodeEffect, it returns a cleanup function rather than using
|
|
8
|
+
* Effect scopes, because the chopsticks instance needs to persist across
|
|
9
|
+
* test suites (not just a single Effect scope).
|
|
10
|
+
*/
|
|
11
|
+
import { Effect, Layer } from "effect";
|
|
12
|
+
import { createLogger } from "../../util/index.js";
|
|
13
|
+
import * as fs from "node:fs";
|
|
14
|
+
import * as path from "node:path";
|
|
15
|
+
// Re-export BuildBlockMode values for consumers who need them before dynamic import
|
|
16
|
+
// These match the values from @acala-network/chopsticks
|
|
17
|
+
export const BuildBlockModeValues = {
|
|
18
|
+
Batch: "Batch",
|
|
19
|
+
Manual: "Manual",
|
|
20
|
+
Instant: "Instant",
|
|
21
|
+
};
|
|
22
|
+
// Flag to track if chopsticks logger has been configured
|
|
23
|
+
let chopsticksLoggerConfigured = false;
|
|
24
|
+
// Cache for dynamically imported chopsticks modules
|
|
25
|
+
let chopsticksModuleCache = null;
|
|
26
|
+
import { ChopsticksService, ChopsticksConfigTag, ChopsticksSetupError, ChopsticksBlockError, ChopsticksStorageError, ChopsticksExtrinsicError, ChopsticksXcmError, ChopsticksCleanupError, } from "./ChopsticksService.js";
|
|
27
|
+
import { parseChopsticksConfigFile } from "./chopsticksConfigParser.js";
|
|
28
|
+
const logger = createLogger({ name: "launchChopsticksEffect" });
|
|
29
|
+
/**
|
|
30
|
+
* Create a log file for chopsticks output
|
|
31
|
+
* Returns the log file path and a write stream
|
|
32
|
+
*/
|
|
33
|
+
function createLogFile(port) {
|
|
34
|
+
const dirPath = path.join(process.cwd(), "tmp", "node_logs");
|
|
35
|
+
// Ensure directory exists
|
|
36
|
+
if (!fs.existsSync(dirPath)) {
|
|
37
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
38
|
+
}
|
|
39
|
+
const logPath = path.join(dirPath, `chopsticks_${port}_${Date.now()}.log`);
|
|
40
|
+
const writeStream = fs.createWriteStream(logPath);
|
|
41
|
+
// Set env var so other parts of moonwall can find it
|
|
42
|
+
process.env.MOON_LOG_LOCATION = logPath;
|
|
43
|
+
return { logPath, writeStream };
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Write a log entry to the chopsticks log file
|
|
47
|
+
*/
|
|
48
|
+
function writeLog(stream, level, message) {
|
|
49
|
+
const timestamp = new Date().toISOString();
|
|
50
|
+
stream.write(`[${timestamp}] [${level.toUpperCase()}] ${message}\n`);
|
|
51
|
+
}
|
|
52
|
+
// Store reference to log file stream for chopsticks integration
|
|
53
|
+
let chopsticksLogStream = null;
|
|
54
|
+
/**
|
|
55
|
+
* Set the log stream for chopsticks to write to
|
|
56
|
+
*/
|
|
57
|
+
export function setChopsticksLogStream(stream) {
|
|
58
|
+
chopsticksLogStream = stream;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Hook into a pino logger to also write to the moonwall log file
|
|
62
|
+
* This preserves the original pino-pretty console output while adding file logging
|
|
63
|
+
*/
|
|
64
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
65
|
+
function hookLoggerToFile(pinoInstance, loggerName) {
|
|
66
|
+
const wrapMethod = (level, originalMethod) => {
|
|
67
|
+
return function (...args) {
|
|
68
|
+
// Call original pino-pretty output
|
|
69
|
+
originalMethod.apply(this, args);
|
|
70
|
+
// Also write to our log file
|
|
71
|
+
if (chopsticksLogStream && args.length > 0) {
|
|
72
|
+
const timestamp = new Date().toISOString();
|
|
73
|
+
const message = typeof args[0] === "string" ? args[0] : JSON.stringify(args[0]);
|
|
74
|
+
chopsticksLogStream.write(`[${timestamp}] [${level.toUpperCase()}] (${loggerName}) ${message}\n`);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
// Wrap each log method
|
|
79
|
+
const originalInfo = pinoInstance.info.bind(pinoInstance);
|
|
80
|
+
const originalWarn = pinoInstance.warn.bind(pinoInstance);
|
|
81
|
+
const originalError = pinoInstance.error.bind(pinoInstance);
|
|
82
|
+
const originalDebug = pinoInstance.debug.bind(pinoInstance);
|
|
83
|
+
pinoInstance.info = wrapMethod("info", originalInfo);
|
|
84
|
+
pinoInstance.warn = wrapMethod("warn", originalWarn);
|
|
85
|
+
pinoInstance.error = wrapMethod("error", originalError);
|
|
86
|
+
pinoInstance.debug = wrapMethod("debug", originalDebug);
|
|
87
|
+
// Also wrap child method to hook child loggers
|
|
88
|
+
const originalChild = pinoInstance.child?.bind(pinoInstance);
|
|
89
|
+
if (originalChild) {
|
|
90
|
+
pinoInstance.child = (bindings) => {
|
|
91
|
+
const child = originalChild(bindings);
|
|
92
|
+
const childName = bindings.name || bindings.child || loggerName;
|
|
93
|
+
hookLoggerToFile(child, childName);
|
|
94
|
+
return child;
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Configure the chopsticks internal logger (synchronous version)
|
|
100
|
+
* Only works if chopsticks has already been imported.
|
|
101
|
+
*/
|
|
102
|
+
export function configureChopsticksLogger(level = "inherit") {
|
|
103
|
+
// Only configure once - first call wins
|
|
104
|
+
if (chopsticksLoggerConfigured) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
// If chopsticks hasn't been loaded yet, mark as configured so
|
|
108
|
+
// getChopsticksModules will handle it
|
|
109
|
+
chopsticksLoggerConfigured = true;
|
|
110
|
+
if (!chopsticksModuleCache) {
|
|
111
|
+
// Will be configured when modules are loaded
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const resolvedLevel = level === "inherit" ? process.env.LOG_LEVEL || "info" : level;
|
|
115
|
+
chopsticksModuleCache.pinoLogger.level = resolvedLevel;
|
|
116
|
+
logger.debug(`Chopsticks internal logger level: ${resolvedLevel}`);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Get chopsticks modules, dynamically importing if needed.
|
|
120
|
+
* Also hooks the chopsticks logger to write to our log file.
|
|
121
|
+
*
|
|
122
|
+
* @param logLevel - Log level to use (default: inherit from LOG_LEVEL env)
|
|
123
|
+
*/
|
|
124
|
+
async function getChopsticksModules(logLevel = "inherit") {
|
|
125
|
+
if (chopsticksModuleCache) {
|
|
126
|
+
return chopsticksModuleCache;
|
|
127
|
+
}
|
|
128
|
+
// Dynamically import chopsticks
|
|
129
|
+
const chopsticks = await import("@acala-network/chopsticks");
|
|
130
|
+
chopsticksModuleCache = {
|
|
131
|
+
setupWithServer: chopsticks.setupWithServer,
|
|
132
|
+
setStorage: chopsticks.setStorage,
|
|
133
|
+
pinoLogger: chopsticks.pinoLogger,
|
|
134
|
+
defaultLogger: chopsticks.defaultLogger,
|
|
135
|
+
};
|
|
136
|
+
// Configure log level if specified
|
|
137
|
+
const resolvedLevel = logLevel === "inherit" ? process.env.LOG_LEVEL || "info" : logLevel;
|
|
138
|
+
chopsticksModuleCache.pinoLogger.level = resolvedLevel;
|
|
139
|
+
// Hook the defaultLogger (and future children) to also write to our log file
|
|
140
|
+
hookLoggerToFile(chopsticksModuleCache.defaultLogger, "chopsticks");
|
|
141
|
+
chopsticksLoggerConfigured = true;
|
|
142
|
+
logger.debug(`Chopsticks internal logger level: ${resolvedLevel}`);
|
|
143
|
+
return chopsticksModuleCache;
|
|
144
|
+
}
|
|
145
|
+
// =============================================================================
|
|
146
|
+
// Helper Functions
|
|
147
|
+
// =============================================================================
|
|
148
|
+
/**
|
|
149
|
+
* Extract a single endpoint string from the config.
|
|
150
|
+
* The ChopsticksConfig endpoint can be a string, array of strings, or undefined.
|
|
151
|
+
*/
|
|
152
|
+
const getEndpointString = (endpoint) => {
|
|
153
|
+
if (typeof endpoint === "string")
|
|
154
|
+
return endpoint;
|
|
155
|
+
if (Array.isArray(endpoint))
|
|
156
|
+
return endpoint[0];
|
|
157
|
+
return undefined;
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* Prepare ChopsticksConfig for setupWithServer by ensuring defaults.
|
|
161
|
+
*
|
|
162
|
+
* Since ChopsticksConfig is now the native chopsticks type (with kebab-case keys),
|
|
163
|
+
* we just need to ensure required defaults are set.
|
|
164
|
+
*/
|
|
165
|
+
const prepareConfigForSetup = (config) => ({
|
|
166
|
+
...config,
|
|
167
|
+
port: config.port ?? 8000,
|
|
168
|
+
host: config.host ?? "127.0.0.1",
|
|
169
|
+
"build-block-mode": config["build-block-mode"] ?? "Manual",
|
|
170
|
+
});
|
|
171
|
+
/**
|
|
172
|
+
* Create service implementation methods that wrap the chain's methods in Effects
|
|
173
|
+
*/
|
|
174
|
+
const createServiceMethods = (chain) => ({
|
|
175
|
+
createBlock: (params) => Effect.tryPromise({
|
|
176
|
+
try: async () => {
|
|
177
|
+
const block = await chain.newBlock({
|
|
178
|
+
transactions: params?.transactions ?? [],
|
|
179
|
+
upwardMessages: params?.ump ?? {},
|
|
180
|
+
downwardMessages: params?.dmp ?? [],
|
|
181
|
+
horizontalMessages: params?.hrmp ?? {},
|
|
182
|
+
});
|
|
183
|
+
return {
|
|
184
|
+
block: {
|
|
185
|
+
hash: block.hash,
|
|
186
|
+
number: block.number,
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
},
|
|
190
|
+
catch: (cause) => new ChopsticksBlockError({
|
|
191
|
+
cause,
|
|
192
|
+
operation: "newBlock",
|
|
193
|
+
}),
|
|
194
|
+
}),
|
|
195
|
+
setStorage: (params) => Effect.tryPromise({
|
|
196
|
+
try: async () => {
|
|
197
|
+
// Use the chopsticks utility function to set storage
|
|
198
|
+
const storage = { [params.module]: { [params.method]: params.params } };
|
|
199
|
+
const modules = await getChopsticksModules();
|
|
200
|
+
await modules.setStorage(chain, storage);
|
|
201
|
+
},
|
|
202
|
+
catch: (cause) => new ChopsticksStorageError({
|
|
203
|
+
cause,
|
|
204
|
+
module: params.module,
|
|
205
|
+
method: params.method,
|
|
206
|
+
}),
|
|
207
|
+
}),
|
|
208
|
+
submitExtrinsic: (extrinsic) => Effect.tryPromise({
|
|
209
|
+
try: () => chain.submitExtrinsic(extrinsic),
|
|
210
|
+
catch: (cause) => new ChopsticksExtrinsicError({
|
|
211
|
+
cause,
|
|
212
|
+
operation: "submit",
|
|
213
|
+
extrinsic,
|
|
214
|
+
}),
|
|
215
|
+
}),
|
|
216
|
+
dryRunExtrinsic: (extrinsic, at) => Effect.tryPromise({
|
|
217
|
+
try: async () => {
|
|
218
|
+
const result = await chain.dryRunExtrinsic(extrinsic, at);
|
|
219
|
+
const isOk = result.outcome.isOk;
|
|
220
|
+
return {
|
|
221
|
+
success: isOk,
|
|
222
|
+
storageDiff: result.storageDiff,
|
|
223
|
+
error: isOk ? undefined : result.outcome.asErr?.toString(),
|
|
224
|
+
};
|
|
225
|
+
},
|
|
226
|
+
catch: (cause) => new ChopsticksExtrinsicError({
|
|
227
|
+
cause,
|
|
228
|
+
operation: "dryRun",
|
|
229
|
+
extrinsic: typeof extrinsic === "string" ? extrinsic : extrinsic.call,
|
|
230
|
+
}),
|
|
231
|
+
}),
|
|
232
|
+
getBlock: (hashOrNumber) => Effect.tryPromise({
|
|
233
|
+
try: async () => {
|
|
234
|
+
const block = hashOrNumber === undefined
|
|
235
|
+
? chain.head
|
|
236
|
+
: typeof hashOrNumber === "number"
|
|
237
|
+
? await chain.getBlockAt(hashOrNumber)
|
|
238
|
+
: await chain.getBlock(hashOrNumber);
|
|
239
|
+
if (!block)
|
|
240
|
+
return undefined;
|
|
241
|
+
return {
|
|
242
|
+
hash: block.hash,
|
|
243
|
+
number: block.number,
|
|
244
|
+
};
|
|
245
|
+
},
|
|
246
|
+
catch: (cause) => new ChopsticksBlockError({
|
|
247
|
+
cause,
|
|
248
|
+
operation: "getBlock",
|
|
249
|
+
blockIdentifier: hashOrNumber,
|
|
250
|
+
}),
|
|
251
|
+
}),
|
|
252
|
+
setHead: (hashOrNumber) => Effect.tryPromise({
|
|
253
|
+
try: async () => {
|
|
254
|
+
const block = typeof hashOrNumber === "number"
|
|
255
|
+
? await chain.getBlockAt(hashOrNumber)
|
|
256
|
+
: await chain.getBlock(hashOrNumber);
|
|
257
|
+
if (!block) {
|
|
258
|
+
throw new Error(`Block not found: ${hashOrNumber}`);
|
|
259
|
+
}
|
|
260
|
+
await chain.setHead(block);
|
|
261
|
+
},
|
|
262
|
+
catch: (cause) => new ChopsticksBlockError({
|
|
263
|
+
cause,
|
|
264
|
+
operation: "setHead",
|
|
265
|
+
blockIdentifier: hashOrNumber,
|
|
266
|
+
}),
|
|
267
|
+
}),
|
|
268
|
+
submitUpwardMessages: (paraId, messages) => Effect.try({
|
|
269
|
+
try: () => chain.submitUpwardMessages(paraId, messages),
|
|
270
|
+
catch: (cause) => new ChopsticksXcmError({
|
|
271
|
+
cause,
|
|
272
|
+
messageType: "ump",
|
|
273
|
+
paraId,
|
|
274
|
+
}),
|
|
275
|
+
}),
|
|
276
|
+
submitDownwardMessages: (messages) => Effect.try({
|
|
277
|
+
try: () => chain.submitDownwardMessages(messages),
|
|
278
|
+
catch: (cause) => new ChopsticksXcmError({
|
|
279
|
+
cause,
|
|
280
|
+
messageType: "dmp",
|
|
281
|
+
}),
|
|
282
|
+
}),
|
|
283
|
+
submitHorizontalMessages: (paraId, messages) => Effect.try({
|
|
284
|
+
try: () => chain.submitHorizontalMessages(paraId, messages),
|
|
285
|
+
catch: (cause) => new ChopsticksXcmError({
|
|
286
|
+
cause,
|
|
287
|
+
messageType: "hrmp",
|
|
288
|
+
paraId,
|
|
289
|
+
}),
|
|
290
|
+
}),
|
|
291
|
+
});
|
|
292
|
+
// =============================================================================
|
|
293
|
+
// Main Launch Function
|
|
294
|
+
// =============================================================================
|
|
295
|
+
/**
|
|
296
|
+
* Launch a chopsticks instance with manual cleanup support
|
|
297
|
+
*
|
|
298
|
+
* This function uses the programmatic setupWithServer API from @acala-network/chopsticks
|
|
299
|
+
* instead of spawning a CLI subprocess. It returns the chopsticks instance along with
|
|
300
|
+
* a cleanup function that should be called when the instance is no longer needed.
|
|
301
|
+
*
|
|
302
|
+
* @param config - Chopsticks configuration
|
|
303
|
+
* @returns Promise with the launch result and cleanup function
|
|
304
|
+
*
|
|
305
|
+
* @example
|
|
306
|
+
* ```typescript
|
|
307
|
+
* const { result, cleanup } = await launchChopsticksEffect({
|
|
308
|
+
* endpoint: "wss://rpc.polkadot.io",
|
|
309
|
+
* port: 8000,
|
|
310
|
+
* buildBlockMode: BuildBlockMode.Manual,
|
|
311
|
+
* });
|
|
312
|
+
*
|
|
313
|
+
* // Use the chopsticks instance
|
|
314
|
+
* const block = await Effect.runPromise(result.createBlock());
|
|
315
|
+
*
|
|
316
|
+
* // When done, cleanup
|
|
317
|
+
* await cleanup();
|
|
318
|
+
* ```
|
|
319
|
+
*/
|
|
320
|
+
export async function launchChopsticksEffect(config) {
|
|
321
|
+
const startTime = Date.now();
|
|
322
|
+
logger.debug(`[T+0ms] Starting chopsticks with endpoint: ${config.endpoint}`);
|
|
323
|
+
// Create log file BEFORE loading chopsticks modules so the logger hooks can use it
|
|
324
|
+
const port = config.port ?? 8000;
|
|
325
|
+
const { logPath, writeStream } = createLogFile(port);
|
|
326
|
+
setChopsticksLogStream(writeStream);
|
|
327
|
+
const program = Effect.gen(function* () {
|
|
328
|
+
// Get chopsticks modules - this also configures and hooks the logger
|
|
329
|
+
const chopsticksModules = yield* Effect.promise(() => getChopsticksModules("inherit"));
|
|
330
|
+
// Convert config to chopsticks format
|
|
331
|
+
const args = prepareConfigForSetup(config);
|
|
332
|
+
logger.debug(`[T+${Date.now() - startTime}ms] Calling setupWithServer...`);
|
|
333
|
+
// Setup chopsticks programmatically
|
|
334
|
+
const context = yield* Effect.tryPromise({
|
|
335
|
+
try: () => chopsticksModules.setupWithServer(args),
|
|
336
|
+
catch: (cause) => new ChopsticksSetupError({
|
|
337
|
+
cause,
|
|
338
|
+
endpoint: getEndpointString(config.endpoint),
|
|
339
|
+
block: config.block ?? undefined,
|
|
340
|
+
}),
|
|
341
|
+
});
|
|
342
|
+
// Parse actual port from addr (format: "host:port")
|
|
343
|
+
const actualPort = Number.parseInt(context.addr.split(":")[1], 10);
|
|
344
|
+
// Log with moonwall's logger for consistent formatting
|
|
345
|
+
const chainName = yield* Effect.promise(() => context.chain.api.getSystemChain());
|
|
346
|
+
logger.info(`${chainName} RPC listening on ws://${context.addr}`);
|
|
347
|
+
logger.debug(`[T+${Date.now() - startTime}ms] Chopsticks started at ${context.addr}`);
|
|
348
|
+
logger.debug(`Log file: ${logPath}`);
|
|
349
|
+
// Write startup info to log file
|
|
350
|
+
writeLog(writeStream, "info", `Chopsticks started for ${chainName}`);
|
|
351
|
+
writeLog(writeStream, "info", `RPC listening on ws://${context.addr}`);
|
|
352
|
+
writeLog(writeStream, "info", `Endpoint: ${config.endpoint}`);
|
|
353
|
+
if (config.block) {
|
|
354
|
+
writeLog(writeStream, "info", `Block: ${config.block}`);
|
|
355
|
+
}
|
|
356
|
+
// Create the cleanup effect
|
|
357
|
+
const cleanup = Effect.tryPromise({
|
|
358
|
+
try: async () => {
|
|
359
|
+
logger.debug("Closing chopsticks...");
|
|
360
|
+
writeLog(writeStream, "info", "Shutting down chopsticks...");
|
|
361
|
+
await context.close();
|
|
362
|
+
writeLog(writeStream, "info", "Chopsticks closed");
|
|
363
|
+
setChopsticksLogStream(null); // Stop writing to file
|
|
364
|
+
writeStream.end();
|
|
365
|
+
logger.debug("Chopsticks closed");
|
|
366
|
+
},
|
|
367
|
+
catch: (cause) => new ChopsticksCleanupError({ cause }),
|
|
368
|
+
}).pipe(Effect.catchAll((error) => Effect.sync(() => {
|
|
369
|
+
logger.error(`Failed to cleanly close chopsticks: ${error}`);
|
|
370
|
+
writeLog(writeStream, "error", `Failed to close: ${error}`);
|
|
371
|
+
setChopsticksLogStream(null);
|
|
372
|
+
writeStream.end();
|
|
373
|
+
})));
|
|
374
|
+
// Create the service implementation
|
|
375
|
+
const serviceMethods = createServiceMethods(context.chain);
|
|
376
|
+
const service = {
|
|
377
|
+
chain: context.chain,
|
|
378
|
+
addr: context.addr,
|
|
379
|
+
port: actualPort,
|
|
380
|
+
...serviceMethods,
|
|
381
|
+
};
|
|
382
|
+
return { service, cleanup };
|
|
383
|
+
});
|
|
384
|
+
// Run the program and return result with cleanup function
|
|
385
|
+
const { service, cleanup } = await Effect.runPromise(program);
|
|
386
|
+
return {
|
|
387
|
+
result: service,
|
|
388
|
+
cleanup: () => Effect.runPromise(cleanup),
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Launch chopsticks as an Effect (for use within Effect pipelines)
|
|
393
|
+
*
|
|
394
|
+
* Unlike launchChopsticksEffect, this version returns the result as an Effect
|
|
395
|
+
* rather than a Promise. Use this when you want to compose the launch with
|
|
396
|
+
* other Effects.
|
|
397
|
+
*
|
|
398
|
+
* @param config - Chopsticks configuration
|
|
399
|
+
* @returns Effect with launch result and cleanup
|
|
400
|
+
*/
|
|
401
|
+
export const launchChopsticksEffectProgram = (config) => Effect.gen(function* () {
|
|
402
|
+
const chopsticksModules = yield* Effect.promise(() => getChopsticksModules("silent"));
|
|
403
|
+
const args = prepareConfigForSetup(config);
|
|
404
|
+
const context = yield* Effect.tryPromise({
|
|
405
|
+
try: () => chopsticksModules.setupWithServer(args),
|
|
406
|
+
catch: (cause) => new ChopsticksSetupError({
|
|
407
|
+
cause,
|
|
408
|
+
endpoint: getEndpointString(config.endpoint),
|
|
409
|
+
block: config.block ?? undefined,
|
|
410
|
+
}),
|
|
411
|
+
});
|
|
412
|
+
const port = Number.parseInt(context.addr.split(":")[1], 10);
|
|
413
|
+
const cleanup = Effect.tryPromise({
|
|
414
|
+
try: () => context.close(),
|
|
415
|
+
catch: (cause) => new ChopsticksCleanupError({ cause }),
|
|
416
|
+
}).pipe(Effect.catchAll((error) => Effect.sync(() => {
|
|
417
|
+
logger.error(`Failed to cleanly close chopsticks: ${error}`);
|
|
418
|
+
})));
|
|
419
|
+
const serviceMethods = createServiceMethods(context.chain);
|
|
420
|
+
const service = {
|
|
421
|
+
chain: context.chain,
|
|
422
|
+
addr: context.addr,
|
|
423
|
+
port,
|
|
424
|
+
...serviceMethods,
|
|
425
|
+
};
|
|
426
|
+
return { result: service, cleanup };
|
|
427
|
+
});
|
|
428
|
+
/**
|
|
429
|
+
* Acquire a chopsticks instance with automatic cleanup on scope finalization
|
|
430
|
+
*
|
|
431
|
+
* This uses Effect.acquireRelease to ensure the chopsticks instance is properly
|
|
432
|
+
* cleaned up when the Effect scope ends, even if an error occurs.
|
|
433
|
+
*/
|
|
434
|
+
const acquireChopsticks = (config) => Effect.acquireRelease(
|
|
435
|
+
// Acquire: Setup chopsticks (first get modules, then setup)
|
|
436
|
+
Effect.promise(() => getChopsticksModules("silent")).pipe(Effect.flatMap((modules) => Effect.tryPromise({
|
|
437
|
+
try: () => modules.setupWithServer(prepareConfigForSetup(config)),
|
|
438
|
+
catch: (cause) => new ChopsticksSetupError({
|
|
439
|
+
cause,
|
|
440
|
+
endpoint: getEndpointString(config.endpoint),
|
|
441
|
+
block: config.block ?? undefined,
|
|
442
|
+
}),
|
|
443
|
+
})), Effect.tap((context) => Effect.sync(() => logger.debug(`Chopsticks started at ${context.addr}`)))),
|
|
444
|
+
// Release: Cleanup chopsticks
|
|
445
|
+
(context) => Effect.tryPromise({
|
|
446
|
+
try: async () => {
|
|
447
|
+
logger.debug("Closing chopsticks...");
|
|
448
|
+
await context.close();
|
|
449
|
+
logger.debug("Chopsticks closed");
|
|
450
|
+
},
|
|
451
|
+
catch: (cause) => new ChopsticksCleanupError({ cause }),
|
|
452
|
+
}).pipe(Effect.catchAll((error) => Effect.sync(() => {
|
|
453
|
+
logger.error(`Failed to cleanly close chopsticks: ${error}`);
|
|
454
|
+
}))));
|
|
455
|
+
/**
|
|
456
|
+
* Create a ChopsticksService Layer that automatically manages the chopsticks lifecycle
|
|
457
|
+
*
|
|
458
|
+
* This Layer uses Effect.acquireRelease under the hood, ensuring that the chopsticks
|
|
459
|
+
* instance is properly cleaned up when the Layer scope ends (e.g., when the test
|
|
460
|
+
* suite finishes or when Effect.runPromise completes).
|
|
461
|
+
*
|
|
462
|
+
* @param config - Chopsticks configuration
|
|
463
|
+
* @returns A scoped Layer providing ChopsticksService
|
|
464
|
+
*
|
|
465
|
+
* @example
|
|
466
|
+
* ```typescript
|
|
467
|
+
* const program = Effect.gen(function* () {
|
|
468
|
+
* const chopsticks = yield* ChopsticksService;
|
|
469
|
+
* const block = yield* chopsticks.createBlock();
|
|
470
|
+
* return block;
|
|
471
|
+
* });
|
|
472
|
+
*
|
|
473
|
+
* // The chopsticks instance will be automatically cleaned up when runPromise completes
|
|
474
|
+
* const result = await Effect.runPromise(
|
|
475
|
+
* program.pipe(
|
|
476
|
+
* Effect.provide(ChopsticksServiceLayer({
|
|
477
|
+
* endpoint: "wss://rpc.polkadot.io",
|
|
478
|
+
* port: 8000,
|
|
479
|
+
* }))
|
|
480
|
+
* )
|
|
481
|
+
* );
|
|
482
|
+
* ```
|
|
483
|
+
*/
|
|
484
|
+
export const ChopsticksServiceLayer = (config) => Layer.scoped(ChopsticksService, Effect.gen(function* () {
|
|
485
|
+
const context = yield* acquireChopsticks(config);
|
|
486
|
+
const port = Number.parseInt(context.addr.split(":")[1], 10);
|
|
487
|
+
const serviceMethods = createServiceMethods(context.chain);
|
|
488
|
+
return {
|
|
489
|
+
chain: context.chain,
|
|
490
|
+
addr: context.addr,
|
|
491
|
+
port,
|
|
492
|
+
...serviceMethods,
|
|
493
|
+
};
|
|
494
|
+
}));
|
|
495
|
+
/**
|
|
496
|
+
* Create a ChopsticksService Layer from a ChopsticksConfigTag dependency
|
|
497
|
+
*
|
|
498
|
+
* This Layer reads the configuration from the ChopsticksConfigTag context,
|
|
499
|
+
* allowing for dependency injection of the configuration.
|
|
500
|
+
*
|
|
501
|
+
* @example
|
|
502
|
+
* ```typescript
|
|
503
|
+
* const configLayer = Layer.succeed(ChopsticksConfigTag, {
|
|
504
|
+
* endpoint: "wss://rpc.polkadot.io",
|
|
505
|
+
* port: 8000,
|
|
506
|
+
* });
|
|
507
|
+
*
|
|
508
|
+
* const program = Effect.gen(function* () {
|
|
509
|
+
* const chopsticks = yield* ChopsticksService;
|
|
510
|
+
* return chopsticks.addr;
|
|
511
|
+
* });
|
|
512
|
+
*
|
|
513
|
+
* const result = await Effect.runPromise(
|
|
514
|
+
* program.pipe(
|
|
515
|
+
* Effect.provide(ChopsticksServiceLive),
|
|
516
|
+
* Effect.provide(configLayer)
|
|
517
|
+
* )
|
|
518
|
+
* );
|
|
519
|
+
* ```
|
|
520
|
+
*/
|
|
521
|
+
export const ChopsticksServiceLive = Layer.scoped(ChopsticksService, Effect.gen(function* () {
|
|
522
|
+
const config = yield* ChopsticksConfigTag;
|
|
523
|
+
const context = yield* acquireChopsticks(config);
|
|
524
|
+
const port = Number.parseInt(context.addr.split(":")[1], 10);
|
|
525
|
+
const serviceMethods = createServiceMethods(context.chain);
|
|
526
|
+
return {
|
|
527
|
+
chain: context.chain,
|
|
528
|
+
addr: context.addr,
|
|
529
|
+
port,
|
|
530
|
+
...serviceMethods,
|
|
531
|
+
};
|
|
532
|
+
}));
|
|
533
|
+
/**
|
|
534
|
+
* Launch chopsticks from a ChopsticksLaunchSpec by parsing the YAML config file
|
|
535
|
+
* and using the programmatic API.
|
|
536
|
+
*
|
|
537
|
+
* This function bridges the existing Moonwall config format to the new
|
|
538
|
+
* programmatic chopsticks launcher, providing:
|
|
539
|
+
* - Early validation of the config file (including env var resolution)
|
|
540
|
+
* - Clear error messages for missing/invalid config
|
|
541
|
+
* - Proper Effect-based error handling
|
|
542
|
+
*
|
|
543
|
+
* @param spec - The ChopsticksLaunchSpec from moonwall config
|
|
544
|
+
* @param options - Additional options
|
|
545
|
+
* @returns Promise with the launch result and cleanup function
|
|
546
|
+
*
|
|
547
|
+
* @example
|
|
548
|
+
* ```typescript
|
|
549
|
+
* const result = await launchChopsticksFromSpec({
|
|
550
|
+
* configPath: "./chopsticks-config.yml",
|
|
551
|
+
* wsPort: 8000,
|
|
552
|
+
* buildBlockMode: "manual",
|
|
553
|
+
* });
|
|
554
|
+
*
|
|
555
|
+
* // Use the service
|
|
556
|
+
* await Effect.runPromise(result.service.createBlock());
|
|
557
|
+
*
|
|
558
|
+
* // Cleanup when done
|
|
559
|
+
* await result.cleanup();
|
|
560
|
+
* ```
|
|
561
|
+
*/
|
|
562
|
+
export async function launchChopsticksFromSpec(spec, options) {
|
|
563
|
+
const timeout = options?.timeout ?? 60000;
|
|
564
|
+
const startTime = Date.now();
|
|
565
|
+
// Note: Logger configuration is now handled in getChopsticksModules() when
|
|
566
|
+
// chopsticks is dynamically imported. The chopsticksLogLevel option is kept
|
|
567
|
+
// for backwards compatibility but has no effect.
|
|
568
|
+
logger.debug(`Launching chopsticks from spec: ${spec.configPath}`);
|
|
569
|
+
// Parse and validate the config file (with env var resolution)
|
|
570
|
+
const parseEffect = parseChopsticksConfigFile(spec.configPath, {
|
|
571
|
+
port: spec.wsPort,
|
|
572
|
+
host: spec.address,
|
|
573
|
+
buildBlockMode: spec.buildBlockMode,
|
|
574
|
+
wasmOverride: spec.wasmOverride,
|
|
575
|
+
allowUnresolvedImports: spec.allowUnresolvedImports,
|
|
576
|
+
});
|
|
577
|
+
// Add timeout to the parse + launch operation
|
|
578
|
+
let configResult;
|
|
579
|
+
try {
|
|
580
|
+
configResult = await Effect.runPromise(parseEffect.pipe(Effect.timeout(timeout), Effect.catchTag("TimeoutException", () => Effect.fail(new ChopsticksSetupError({
|
|
581
|
+
cause: new Error(`Config parsing timed out after ${timeout}ms`),
|
|
582
|
+
endpoint: spec.configPath,
|
|
583
|
+
})))));
|
|
584
|
+
}
|
|
585
|
+
catch (error) {
|
|
586
|
+
// Re-throw with clearer message that includes the actual cause
|
|
587
|
+
// Effect errors format their toString() nicely, extract the [cause] part if present
|
|
588
|
+
const errorString = String(error);
|
|
589
|
+
// Extract the relevant cause message from Effect's error format
|
|
590
|
+
// Format: "(FiberFailure) ChopsticksSetupError: ... [cause]: Error: actual message"
|
|
591
|
+
const causeMatch = errorString.match(/\[cause\]:\s*Error:\s*(.+)/s);
|
|
592
|
+
if (causeMatch) {
|
|
593
|
+
throw new Error(`Chopsticks config validation failed: ${causeMatch[1].trim()}`);
|
|
594
|
+
}
|
|
595
|
+
// Fallback to full error string
|
|
596
|
+
throw new Error(`Chopsticks config validation failed: ${errorString}`);
|
|
597
|
+
}
|
|
598
|
+
logger.debug(`Config parsed in ${Date.now() - startTime}ms`);
|
|
599
|
+
logger.debug(` endpoint: ${configResult.endpoint}`);
|
|
600
|
+
logger.debug(` port: ${configResult.port}`);
|
|
601
|
+
// Launch using the programmatic API
|
|
602
|
+
let service;
|
|
603
|
+
let cleanup;
|
|
604
|
+
try {
|
|
605
|
+
const result = await launchChopsticksEffect(configResult);
|
|
606
|
+
service = result.result;
|
|
607
|
+
cleanup = result.cleanup;
|
|
608
|
+
}
|
|
609
|
+
catch (error) {
|
|
610
|
+
// Re-throw with clearer message - use same extraction as config validation
|
|
611
|
+
const errorString = String(error);
|
|
612
|
+
const causeMatch = errorString.match(/\[cause\]:\s*Error:\s*(.+)/s);
|
|
613
|
+
const causeMessage = causeMatch ? causeMatch[1].trim() : errorString;
|
|
614
|
+
throw new Error(`Chopsticks failed to connect to endpoint '${configResult.endpoint}': ${causeMessage}`);
|
|
615
|
+
}
|
|
616
|
+
logger.debug(`Chopsticks launched in ${Date.now() - startTime}ms at ${service.addr}`);
|
|
617
|
+
return {
|
|
618
|
+
service,
|
|
619
|
+
cleanup,
|
|
620
|
+
port: service.port,
|
|
621
|
+
addr: service.addr,
|
|
622
|
+
};
|
|
623
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { MoonwallConfig, Environment } from "../../api/types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Sets the cached config. Used by async loaders to populate the cache.
|
|
4
|
+
* @internal
|
|
5
|
+
*/
|
|
6
|
+
export declare function setCachedConfig(config: MoonwallConfig): void;
|
|
7
|
+
/**
|
|
8
|
+
* Gets the cached config if available.
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
export declare function getCachedConfig(): MoonwallConfig | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Imports the Moonwall config from the path specified in MOON_CONFIG_PATH.
|
|
14
|
+
* Uses a cached version if available.
|
|
15
|
+
*/
|
|
16
|
+
export declare function importJsonConfig(): MoonwallConfig;
|
|
17
|
+
/**
|
|
18
|
+
* Caches the config from the MOON_CONFIG_PATH environment variable.
|
|
19
|
+
*/
|
|
20
|
+
export declare function cacheConfig(): void;
|
|
21
|
+
/**
|
|
22
|
+
* Gets the current environment configuration based on MOON_TEST_ENV.
|
|
23
|
+
*/
|
|
24
|
+
export declare function getEnvironmentFromConfig(): Environment;
|
|
25
|
+
/**
|
|
26
|
+
* Checks if the current environment is an Ethereum-compatible dev config.
|
|
27
|
+
*/
|
|
28
|
+
export declare function isEthereumDevConfig(): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Checks if the current environment is an Ethereum-compatible zombie config.
|
|
31
|
+
*/
|
|
32
|
+
export declare function isEthereumZombieConfig(): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Checks if a specific option is set in the current environment config.
|
|
35
|
+
*/
|
|
36
|
+
export declare function isOptionSet(option: string): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Loads environment variables defined in the current environment config.
|
|
39
|
+
*/
|
|
40
|
+
export declare function loadEnvVars(): void;
|
|
41
|
+
//# sourceMappingURL=configAccessors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configAccessors.d.ts","sourceRoot":"","sources":["../../../src/services/config/configAccessors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,iCAAiC;AAO5E;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAE5D;AAED;;;GAGG;AACH,wBAAgB,eAAe,IAAI,cAAc,GAAG,SAAS,CAE5D;AAsCD;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,cAAc,CAsBjD;AAED;;GAEG;AACH,wBAAgB,WAAW,SAe1B;AAED;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,WAAW,CAStD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAG7C;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAGhD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAKnD;AAmBD;;GAEG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAOlC"}
|