From 226eda9015ce915ea8bb7864bdf8ab51398433ae Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Wed, 20 Nov 2024 14:34:54 -0500 Subject: [PATCH 1/2] chore(cosmic-swingset): Type-check JS files --- packages/cosmic-swingset/tsconfig.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/cosmic-swingset/tsconfig.json b/packages/cosmic-swingset/tsconfig.json index 993dde391d7..ac54f062118 100644 --- a/packages/cosmic-swingset/tsconfig.json +++ b/packages/cosmic-swingset/tsconfig.json @@ -1,9 +1,6 @@ // This file can contain .js-specific Typescript compiler config. { "extends": "../../tsconfig.json", - "compilerOptions": { - "checkJs": false, - }, "include": [ "calc-*.js", "src/**/*.js", From a9fdcea5a6e05b3aa514653f53046f1086c8bcb7 Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Wed, 20 Nov 2024 14:34:54 -0500 Subject: [PATCH 2/2] chore(cosmic-swingset): Fix lint issues --- .../cosmic-swingset/src/anylogger-agoric.js | 4 +- packages/cosmic-swingset/src/chain-main.js | 8 ++- packages/cosmic-swingset/src/entrypoint.js | 4 +- .../src/helpers/bufferedStorage.js | 20 ++++--- packages/cosmic-swingset/src/sim-chain.js | 54 ++++++++++++------- .../test/clean-core-eval.test.js | 2 + packages/cosmic-swingset/test/gov-code.js | 1 + .../test/provision-smartwallet.test.js | 3 +- .../cosmic-swingset/test/run-policy.test.js | 2 + packages/cosmic-swingset/tools/test-kit.js | 2 + packages/internal/src/chain-utils.js | 1 + packages/swingset-liveslots/src/liveslots.js | 2 +- 12 files changed, 65 insertions(+), 38 deletions(-) diff --git a/packages/cosmic-swingset/src/anylogger-agoric.js b/packages/cosmic-swingset/src/anylogger-agoric.js index d870c48cb3e..92353c40e0a 100644 --- a/packages/cosmic-swingset/src/anylogger-agoric.js +++ b/packages/cosmic-swingset/src/anylogger-agoric.js @@ -32,8 +32,8 @@ const selectedCode = anylogger.levels[selectedLevel]; const globalCode = selectedCode === undefined ? -Infinity : selectedCode; const oldExt = anylogger.ext; -anylogger.ext = (l, o) => { - l = oldExt(l, o); +anylogger.ext = logger => { + const l = oldExt(logger); l.enabledFor = lvl => globalCode >= anylogger.levels[lvl]; const prefix = l.name.replace(/:/g, ': '); diff --git a/packages/cosmic-swingset/src/chain-main.js b/packages/cosmic-swingset/src/chain-main.js index 2efd94998a8..5f65f771e62 100644 --- a/packages/cosmic-swingset/src/chain-main.js +++ b/packages/cosmic-swingset/src/chain-main.js @@ -1,6 +1,6 @@ // @ts-check -import path from 'node:path'; +import nativePath from 'node:path'; import v8 from 'node:v8'; import process from 'node:process'; import fs from 'node:fs'; @@ -167,7 +167,11 @@ const makePrefixedBridgeStorage = ( }); }; -export default async function main(progname, args, { env, homedir, agcc }) { +export default async function main( + progname, + args, + { env, homedir, path = nativePath, agcc }, +) { const portNums = {}; // TODO: use the 'basedir' pattern diff --git a/packages/cosmic-swingset/src/entrypoint.js b/packages/cosmic-swingset/src/entrypoint.js index 7e1b2de18b2..e6b305a496e 100755 --- a/packages/cosmic-swingset/src/entrypoint.js +++ b/packages/cosmic-swingset/src/entrypoint.js @@ -18,9 +18,9 @@ import main from './chain-main.js'; const log = anylogger('ag-chain-cosmos'); main(process.argv[1], process.argv.splice(2), { - path, - homedir: os.homedir(), env: process.env, + homedir: os.homedir(), + path, agcc, }).then( _res => 0, diff --git a/packages/cosmic-swingset/src/helpers/bufferedStorage.js b/packages/cosmic-swingset/src/helpers/bufferedStorage.js index 8d860e06f58..0233faa492d 100644 --- a/packages/cosmic-swingset/src/helpers/bufferedStorage.js +++ b/packages/cosmic-swingset/src/helpers/bufferedStorage.js @@ -5,7 +5,7 @@ import { assert, Fail } from '@endo/errors'; // XXX Do these "StorageAPI" functions belong in their own package? /** - * @template {unknown} [T=unknown] + * @template [T=unknown] * @typedef {{ * has: (key: string) => boolean, * get: (key: string) => T | undefined, @@ -16,7 +16,7 @@ import { assert, Fail } from '@endo/errors'; */ /** - * @template {unknown} [T=unknown] + * @template [T=unknown] * @typedef {KVStore & {commit: () => void, abort: () => void}} BufferedKVStore */ @@ -210,15 +210,13 @@ export function provideEnhancedKVStore(mapOrKvStore = new Map()) { * until told to commit (or abort) them. * * @template [T=unknown] - * @param {KVStore} kvStore The StorageAPI object to wrap - * @param {{ - * onGet?: (key: string, value: T | undefined) => void, // a callback invoked after getting a value from kvStore - * onPendingSet?: (key: string, value: T) => void, // a callback invoked after a new uncommitted value is set - * onPendingDelete?: (key: string) => void, // a callback invoked after a new uncommitted delete - * onCommit?: () => void, // a callback invoked after pending operations have been committed - * onAbort?: () => void, // a callback invoked after pending operations have been aborted - * }} listeners Optional callbacks to be invoked when respective events occur - * + * @param {KVStore} kvStore the StorageAPI object to wrap + * @param {object} [listeners] optional callbacks to be invoked when respective events occur + * @param {(key: string, value: T | undefined) => void} [listeners.onGet] a callback invoked after getting a value from kvStore + * @param {(key: string, value: T) => void} [listeners.onPendingSet] a callback invoked after a new uncommitted value is set + * @param {(key: string) => void} [listeners.onPendingDelete] a callback invoked after a new uncommitted delete + * @param {() => void} [listeners.onCommit] a callback invoked after pending operations have been committed + * @param {() => void} [listeners.onAbort] a callback invoked after pending operations have been aborted * @returns {{kvStore: KVStore} & Pick, 'commit' | 'abort'>} */ export function makeBufferedStorage(kvStore, listeners = {}) { diff --git a/packages/cosmic-swingset/src/sim-chain.js b/packages/cosmic-swingset/src/sim-chain.js index 93e5a98d4e5..2ffecc93914 100644 --- a/packages/cosmic-swingset/src/sim-chain.js +++ b/packages/cosmic-swingset/src/sim-chain.js @@ -19,8 +19,11 @@ import { launch } from './launch-chain.js'; import { getTelemetryProviders } from './kernel-stats.js'; import { DEFAULT_SIM_SWINGSET_PARAMS, QueueInbound } from './sim-params.js'; import { parseQueueSizes } from './params.js'; +import { makeKVStoreFromMap } from './helpers/bufferedStorage.js'; import { makeQueue, makeQueueStorageMock } from './helpers/make-queue.js'; +/** @import { Mailbox } from '@agoric/swingset-vat' */ + const console = anylogger('fake-chain'); const TELEMETRY_SERVICE_NAME = 'sim-cosmos'; @@ -28,10 +31,11 @@ const TELEMETRY_SERVICE_NAME = 'sim-cosmos'; const PRETEND_BLOCK_DELAY = 5; const scaleBlockTime = ms => Math.floor(ms / 1000); -async function makeMapStorage(file) { - let content; +async function makeMailboxStorageFromFile(file) { + /** @type {Map} */ const map = new Map(); - map.commit = async () => { + const kvStore = makeKVStoreFromMap(map); + const commit = async () => { const obj = {}; for (const [k, v] of map.entries()) { obj[k] = exportMailbox(v); @@ -39,20 +43,24 @@ async function makeMapStorage(file) { const json = stringify(obj); await fs.promises.writeFile(file, json); }; - - await (async () => { - content = await fs.promises.readFile(file); + const read = async () => { + const content = await fs.promises.readFile(file, 'utf8'); return JSON.parse(content); - })().then( - obj => { - for (const [k, v] of Object.entries(obj)) { - map.set(k, importMailbox(v)); - } - }, - () => {}, - ); + }; + const load = async obj => { + map.clear(); + for (const [k, v] of Object.entries(obj)) { + map.set(k, importMailbox(v)); + } + }; + const reset = async () => { + const obj = await read(); + await load(obj); + }; - return map; + await read().then(load, () => {}); + + return { ...kvStore, commit, abort: reset }; } export async function connectToFakeChain(basedir, GCI, delay, inbound) { @@ -61,7 +69,7 @@ export async function connectToFakeChain(basedir, GCI, delay, inbound) { const mailboxFile = path.join(basedir, `fake-chain-${GCI}-mailbox.json`); const bootAddress = `${GCI}-client`; - const mailboxStorage = await makeMapStorage(mailboxFile); + const mailboxStorage = await makeMailboxStorageFromFile(mailboxFile); const argv = { giveMeAllTheAgoricPowers: true, @@ -109,6 +117,7 @@ export async function connectToFakeChain(basedir, GCI, delay, inbound) { const actionQueue = makeQueue(actionQueueStorage); const s = await launch({ + bridgeOutbound: /** @type {any} */ (undefined), actionQueueStorage, highPriorityQueueStorage, kernelStateDBDir: stateDBdir, @@ -120,13 +129,20 @@ export async function connectToFakeChain(basedir, GCI, delay, inbound) { debugName: GCI, metricsProvider, slogSender, + swingsetConfig: {}, }); const { blockingSend, savedHeight } = s; let blockHeight = savedHeight; const intoChain = []; - let nextBlockTimeout = 0; + /** @type {undefined | ReturnType} */ + let nextBlockTimeout; + const resetNextBlockTimeout = () => { + if (nextBlockTimeout === undefined) return; + clearTimeout(nextBlockTimeout); + nextBlockTimeout = undefined; + }; const maximumDelay = (delay || PRETEND_BLOCK_DELAY) * 1000; @@ -172,7 +188,7 @@ export async function connectToFakeChain(basedir, GCI, delay, inbound) { // Done processing, "commit the block". await blockingSend({ type: 'COMMIT_BLOCK', blockHeight, blockTime }); - clearTimeout(nextBlockTimeout); + resetNextBlockTimeout(); nextBlockTimeout = setTimeout(simulateBlock, maximumDelay); // TODO: maybe add latency to the inbound messages. @@ -197,7 +213,7 @@ export async function connectToFakeChain(basedir, GCI, delay, inbound) { // Only actually simulate a block if we're not in bootstrap. let p; if (blockHeight && !delay) { - clearTimeout(nextBlockTimeout); + resetNextBlockTimeout(); p = simulateBlock(); } await p; diff --git a/packages/cosmic-swingset/test/clean-core-eval.test.js b/packages/cosmic-swingset/test/clean-core-eval.test.js index 9c0a9717f76..e04cb24f401 100644 --- a/packages/cosmic-swingset/test/clean-core-eval.test.js +++ b/packages/cosmic-swingset/test/clean-core-eval.test.js @@ -5,6 +5,8 @@ import { } from '../scripts/clean-core-eval.js'; test('defangEvaluableCode is working', t => { + /** @typedef {import('ava').ThrowsExpectation} EvaluationExpectation */ + /** @type {Array<[string, string?, EvaluationExpectation?, EvaluationExpectation?]>} */ const samples = [ [''], [ diff --git a/packages/cosmic-swingset/test/gov-code.js b/packages/cosmic-swingset/test/gov-code.js index a66d2b11994..dd52188eeeb 100644 --- a/packages/cosmic-swingset/test/gov-code.js +++ b/packages/cosmic-swingset/test/gov-code.js @@ -1,4 +1,5 @@ /* global E */ +/// /** * This file, along with the companion `gov-permit.json`, are used to test "big * hammer" chain governance. They don't have a functional purpose outside of diff --git a/packages/cosmic-swingset/test/provision-smartwallet.test.js b/packages/cosmic-swingset/test/provision-smartwallet.test.js index 2162550fe82..8fdea18bd30 100644 --- a/packages/cosmic-swingset/test/provision-smartwallet.test.js +++ b/packages/cosmic-swingset/test/provision-smartwallet.test.js @@ -40,7 +40,7 @@ test.before(async t => { const io = { spawn: ambientSpawn, cwd: makefileDir }; const pspawnMake = pspawn('make', io); const pspawnAgd = pspawn('bin/ag-chain-cosmos', io); - const scenario2 = makeScenario2({ pspawnMake, pspawnAgd, delay, log: t.log }); + const scenario2 = makeScenario2({ pspawnMake, pspawnAgd, log: t.log }); const walletTool = makeWalletTool({ runMake: scenario2.runMake, pspawnAgd, @@ -65,6 +65,7 @@ test.before(async t => { // if run with the test above. // TODO: https://github.com/Agoric/agoric-sdk/issues/6766 test.skip('integration test: smart wallet provision', async t => { + // @ts-expect-error context has unknown type const { scenario2, walletTool, soloAddr } = t.context; const enoughBlocksToProvision = 7; diff --git a/packages/cosmic-swingset/test/run-policy.test.js b/packages/cosmic-swingset/test/run-policy.test.js index e062b48f622..91157278905 100644 --- a/packages/cosmic-swingset/test/run-policy.test.js +++ b/packages/cosmic-swingset/test/run-policy.test.js @@ -15,6 +15,7 @@ import { makeVatCleanupBudgetFromKeywords, } from '../src/sim-params.js'; +/** @import { ManagerType, SwingSetConfig } from '@agoric/swingset-vat' */ /** @import { KVStore } from '../src/helpers/bufferedStorage.js' */ /** @@ -59,6 +60,7 @@ test('cleanup work must be limited by vat_cleanup_budget', async t => { bundles: makeSourceDescriptors({ puppet: '@agoric/swingset-vat/tools/vat-puppet.js', }), + /** @type {Partial} */ configOverrides: { // Aggressive GC. defaultReapInterval: 1, diff --git a/packages/cosmic-swingset/tools/test-kit.js b/packages/cosmic-swingset/tools/test-kit.js index ee14da4a4e7..175038c291c 100644 --- a/packages/cosmic-swingset/tools/test-kit.js +++ b/packages/cosmic-swingset/tools/test-kit.js @@ -35,6 +35,7 @@ const stripUndefined = obj => Object.entries(obj).filter(([_key, value]) => value !== undefined), ); +/** @type {InitMsg} */ export const defaultInitMessage = harden( makeInitMsg({ type: SwingsetMessageType.AG_COSMOS_INIT, @@ -59,6 +60,7 @@ export const defaultInitMessage = harden( ), }), ); +/** @type {InitMsg} */ export const defaultBootstrapMessage = harden({ ...deepCopyJsonable(defaultInitMessage), blockHeight: 1, diff --git a/packages/internal/src/chain-utils.js b/packages/internal/src/chain-utils.js index fe1716a6016..264c3391b1d 100644 --- a/packages/internal/src/chain-utils.js +++ b/packages/internal/src/chain-utils.js @@ -25,6 +25,7 @@ import * as _ActionType from './action-types.js'; * @typedef {BlockInfo & { * type: typeof _ActionType.AG_COSMOS_INIT; * chainID: string; + * isBootstrap?: boolean; * supplyCoins: { denom: string; amount: NatString }[]; * }} InitMsg * cosmosInitAction fields that are subject to consensus. See cosmosInitAction diff --git a/packages/swingset-liveslots/src/liveslots.js b/packages/swingset-liveslots/src/liveslots.js index 73855c704af..b0d82478a8f 100644 --- a/packages/swingset-liveslots/src/liveslots.js +++ b/packages/swingset-liveslots/src/liveslots.js @@ -1319,7 +1319,7 @@ function build( /** * @param {import('./types.js').VatDeliveryObject} delivery - * @returns {void | Promise} + * @returns {undefined | ReturnType} */ function dispatchToUserspace(delivery) { let result;