From 4329413f80525df65ec4938fc3f5672578f21fe9 Mon Sep 17 00:00:00 2001 From: Yonghui Lin Date: Wed, 22 Jun 2022 16:48:47 +0800 Subject: [PATCH] feat(debugger): supported debug message (#358) * test(debugger): sepc256k1 with wrong signature * feat(debugger): export default ckb-debugger download dir * feat(debugger): output debugger message in ExecuteResult --- packages/debugger/src/download.ts | 7 ++- packages/debugger/src/executor.ts | 25 +++++++-- packages/debugger/src/parse.ts | 11 +++- packages/debugger/src/types.ts | 1 + packages/debugger/tests/context.test.ts | 70 +++++++++++++++++++++++- packages/debugger/tests/deps/debugger | Bin 0 -> 3784 bytes 6 files changed, 103 insertions(+), 11 deletions(-) create mode 100644 packages/debugger/tests/deps/debugger diff --git a/packages/debugger/src/download.ts b/packages/debugger/src/download.ts index b11895f4b..f815e1927 100644 --- a/packages/debugger/src/download.ts +++ b/packages/debugger/src/download.ts @@ -5,6 +5,10 @@ import path from "path"; import * as fs from "fs"; import { CKB_DEBUGGER_VERSION } from "./constants"; +export const DEFAULT_CKB_DEBUGGER_DIRECTORY_PATH = envPaths("ckb-debugger", { + suffix: CKB_DEBUGGER_VERSION, +}).cache; + export interface DownloadDebuggerOptions { version?: string; dir?: string; @@ -16,8 +20,7 @@ export class CKBDebuggerDownloader { constructor(options?: DownloadDebuggerOptions) { const version = options?.version || CKB_DEBUGGER_VERSION; - const saveToPath = - options?.dir || envPaths("ckb-debugger", { suffix: version }).cache; + const saveToPath = options?.dir || DEFAULT_CKB_DEBUGGER_DIRECTORY_PATH; this.config = { dir: saveToPath, version }; } diff --git a/packages/debugger/src/executor.ts b/packages/debugger/src/executor.ts index e7f72e9b0..b8cacc69c 100644 --- a/packages/debugger/src/executor.ts +++ b/packages/debugger/src/executor.ts @@ -1,6 +1,6 @@ -import { DataLoader, Executor, ExecuteResult } from "./types"; +import { DataLoader, ExecuteResult, Executor } from "./types"; import { TransactionSkeletonType } from "@ckb-lumos/helpers"; -import { execSync } from "child_process"; +import { spawnSync } from "child_process"; import { Hash } from "@ckb-lumos/base"; import * as fs from "fs"; import * as os from "os"; @@ -54,9 +54,24 @@ export class CKBDebugger implements Executor { ): Promise { const tmpTxPath = this.saveTmpTxFile(txSkeleton); - const buf = execSync( - `${this.debuggerPath} --mode full --tx-file ${tmpTxPath} --script-hash ${options.scriptHash} --script-group-type ${options.scriptGroupType}` + const buf = spawnSync( + this.debuggerPath, + [ + "--tx-file", + tmpTxPath, + "--script-hash", + options.scriptHash, + "--script-group-type", + options.scriptGroupType, + ], + { + env: { RUST_LOG: "debug" }, + } + ); + + return parseDebuggerMessage( + buf.stdout.toString("utf-8"), + buf.stderr.toString("utf-8") ); - return parseDebuggerMessage(buf.toString("utf-8")); } } diff --git a/packages/debugger/src/parse.ts b/packages/debugger/src/parse.ts index 6aef76142..c254a751c 100644 --- a/packages/debugger/src/parse.ts +++ b/packages/debugger/src/parse.ts @@ -7,18 +7,23 @@ import { CellDep, HexString } from "@ckb-lumos/base"; import { bytify } from "@ckb-lumos/codec/lib/bytes"; import { OutPointVec } from "./codecs"; -export function parseDebuggerMessage(message: string): ExecuteResult { +export function parseDebuggerMessage( + message: string, + debugMessage = "" +): ExecuteResult { const codeMatch = message.match(/Run result: (-?\d+)/); const cycleMatch = message.match(/Total cycles consumed: (\d+)/); if (!codeMatch || !cycleMatch) { - throw new Error("Invalid debugger result: " + message); + throw new Error( + "Invalid debugger result: " + message + (debugMessage ? debugMessage : "") + ); } const code = Number(codeMatch[1]); const cycles = Number(cycleMatch[1]); - return { code, cycles, message }; + return { code, cycles, message, debugMessage }; } type ResolvedCellDep = { cell_dep: CellDep; data: HexString }; diff --git a/packages/debugger/src/types.ts b/packages/debugger/src/types.ts index e455ee3f5..3e60b20f2 100644 --- a/packages/debugger/src/types.ts +++ b/packages/debugger/src/types.ts @@ -17,6 +17,7 @@ export interface ExecuteResult { code: number; cycles: number; message: string; + debugMessage: string; } export interface DataLoader { diff --git a/packages/debugger/tests/context.test.ts b/packages/debugger/tests/context.test.ts index ce42a77bc..c5a4db987 100644 --- a/packages/debugger/tests/context.test.ts +++ b/packages/debugger/tests/context.test.ts @@ -31,6 +31,12 @@ const context = createTestContext({ path: path.join(__dirname, "deps/secp256k1_blake160"), includes: [path.join(__dirname, "deps/secp256k1_data_info")], }, + // https://github.com/nervosnetwork/ckb/blob/develop/script/testdata/debugger.c + DEBUGGER: { + // the dep_type is defaults to "code" + // dep_type: "code", + path: path.join(__dirname, "deps/debugger"), + }, }, }); @@ -150,5 +156,67 @@ test("context#CKBDebugger with secp256k1 with correct signature", async (t) => { t.true(result.cycles > 0); }); -test.todo("context#CKBDebugger with secp256k1 with wrong signature"); +test("context#CKBDebugger with secp256k1 with wrong signature", async (t) => { + let txSkeleton = TransactionSkeleton({}); + const pk = hexify(randomBytes(32)); + const blake160 = privateKeyToBlake160(pk); + + const secp256k1Lock = registry.newScript("SECP256K1_BLAKE160", blake160); + + txSkeleton = txSkeleton.update("inputs", (inputs) => + inputs.push({ + out_point: mockOutPoint(), + ...createCellWithMinimalCapacity({ lock: secp256k1Lock }), + }) + ); + txSkeleton.update("outputs", (outputs) => + outputs.push(createCellWithMinimalCapacity({ lock: secp256k1Lock })) + ); + txSkeleton = txSkeleton.update("cellDeps", (cellDeps) => + cellDeps.push(registry.newCellDep("SECP256K1_BLAKE160")) + ); + + txSkeleton = txSkeleton.update("witnesses", (witnesses) => + witnesses.push(hexify(WitnessArgs.pack({ lock: "0x" + "00".repeat(65) }))) + ); + const signingGroup = createP2PKHMessageGroup(txSkeleton, [secp256k1Lock]); + const wrongPK = hexify(randomBytes(32)); + const signedMessage = signRecoverable(signingGroup[0].message, wrongPK); + + txSkeleton = txSkeleton.update("witnesses", (witnesses) => + witnesses.set(0, hexify(WitnessArgs.pack({ lock: signedMessage }))) + ); + + const result = await context.executor.execute(txSkeleton, { + scriptGroupType: "lock", + scriptHash: computeScriptHash(secp256k1Lock), + }); + + t.is(result.code, -31); + t.true(result.cycles > 0); +}); + +test("context#CKBDebugger with printf debug message", async (t) => { + let txSkeleton = TransactionSkeleton({}); + const debugScript = registry.newScript("DEBUGGER", "0x"); + + txSkeleton = txSkeleton.update("inputs", (inputs) => + inputs.push({ + out_point: mockOutPoint(), + ...createCellWithMinimalCapacity({ lock: debugScript }), + }) + ); + txSkeleton = txSkeleton.update("cellDeps", (cellDeps) => + cellDeps.push(registry.newCellDep("DEBUGGER")) + ); + + const result = await context.executor.execute(txSkeleton, { + scriptGroupType: "lock", + scriptHash: computeScriptHash(debugScript), + }); + + t.regex(result.debugMessage, /debugger print utf-8 string/); + t.is(result.code, 0); +}); + test.todo("context#CKBDebugger with transfer sUDT"); diff --git a/packages/debugger/tests/deps/debugger b/packages/debugger/tests/deps/debugger new file mode 100644 index 0000000000000000000000000000000000000000..c0ef526adce0c13d7569bb17d060325c310e578b GIT binary patch literal 3784 zcmeHKUrbw782|3=Z3~+MT{k+mA(blAZdQso7!U%C+p?)MS+YGC5z1}(BbH%%nPNih z?QMY)G9ks3L=v%4h8r;?b0L`zY*7TGChoz^CB`7s!2?M#7AMK3p2IzdbtFFR&2W-? zzJI^p_uYQ?+@5pa4C4zn7t9}tl`NNkw<9R= zj7_pJcF7*@-P`L$DbiszJ=hTTvp$B;9Q6CbC|_u{(xq2_a`;Bn?~6PR5SF9~eNbA{ zcQfm$=OsQ4^Jxb3qx9iJ;0$=nC3R{l6!o^{lg!QECq&L^#O&iBSgBn$RA<@3WBl1^M&79BIy1y+1YaPa2muB-EzDSiQ!%AXaroJK1*@ zUaxA6wmMKPA(RSoQNSn!iQa?-dD=gDTU63EM~v8zSy0(dwkkd$ib~?`9if-em;ARGC0+Jfe9rY{E3 z^R_YkljDqTrYU!scj|kzWqK}9merpZQ+lK=)5Vl7;2w1C4jT$#EHWbaBfm|lrlf?q zS1#(w2`z=STBE7#&SS&&do^9Bg|C)5VMhw9-%|wT@0*HeGURcsRc$NHybYI^=fE^> zu$qd0G=^+~;U|#C?A9CSO&4$Gf1oiysy0nKGm;;(v zDd($*!zjRYW|SFKU18SzJ_G@$tD&Q*$>lM&ds^B=V~5!IOtH}`A_K1!fK~Edy+Pj3 z@}zfn1CXV>N0UU>?^EoJ*#BUnzb5Uu?=KbZa^GJ0MUDQ2w#Rk{wmY!hf$a`#ci`bV zFh|axRN9XnD=|K0KY99Tqt$A$TJoXNj4F6qyuvwPj7a4&)Sh!k3R?==^XuGra^Oio z6M)6rjP`EP(Et|F^|lBW&snEKbb!UxT-WGvxLsgrX=@Sd93GFO6D*C$pt^$dDx$&b z1&eUj?RK@{B)GW6A)-@3Lxp6Mj+2B>K07wE(E3z9 ziz4Ys{A+}NjqoXsCZINzr6`bm|8)J#5q=H&I!GRrM}3t@N#fB`Tqi^$aEP1 literal 0 HcmV?d00001