diff --git a/.gitignore b/.gitignore index 86573cf1f..2c5d29933 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,8 @@ build-*/ # Direnv or shell hook + Nix Flake generated files .direnv/ result +result-bin +result-man docs/book/book src/index.js @@ -205,4 +207,4 @@ csources_v1/ .aider* # Temporary .patch file, used to coppy results from codex and applied using git apply .patch -*.patch \ No newline at end of file +*.patch diff --git a/appimage-scripts/build_appimage.sh b/appimage-scripts/build_appimage.sh index dbe4ace1a..ebc2abfae 100755 --- a/appimage-scripts/build_appimage.sh +++ b/appimage-scripts/build_appimage.sh @@ -137,6 +137,12 @@ nix build "${ROOT_PATH}#packages.${CURRENT_NIX_SYSTEM}.cargo-stylus" CARGO_STYLUS=$(nix eval --raw "${ROOT_PATH}#packages.${CURRENT_NIX_SYSTEM}.cargo-stylus.out") cp -L "${CARGO_STYLUS}"/bin/cargo-stylus "${APP_DIR}"/bin +# cargo-expand +nix build "${ROOT_PATH}#packages.${CURRENT_NIX_SYSTEM}.cargo-expand" + +CARGO_EXPAND=$(nix eval --raw "${ROOT_PATH}#packages.${CURRENT_NIX_SYSTEM}.cargo-expand.out") +cp -L "${CARGO_EXPAND}"/bin/cargo-expand "${APP_DIR}"/bin + # ctags cp -Lr "${ROOT_PATH}/src/links/ctags" "${APP_DIR}/bin/" chmod +x "${APP_DIR}/bin/ctags" @@ -261,6 +267,7 @@ patchelf --set-interpreter "${INTERPRETER_PATH}" "${APP_DIR}"/bin/wazero patchelf --set-interpreter "${INTERPRETER_PATH}" "${APP_DIR}"/bin/ctags patchelf --set-interpreter "${INTERPRETER_PATH}" "${APP_DIR}"/bin/curl patchelf --set-interpreter "${INTERPRETER_PATH}" "${APP_DIR}"/bin/cargo-stylus +patchelf --set-interpreter "${INTERPRETER_PATH}" "${APP_DIR}"/bin/cargo-expand patchelf --set-interpreter "${INTERPRETER_PATH}" "${APP_DIR}"/bin/node patchelf --set-interpreter "${INTERPRETER_PATH}" "${APP_DIR}"/ruby/bin/ruby diff --git a/flake.lock b/flake.lock index 675167084..e57b2cd08 100644 --- a/flake.lock +++ b/flake.lock @@ -39,11 +39,11 @@ }, "appimage-channel": { "locked": { - "lastModified": 1737569578, - "narHash": "sha256-6qY0pk2QmUtBT9Mywdvif0i/CLVgpCjMUn6g9vB+f3M=", + "lastModified": 1751274312, + "narHash": "sha256-/bVBlRpECLVzjV19t5KMdMFWSwKLtb5RyXdjz3LJT+g=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "47addd76727f42d351590c905d9d1905ca895b82", + "rev": "50ab793786d9de88ee30ec4e4c24fb4236fc2674", "type": "github" }, "original": { @@ -308,11 +308,11 @@ "rust-analyzer-src": "rust-analyzer-src" }, "locked": { - "lastModified": 1735540357, - "narHash": "sha256-XbIfjxEOM6JmLCILozlFEUrfCpXvQNo9l+VAU7FCahI=", + "lastModified": 1759214609, + "narHash": "sha256-+V3SeMjAMd9j9JTECk9oc0gWhtsk79rFEbYf/tHjywo=", "owner": "nix-community", "repo": "fenix", - "rev": "92bb57bf88e4b8e6b4fe4e79fbfff2fc3f04df88", + "rev": "f93a2d7225bc7a93d3379acff8fe722e21d97852", "type": "github" }, "original": { @@ -411,11 +411,11 @@ ] }, "locked": { - "lastModified": 1733312601, - "narHash": "sha256-4pDvzqnegAfRkPwO3wmwBhVi/Sye1mzps0zHWYnP88c=", + "lastModified": 1756770412, + "narHash": "sha256-+uWLQZccFHwqpGqr2Yt5VsW/PbeJVTn9Dk6SHWhNRPw=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "205b12d8b7cd4802fbcb8e8ef6a0f1408781a4f9", + "rev": "4524271976b625a4a605beefd893f270620fd751", "type": "github" }, "original": { @@ -988,11 +988,11 @@ ] }, "locked": { - "lastModified": 1748958660, - "narHash": "sha256-hR5+KUMhoF+36eRInJXecK6EafkEPsAFmx4zvDNQwq0=", + "lastModified": 1758198839, + "narHash": "sha256-UfTrdi3YNf9ao1Lvxt5bvmk6ZrqdujuAb2mqp5AZdOY=", "owner": "metacraft-labs", "repo": "nix-blockchain-development", - "rev": "81e8abd12975c24be23174aab138ac5c76a0572b", + "rev": "8be37e1942152655bb8507955ee742d9f78ad9e0", "type": "github" }, "original": { @@ -1340,11 +1340,11 @@ }, "nixpkgs-unstable_2": { "locked": { - "lastModified": 1735471104, - "narHash": "sha256-0q9NGQySwDQc7RhAV2ukfnu7Gxa5/ybJ2ANT8DQrQrs=", + "lastModified": 1759036355, + "narHash": "sha256-0m27AKv6ka+q270dw48KflE0LwQYrO7Fm4/2//KCVWg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "88195a94f390381c6afcdaa933c2f6ff93959cb4", + "rev": "e9f00bd893984bc8ce46c895c3bf7cac95331127", "type": "github" }, "original": { @@ -1387,11 +1387,11 @@ }, "nixpkgs_4": { "locked": { - "lastModified": 1753549186, - "narHash": "sha256-Znl7rzuxKg/Mdm6AhimcKynM7V3YeNDIcLjBuoBcmNs=", + "lastModified": 1759036355, + "narHash": "sha256-0m27AKv6ka+q270dw48KflE0LwQYrO7Fm4/2//KCVWg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "17f6bd177404d6d43017595c5264756764444ab8", + "rev": "e9f00bd893984bc8ce46c895c3bf7cac95331127", "type": "github" }, "original": { @@ -1440,11 +1440,11 @@ "rust-analyzer-src": { "flake": false, "locked": { - "lastModified": 1735485512, - "narHash": "sha256-B9tZfdCnZF7Qo/Ys/LgKtUlzIr38c9fDYgo/XcS8Gtc=", + "lastModified": 1759134797, + "narHash": "sha256-YPi+jL3tx/yC5J5l7/OB7Lnlr9BMTzYnZtm7tRJzUNg=", "owner": "rust-lang", "repo": "rust-analyzer", - "rev": "59bc7b49d0ad319de8c477c63da552cbc8a05e4c", + "rev": "062ac7a5451e8e92a32e22a60d86882d6a034f3f", "type": "github" }, "original": { @@ -1714,16 +1714,16 @@ ] }, "locked": { - "lastModified": 1758199783, - "narHash": "sha256-CtYezlNMhXlTLIZaVQiUKRjQyKTN5YGRNXUlZUYN44U=", + "lastModified": 1759236464, + "narHash": "sha256-nR246Xy95Sczh/Hi7X1ExhuDoA9/HVi4lrazYyqQnDE=", "owner": "metacraft-labs", "repo": "codetracer-wasm-recorder", - "rev": "5cf6e2a1e601338224ba8eda2bf0fc02857cea00", + "rev": "991d7caf8883154a002251a885c3073f25a42f51", "type": "github" }, "original": { "owner": "metacraft-labs", - "ref": "wasm-tracing", + "ref": "feat-decode-events", "repo": "codetracer-wasm-recorder", "type": "github" } diff --git a/flake.nix b/flake.nix index 648aa4759..558e0657a 100644 --- a/flake.nix +++ b/flake.nix @@ -33,7 +33,7 @@ }; wazero = { - url = "github:metacraft-labs/codetracer-wasm-recorder?ref=wasm-tracing"; + url = "github:metacraft-labs/codetracer-wasm-recorder?ref=feat-decode-events"; # TODO: restore to wasm-tracing inputs.nixpkgs.follows = "nixpkgs-unstable"; flake = true; }; diff --git a/nix/packages/default.nix b/nix/packages/default.nix index 08c98c651..be76ae9cd 100644 --- a/nix/packages/default.nix +++ b/nix/packages/default.nix @@ -26,6 +26,8 @@ cargo-stylus = inputs.nix-blockchain-development.outputs.legacyPackages.${system}.metacraft-labs.cargo-stylus; + cargo-expand = pkgs.cargo-expand; + # curl = pkgs.curl; inherit (pkgs) curl; @@ -320,6 +322,7 @@ name = "runtime-deps"; paths = [ + pkgs.cargo-expand cargo-stylus resources-derivation db-backend diff --git a/nix/shells/main.nix b/nix/shells/main.nix index 26e1dcddd..92c7d10dc 100644 --- a/nix/shells/main.nix +++ b/nix/shells/main.nix @@ -49,6 +49,7 @@ mkShell { # stylus ourPkgs.cargo-stylus + cargo-expand yarn yarn2nix diff --git a/src/ct/codetracerconf.nim b/src/ct/codetracerconf.nim index f2aab5555..cb6c1525c 100644 --- a/src/ct/codetracerconf.nim +++ b/src/ct/codetracerconf.nim @@ -263,6 +263,12 @@ type desc: "Path to a stylus emv trace json file" .} : string + recordStylusSignatureMap* {. + name: "stylus-signature-map" + defaultValue: "" + desc: "Path to a stylus signature map json file" + .} : string + recordAddress* {. name: "address" abbr: "a" diff --git a/src/ct/db_backend_record.nim b/src/ct/db_backend_record.nim index 04153d39d..577ae9e17 100644 --- a/src/ct/db_backend_record.nim +++ b/src/ct/db_backend_record.nim @@ -59,6 +59,7 @@ proc recordDb( lang: Lang, vmExe: string, program: string, args: seq[string], backend: string, traceFolder: string, stylusTrace: string, + stylusSignatureMap: string, traceId: int): Trace = createDir(traceFolder) @@ -83,6 +84,9 @@ proc recordDb( if stylusTrace.len > 0: vmArgs.add("-stylus") vmArgs.add(stylusTrace) + if stylusSignatureMap.len > 0: + vmArgs.add("--stylus-signature-map") + vmArgs.add(stylusSignatureMap) vmArgs = vmArgs.concat(@["--trace-dir", traceFolder, program]) vmArgs of LangNoir: @@ -154,6 +158,7 @@ proc recordDb( proc record( cmd: string, args: seq[string], compileCommand: string, langArg: Lang, backend: string, stylusTrace: string, + stylusSignatureMap: string, test = false, basic = false, traceIDRecord: int = -1, customPath: string = "", outputFolderArg: string = ""): Trace = var traceID: int @@ -225,7 +230,7 @@ proc record( try: if lang == LangRubyDb: - return recordDb(LangRubyDb, rubyExe, executable, args, backend, outputFolder, "", traceId) + return recordDb(LangRubyDb, rubyExe, executable, args, backend, outputFolder, "", "", traceId) elif lang in {LangNoir, LangRustWasm, LangCppWasm}: if lang == LangNoir: # TODO: base the first arg: source folder for record symbols on @@ -238,9 +243,9 @@ proc record( # echo "wasm vm path ", vmPath else: vmPath = noirExe - return recordDb(lang, vmPath, executable, args, backend, outputFolder, stylusTrace, traceId) + return recordDb(lang, vmPath, executable, args, backend, outputFolder, stylusTrace, stylusSignatureMap, traceId) elif lang == LangSmall: - return recordDb(LangSmall, smallExe, executable, args, backend, outputFolder, stylusTrace, traceId) + return recordDb(LangSmall, smallExe, executable, args, backend, outputFolder, stylusTrace, stylusSignatureMap, traceId) else: echo fmt"ERROR: unsupported lang {lang}" quit(1) @@ -323,6 +328,7 @@ proc main*(): Trace = # [--backend ] # [-e/--export ] [-c/--cleanup-output-folder] # [-t/--stylus-trace ] + # [--stylus-signature-map ] # [-a/--address
] [--socket ] # [] let args = os.commandLineParams() @@ -341,6 +347,7 @@ proc main*(): Trace = var exportZipPath = "" var backend = "" var stylusTrace = "" + var stylusSignatureMap = "" var address = "" var socketPath = "" var isExportedWithArg = false @@ -385,6 +392,12 @@ proc main*(): Trace = return stylusTrace = args[i + 1] i += 2 + elif arg == "--stylus-signature-map": + if args.len() < i + 2: + displayHelp() + return + stylusSignatureMap = args[i + 1] + i += 2 elif arg == "--address" or arg == "-a": if args.len() < i + 2: displayHelp() @@ -483,7 +496,7 @@ proc main*(): Trace = try: var trace = record( - program, recordArgs, "", lang, backend, stylusTrace, + program, recordArgs, "", lang, backend, stylusTrace, stylusSignatureMap, traceIDRecord=traceID, outputFolderArg=outputFolder) traceId = trace.id outputFolder = trace.outputFolder diff --git a/src/ct/launch/launch.nim b/src/ct/launch/launch.nim index 542f9f46e..7529640e5 100644 --- a/src/ct/launch/launch.nim +++ b/src/ct/launch/launch.nim @@ -143,6 +143,7 @@ proc runInitial*(conf: CodetracerConf) = discard record( conf.recordLang, conf.recordOutputFolder, conf.recordExportFile, conf.recordStylusTrace, + conf.recordStylusSignatureMap, conf.recordAddress, conf.recordSocket, conf.recordProgram, conf.recordArgs) of StartupCommand.run: diff --git a/src/ct/stylus/arb_node_utils.nim b/src/ct/stylus/arb_node_utils.nim index 43aaeeb4d..38d1dc668 100644 --- a/src/ct/stylus/arb_node_utils.nim +++ b/src/ct/stylus/arb_node_utils.nim @@ -4,8 +4,8 @@ import ../../common/[types, paths] const DEFAULT_NODE_URL* = "http://localhost:8547" # TODO: get name from config? Maybe use SQLite? -let - CONTRACT_WASM_PATH* = getHomeDir() / ".local" / "share" / "codetracer" / "contract-debug-wasm" +let + CONTRACT_DEBUG_DATA_PATH* = getHomeDir() / ".local" / "share" / "codetracer" / "contract-debug-data" EVM_TRACE_DIR_PATH* = codetracerTmpPath proc jsonRpcRequest(methodParam: string, params: JsonNode): JsonNode {.raises: [IOError, ValueError].} = @@ -55,7 +55,7 @@ proc getPermittedToHashes(): HashSet[string] {.raises: [].} = init(toHashes) try: - for file in walkDir(CONTRACT_WASM_PATH): + for file in walkDir(CONTRACT_DEBUG_DATA_PATH): if file.kind == pcDir: let toAddr = splitPath(file.path)[1] toHashes.incl(toAddr) diff --git a/src/ct/stylus/deploy.nim b/src/ct/stylus/deploy.nim index a78a622d5..bc05c3485 100644 --- a/src/ct/stylus/deploy.nim +++ b/src/ct/stylus/deploy.nim @@ -1,4 +1,4 @@ -import std/[os, osproc, streams, strutils] +import std/[json, os, osproc, re, streams, strutils, tables] import arb_node_utils # NOTE: remove CatchableError if using custom exception @@ -91,18 +91,56 @@ proc doDebugBuild(): string {.raises: [OSError, IOError, CatchableError, Excepti return possibleFiles[0] -proc saveContractDebugWasm(deploymentAddr: string, wasmWithDebug: string) {.raises: [OSError, IOError].} = - let currDir = CONTRACT_WASM_PATH / deploymentAddr - let currFile = currDir / "debug.wasm" +# NOTE: remove CatchableError if using custom exception +proc doSignatureMap(): Table[string, string] {.raises: [OSError, IOError, CatchableError, Exception].} = + let process = startProcess( + "cargo", + args=["expand", "--lib"], + options={poEchoCmd, poUsePath, poStdErrToStdOut} + ) + defer: process.close() + + let outStream = process.outputStream + + var output = "" + + while process.running: + output.add(outStream.readAll()) + + output.add(outStream.readAll()) + + let exitCode = process.peekExitCode() + + if exitCode != 0: + echo "Can't extract event signatures! cargo expand output:" + echo output + return + + let signatureRegex = re"Event with signature `(.*)` and selector `(.*)`.\n```solidity\n(.*)\n```" + var matches = @["", "", ""] + + for eventComment in output.findAll(signatureRegex): + discard eventComment.match(signatureRegex, matches) + result[matches[1]] = matches[2] + +proc saveContractDebugWasm(deploymentAddr: string, wasmWithDebug: string, signatureMapJson: string) {.raises: [OSError, IOError].} = + let debugDataDir = CONTRACT_DEBUG_DATA_PATH / deploymentAddr + let debugWasmFile = debugDataDir / "debug.wasm" + let signatureMapFile = debugDataDir / "signature_map.json" + + createDir(debugDataDir) + + copyFile(wasmWithDebug, debugWasmFile) + echo "Debug executable for ", deploymentAddr, " saved at ", debugWasmFile - createDir(currDir) - copyFile(wasmWithDebug, currFile) + writeFile(signatureMapFile, signatureMapJson) + echo "Signature map for ", deploymentAddr, " saved at ", signatureMapFile - echo "Debug executable for ", deploymentAddr, " saved at ", currFile # NOTE: remove CatchableError if using custom exception proc deployStylus*() {.raises: [OSError, IOError, CatchableError, Exception].} = let wasmWithDebug = doDebugBuild() + let signatureMapJson = $(%doSignatureMap()) let deploymentAddr = doDeploy() - saveContractDebugWasm(deploymentAddr, wasmWithDebug) + saveContractDebugWasm(deploymentAddr, wasmWithDebug, signatureMapJson) diff --git a/src/ct/stylus/record.nim b/src/ct/stylus/record.nim index 399f9346b..b23ec7786 100644 --- a/src/ct/stylus/record.nim +++ b/src/ct/stylus/record.nim @@ -39,16 +39,24 @@ proc getEvmTrace(hash: string): string {.raises: [OSError, IOError, CatchableErr return outputFile proc getContractWasmPath(deploymentAddr: string): string {.raises: [].} = - return CONTRACT_WASM_PATH / deploymentAddr / "debug.wasm" + return CONTRACT_DEBUG_DATA_PATH / deploymentAddr / "debug.wasm" + +proc getContractSignatureMapPath(deploymentAddr: string): string {.raises: [].} = + return CONTRACT_DEBUG_DATA_PATH / deploymentAddr / "signature_map.json" # NOTE: remove CatchableError if using custom exception proc recordStylus*(hash: string): Trace {.raises: [IOError, ValueError, OSError, CatchableError, Exception].} = - let wasm = getContractWasmPath(getTransactionContractAddress(hash)) + let contractAddress = getTransactionContractAddress(hash) + let wasm = getContractWasmPath(contractAddress) + let signatureMap = getContractSignatureMapPath(contractAddress) let evmTrace = getEvmTrace(hash) + if not fileExists(signatureMap): + raise newException(CatchableError, "Signature map not found at " & signatureMap) + echo "WASM with debug info: ", wasm, " EVM trace: ", evmTrace - result = record("", ".", "", evmTrace, "", "", wasm, @[]) + result = record("", ".", "", evmTrace, signatureMap, "", "", wasm, @[]) updateField(result.id, "program", hash, false) result.program = hash @@ -58,4 +66,4 @@ proc replayStylus*(hash: string) {.raises: [IOError, ValueError, OSError, Catcha let recordedTrace = recordStylus(hash) # for now it prints `traceId:` which is read by index(from ct arb explorer) which starts the replay in its instance # for example - # traceId:479 + # traceId:479 diff --git a/src/ct/trace/record.nim b/src/ct/trace/record.nim index a53f4e524..92747d56a 100644 --- a/src/ct/trace/record.nim +++ b/src/ct/trace/record.nim @@ -33,6 +33,7 @@ proc record*(lang: string, outputFolder: string, exportFile: string, stylusTrace: string, + stylusSignatureMap: string, address: string, socketPath: string, program: string, @@ -51,6 +52,9 @@ proc record*(lang: string, if stylusTrace != "": pargs.add("--stylus-trace") pargs.add(stylusTrace) + if stylusSignatureMap != "": + pargs.add("--stylus-signature-map") + pargs.add(stylusSignatureMap) if address != "": pargs.add("--address") pargs.add(address) diff --git a/src/ct/trace/run.nim b/src/ct/trace/run.nim index 008e39424..d2a38a1c4 100644 --- a/src/ct/trace/run.nim +++ b/src/ct/trace/run.nim @@ -38,6 +38,7 @@ proc runWithRestart( outputFolder="", exportFile="", stylusTrace="", + stylusSignatureMap="", address="", socketPath="", program=recordArgs[0],