From 605f9067468da7fb9925b6210ad583dac3579b39 Mon Sep 17 00:00:00 2001 From: OmarTawfik <15987992+OmarTawfik@users.noreply.github.com> Date: Thu, 14 Nov 2024 20:43:21 -0800 Subject: [PATCH] upgrade slang to `0.18.3` The newest version includes many performance improvements, and adds WASM support. It also adds a bunch of requested public APIs. This allows importing Slang from any WASM-compatible environment (NodeJS), at the cost of using ESM (or using `await import()` from CJS). That turns the calling utility `makeNamespacedInput()` to be `async`. Please let me know if I need to verify/run anything else. --- packages/core/package.json | 2 +- .../core/src/utils/make-namespaced.test.ts | 2 +- packages/core/src/utils/make-namespaced.ts | 82 +++++++------- packages/core/src/utils/slang/trivia.ts | 23 ---- packages/plugin-hardhat/src/index.ts | 12 ++- tsconfig.base.json | 4 +- yarn.lock | 101 +++--------------- 7 files changed, 61 insertions(+), 165 deletions(-) delete mode 100644 packages/core/src/utils/slang/trivia.ts diff --git a/packages/core/package.json b/packages/core/package.json index 31d27cb30..797375dd8 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -61,7 +61,7 @@ "typescript": "^5.0.0" }, "dependencies": { - "@nomicfoundation/slang": "^0.17.0", + "@nomicfoundation/slang": "^0.18.3", "cbor": "^9.0.0", "chalk": "^4.1.0", "compare-versions": "^6.0.0", diff --git a/packages/core/src/utils/make-namespaced.test.ts b/packages/core/src/utils/make-namespaced.test.ts index 918b4ec67..e236f3d57 100644 --- a/packages/core/src/utils/make-namespaced.test.ts +++ b/packages/core/src/utils/make-namespaced.test.ts @@ -40,7 +40,7 @@ async function testMakeNamespaced( // Inefficient, but we want to test that we don't actually modify the original input object const origInput = JSON.parse(JSON.stringify(origBuildInfo.input)); - const modifiedInput = makeNamespacedInput( + const modifiedInput = await makeNamespacedInput( origBuildInfo.input, origBuildInfo.output, keepAllNatSpec ? undefined : origBuildInfo.solcVersion, diff --git a/packages/core/src/utils/make-namespaced.ts b/packages/core/src/utils/make-namespaced.ts index 850f33f58..9d1a1b7a1 100644 --- a/packages/core/src/utils/make-namespaced.ts +++ b/packages/core/src/utils/make-namespaced.ts @@ -37,7 +37,11 @@ const OUTPUT_SELECTION = { * @param solcVersion The version of the solc compiler that was originally used to compile the input. * @returns The modified solc input with storage layout that includes namespaced type information. */ -export function makeNamespacedInput(input: SolcInput, output: SolcOutput, solcVersion?: string): SolcInput { +export async function makeNamespacedInput( + input: SolcInput, + output: SolcOutput, + solcVersion?: string, +): Promise { const modifiedSources: Record = {}; for (const [sourcePath] of Object.entries(input.sources)) { @@ -163,7 +167,7 @@ export function makeNamespacedInput(input: SolcInput, output: SolcOutput, solcVe } } - const modifiedSource = tryRemoveNonStructNatSpec(getModifiedSource(orig, modifications), solcVersion); + const modifiedSource = await tryRemoveNonStructNatSpec(getModifiedSource(orig, modifications), solcVersion); modifiedSources[sourcePath] = { ...source, content: modifiedSource }; } @@ -177,60 +181,46 @@ export function makeNamespacedInput(input: SolcInput, output: SolcOutput, solcVe * * Otherwise, return the original content. */ -function tryRemoveNonStructNatSpec(origContent: string, solcVersion: string | undefined): string { - const natSpecRemovals: Modification[] = []; +async function tryRemoveNonStructNatSpec(origContent: string, solcVersion: string | undefined): Promise { + if (solcVersion === undefined) { + return origContent; + } - if (solcVersion !== undefined && tryRequire('@nomicfoundation/slang') && slangSupportsVersion(solcVersion)) { - /* eslint-disable @typescript-eslint/no-var-requires */ - const { Language } = require('@nomicfoundation/slang/language'); - const { NonterminalKind, TerminalKind } = require('@nomicfoundation/slang/kinds'); - const { TerminalNode } = require('@nomicfoundation/slang/cst'); - const { isTrivia } = require('./slang/trivia'); - /* eslint-enable @typescript-eslint/no-var-requires */ + const { Parser } = await import('@nomicfoundation/slang/parser'); + if (!Parser.supportedVersions().includes(solcVersion)) { + return origContent; + } - const language = new Language(solcVersion); - const parseOutput = language.parse(NonterminalKind.SourceUnit, origContent); - const cursor = parseOutput.createTreeCursor(); + const { TerminalKind, TerminalKindExtensions } = await import('@nomicfoundation/slang/cst'); + const parser = Parser.create(solcVersion); + const parseOutput = parser.parse(Parser.rootKind(), origContent); + const cursor = parseOutput.createTreeCursor(); + + const natSpecRemovals: Modification[] = []; + + while ( + cursor.goToNextTerminalWithKinds([TerminalKind.MultiLineNatSpecComment, TerminalKind.SingleLineNatSpecComment]) + ) { + // Lookahead to determine if the next non-trivia node is the struct keyword. + // If so, this NatSpec is part of the struct definition and should not be removed. + const lookaheadCursor = cursor.clone(); while ( - cursor.goToNextTerminalWithKinds([TerminalKind.MultiLineNatSpecComment, TerminalKind.SingleLineNatSpecComment]) + lookaheadCursor.goToNextTerminal() && + lookaheadCursor.node.isTerminalNode() && + TerminalKindExtensions.isTrivia(lookaheadCursor.node.kind) ) { - // Lookahead to determine if the next non-trivia node is the struct keyword. - // If so, this NatSpec is part of the struct definition and should not be removed. - const lookaheadCursor = cursor.clone(); - while (lookaheadCursor.goToNextTerminal() && isTrivia(lookaheadCursor.node())) { - // skip over trivia nodes - } - if (lookaheadCursor.node().kind === TerminalKind.StructKeyword) { - continue; - } + // skip over trivia nodes + } - const triviaNode = cursor.node(); - assert(triviaNode instanceof TerminalNode); - natSpecRemovals.push(makeDeleteRange(cursor.textRange.start.utf8, cursor.textRange.end.utf8)); + if (lookaheadCursor.node.kind === TerminalKind.StructKeyword) { + continue; } - return getModifiedSource(Buffer.from(origContent, 'utf8'), natSpecRemovals); - } else { - return origContent; - } -} -function tryRequire(id: string) { - try { - require(id); - return true; - } catch (e: any) { - // do nothing + natSpecRemovals.push(makeDeleteRange(cursor.textRange.start.utf8, cursor.textRange.end.utf8)); } - return false; -} - -function slangSupportsVersion(solcVersion: string): boolean { - /* eslint-disable @typescript-eslint/no-var-requires */ - const { Language } = require('@nomicfoundation/slang/language'); - /* eslint-enable @typescript-eslint/no-var-requires */ - return Language.supportedVersions().includes(solcVersion); + return getModifiedSource(Buffer.from(origContent, 'utf8'), natSpecRemovals); } interface Modification { diff --git a/packages/core/src/utils/slang/trivia.ts b/packages/core/src/utils/slang/trivia.ts deleted file mode 100644 index b8b716b0a..000000000 --- a/packages/core/src/utils/slang/trivia.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { TerminalKind } from '@nomicfoundation/slang/kinds'; -import { Node, TerminalNode } from '@nomicfoundation/slang/cst'; - -/** - * Returns true if the node is a trivia terminal (whitespace or comment or NatSpec) - * - * CAUTION: This must be imported dynamically. - * Only import this file if Slang is supported on the current platform, otherwise an error will be thrown on import. - */ -export function isTrivia(node: Node) { - return node instanceof TerminalNode && isTriviaKind(node.kind); -} - -function isTriviaKind(kind: TerminalKind) { - return ( - kind === TerminalKind.EndOfLine || - kind === TerminalKind.MultiLineComment || - kind === TerminalKind.MultiLineNatSpecComment || - kind === TerminalKind.SingleLineComment || - kind === TerminalKind.SingleLineNatSpecComment || - kind === TerminalKind.Whitespace - ); -} diff --git a/packages/plugin-hardhat/src/index.ts b/packages/plugin-hardhat/src/index.ts index f7458a300..37f9d6177 100644 --- a/packages/plugin-hardhat/src/index.ts +++ b/packages/plugin-hardhat/src/index.ts @@ -69,7 +69,9 @@ interface RunCompilerArgs { } subtask(TASK_COMPILE_SOLIDITY, async (args: { force: boolean }, hre, runSuper) => { - const { readValidations, ValidationsCacheOutdated, ValidationsCacheNotFound } = await import('./utils/validations'); + const { readValidations, ValidationsCacheOutdated, ValidationsCacheNotFound } = await import( + './utils/validations.js' + ); try { await readValidations(hre); @@ -88,18 +90,18 @@ subtask(TASK_COMPILE_SOLIDITY_COMPILE, async (args: RunCompilerArgs, hre, runSup const { isNamespaceSupported, validate, solcInputOutputDecoder, makeNamespacedInput } = await import( '@openzeppelin/upgrades-core' ); - const { writeValidations } = await import('./utils/validations'); + const { writeValidations } = await import('./utils/validations.js'); // TODO: patch input const { output, solcBuild } = await runSuper(); - const { isFullSolcOutput } = await import('./utils/is-full-solc-output'); + const { isFullSolcOutput } = await import('./utils/is-full-solc-output.js'); if (isFullSolcOutput(output)) { const decodeSrc = solcInputOutputDecoder(args.input, output); let namespacedOutput = undefined; if (isNamespaceSupported(args.solcVersion)) { - const namespacedInput = makeNamespacedInput(args.input, output, args.solcVersion); + const namespacedInput = await makeNamespacedInput(args.input, output, args.solcVersion); namespacedOutput = (await runSuper({ ...args, quiet: true, input: namespacedInput })).output; const namespacedCompileErrors = getNamespacedCompileErrors(namespacedOutput); @@ -210,7 +212,7 @@ extendConfig((config: HardhatConfig) => { if (tryRequire('@nomicfoundation/hardhat-verify')) { subtask('verify:etherscan').setAction(async (args, hre, runSuper) => { - const { verify } = await import('./verify-proxy'); + const { verify } = await import('./verify-proxy.js'); return await verify(args, hre, runSuper); }); } diff --git a/tsconfig.base.json b/tsconfig.base.json index 3d424f2c4..546061581 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -2,9 +2,9 @@ "compilerOptions": { "incremental": true, "target": "es2020", - "module": "commonjs", + "module": "nodenext", "strict": true, - "moduleResolution": "node", + "moduleResolution": "nodenext", "esModuleInterop": true, "sourceMap": true, "declaration": true, diff --git a/yarn.lock b/yarn.lock index 1a58a33ab..8a44640ba 100644 --- a/yarn.lock +++ b/yarn.lock @@ -208,6 +208,11 @@ "@babel/helper-validator-identifier" "^7.24.7" to-fast-properties "^2.0.0" +"@bytecodealliance/preview2-shim@0.17.0": + version "0.17.0" + resolved "https://registry.yarnpkg.com/@bytecodealliance/preview2-shim/-/preview2-shim-0.17.0.tgz#9bc1cadbb9f86c446c6f579d3431c08a06a6672e" + integrity sha512-JorcEwe4ud0x5BS/Ar2aQWOQoFzjq/7jcnxYXCvSMh0oRm0dQXzOA+hqLDBnOMks1LLBA7dmiLLsEBl09Yd6iQ== + "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" @@ -685,65 +690,12 @@ table "^6.8.0" undici "^5.14.0" -"@nomicfoundation/slang-darwin-arm64@0.17.0": - version "0.17.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/slang-darwin-arm64/-/slang-darwin-arm64-0.17.0.tgz#8cded3c24322624e3b6618760caba8e840bd1c1d" - integrity sha512-O0q94EUtoWy9A5kOTOa9/khtxXDYnLqmuda9pQELurSiwbQEVCPQL8kb34VbOW+ifdre66JM/05Xw9JWhIZ9sA== - -"@nomicfoundation/slang-darwin-x64@0.17.0": - version "0.17.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/slang-darwin-x64/-/slang-darwin-x64-0.17.0.tgz#6ebeb33a2ced89fc6023f6cda4af96403486038a" - integrity sha512-IaDbHzvT08sBK2HyGzonWhq1uu8IxdjmTqAWHr25Oh/PYnamdi8u4qchZXXYKz/DHLoYN3vIpBXoqLQIomhD/g== - -"@nomicfoundation/slang-linux-arm64-gnu@0.17.0": - version "0.17.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/slang-linux-arm64-gnu/-/slang-linux-arm64-gnu-0.17.0.tgz#41c7e57a9b1a3aee6911f0cab22e683c149fb470" - integrity sha512-Lj4anvOsQZxs1SycG8VyT2Rl2oqIhyLSUCgGepTt3CiJ/bM+8r8bLJIgh8vKkki4BWz49YsYIgaJB2IPv8FFTw== - -"@nomicfoundation/slang-linux-arm64-musl@0.17.0": - version "0.17.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/slang-linux-arm64-musl/-/slang-linux-arm64-musl-0.17.0.tgz#9c4b51689274ae75c2c8a4cddd2e1cc0a79c191d" - integrity sha512-/xkTCa9d5SIWUBQE3BmLqDFfJRr4yUBwbl4ynPiGUpRXrD69cs6pWKkwjwz/FdBpXqVo36I+zY95qzoTj/YhOA== - -"@nomicfoundation/slang-linux-x64-gnu@0.17.0": - version "0.17.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/slang-linux-x64-gnu/-/slang-linux-x64-gnu-0.17.0.tgz#c3a3b6a7b775fc617832958d10e6664bf86d39d0" - integrity sha512-oe5IO5vntOqYvTd67deCHPIWuSuWm6aYtT2/0Kqz2/VLtGz4ClEulBSRwfnNzBVtw2nksWipE1w8BzhImI7Syg== - -"@nomicfoundation/slang-linux-x64-musl@0.17.0": - version "0.17.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/slang-linux-x64-musl/-/slang-linux-x64-musl-0.17.0.tgz#725118ff99a7217b9f1d1bd84411d9442084077d" - integrity sha512-PpYCI5K/kgLAMXaPY0V4VST5gCDprEOh7z/47tbI8kJQumI5odjsj/Cs8MpTo7/uRH6flKYbVNgUzcocWVYrAQ== - -"@nomicfoundation/slang-win32-arm64-msvc@0.17.0": - version "0.17.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/slang-win32-arm64-msvc/-/slang-win32-arm64-msvc-0.17.0.tgz#9c8bc4ccf21eaaac0cfcb6d3954ede4e2dea4c02" - integrity sha512-u/Mkf7OjokdBilP7QOJj6QYJU4/mjkbKnTX21wLyCIzeVWS7yafRPYpBycKIBj2pRRZ6ceAY5EqRpb0aiCq+0Q== - -"@nomicfoundation/slang-win32-ia32-msvc@0.17.0": - version "0.17.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/slang-win32-ia32-msvc/-/slang-win32-ia32-msvc-0.17.0.tgz#3fc5d00a3f8c1d85a5e94146af78a5526a4f3d27" - integrity sha512-XJBVQfNnZQUv0tP2JSJ573S+pmgrLWgqSZOGaMllnB/TL1gRci4Z7dYRJUF2s82GlRJE+FHSI2Ro6JISKmlXCg== - -"@nomicfoundation/slang-win32-x64-msvc@0.17.0": - version "0.17.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/slang-win32-x64-msvc/-/slang-win32-x64-msvc-0.17.0.tgz#f6a5e3250fa07cbda49151edeb80f09090e5b71a" - integrity sha512-zPGsAeiTfqfPNYHD8BfrahQmYzA78ZraoHKTGraq/1xwJwzBK4bu/NtvVA4pJjBV+B4L6DCxVhSbpn40q26JQA== - -"@nomicfoundation/slang@^0.17.0": - version "0.17.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/slang/-/slang-0.17.0.tgz#d9c25cd711ebf3490c9d0c99e9b4ca2481341a6b" - integrity sha512-1GlkGRcGpVnjFw9Z1vvDKOKo2mzparFt7qrl2pDxWp+jrVtlvej98yCMX52pVyrYE7ZeOSZFnx/DtsSgoukStQ== - dependencies: - "@nomicfoundation/slang-darwin-arm64" "0.17.0" - "@nomicfoundation/slang-darwin-x64" "0.17.0" - "@nomicfoundation/slang-linux-arm64-gnu" "0.17.0" - "@nomicfoundation/slang-linux-arm64-musl" "0.17.0" - "@nomicfoundation/slang-linux-x64-gnu" "0.17.0" - "@nomicfoundation/slang-linux-x64-musl" "0.17.0" - "@nomicfoundation/slang-win32-arm64-msvc" "0.17.0" - "@nomicfoundation/slang-win32-ia32-msvc" "0.17.0" - "@nomicfoundation/slang-win32-x64-msvc" "0.17.0" +"@nomicfoundation/slang@^0.18.3": + version "0.18.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/slang/-/slang-0.18.3.tgz#976b6c3820081cebf050afbea434038aac9313cc" + integrity sha512-YqAWgckqbHM0/CZxi9Nlf4hjk9wUNLC9ngWCWBiqMxPIZmzsVKYuChdlrfeBPQyvQQBoOhbx+7C1005kLVQDZQ== + dependencies: + "@bytecodealliance/preview2-shim" "0.17.0" "@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.2": version "0.1.2" @@ -5146,16 +5098,7 @@ statuses@2.0.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -5226,7 +5169,7 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -5240,13 +5183,6 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - strip-ansi@^7.0.1, strip-ansi@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -5719,7 +5655,7 @@ workerpool@^6.5.1: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -5746,15 +5682,6 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"