MCPcopy Create free account
hub / github.com/CashScript/cashscript / debugSingleScenario

Function debugSingleScenario

packages/cashscript/src/debugging.ts:66–193  ·  view source on GitHub ↗
(
  template: WalletTemplate, artifact: Artifact | undefined, unlockingScriptId: string, scenarioId: string,
)

Source from the content-addressed store, hash-verified

64};
65
66const debugSingleScenario = (
67 template: WalletTemplate, artifact: Artifact | undefined, unlockingScriptId: string, scenarioId: string,
68): DebugResult => {
69 const { vm, program } = createProgram(template, unlockingScriptId, scenarioId);
70
71 const fullDebugSteps = vm.debug(program);
72
73 // P2SH executions have 3 phases, we only want the last one (locking script execution)
74 // https://libauth.org/types/AuthenticationVirtualMachine.html#__type.debug
75 const lockingScriptDebugResult = fullDebugSteps.slice(findLastIndex(fullDebugSteps, (state) => state.ip === 0));
76
77 // The controlStack determines whether the current debug step is in the executed branch
78 // It also tracks loop / function usage, but for the purpose of determining whether a step was executed,
79 // we only need to check that there are no 'false' items in the control stack.
80 // https://libauth.org/types/AuthenticationProgramStateControlStack.html
81 // https://github.com/bitjson/bch-loops#control-stack
82 const executedDebugSteps = lockingScriptDebugResult
83 .filter((debugStep) => debugStep.controlStack.every(item => item !== false));
84
85 // P2PKH inputs do not have an artifact, so we skip the console.log handling
86 if (artifact) {
87 // Try to match each executed debug step to a log entry if it exists. Note that inside loops,
88 // the same log statement may be executed multiple times in different debug steps
89 // Also note that multiple log statements may exist for the same ip, so we need to handle all of them
90 const executedLogs = executedDebugSteps
91 .flatMap((debugStep, index) => {
92 const logEntries = artifact.debug?.logs?.filter((log) => log.ip === debugStep.ip);
93 if (!logEntries || logEntries.length === 0) return [];
94
95 const reversedPriorDebugSteps = executedDebugSteps.slice(0, index + 1).reverse();
96
97 return logEntries.map((logEntry) => {
98 const decodedLogData = logEntry.data
99 .map((dataEntry) => decodeLogDataEntry(dataEntry, reversedPriorDebugSteps, vm));
100 return { logEntry, decodedLogData };
101 });
102 });
103
104 for (const { logEntry, decodedLogData } of executedLogs) {
105 const inputIndex = extractInputIndexFromScenario(scenarioId);
106 logConsoleLogStatement(logEntry, decodedLogData, artifact.contractName, inputIndex);
107 }
108 }
109
110 const lastExecutedDebugStep = executedDebugSteps[executedDebugSteps.length - 1];
111
112 // If an error is present in the last step, that means a require statement in the middle of the function failed
113 if (lastExecutedDebugStep.error) {
114 // In Libauth any thrown error gets registered in the instruction that happens right *after* the instruction that
115 // caused the error (in other words the OP_VERIFY). We need to decrement the instruction pointer to get the correct
116 // failing instruction.
117 const failingIp = lastExecutedDebugStep.ip - 1;
118 const failingInstruction = lastExecutedDebugStep.instructions[failingIp];
119
120 // With optimisations, the OP_CHECKSIG and OP_VERIFY instructions are merged into a single opcode (OP_CHECKSIGVERIFY).
121 // However, for the final verify, the OP_VERIFY is not present. In most cases, the implicit final VERIFY is checked
122 // later in the code. However, for NULLFAIL, the error is thrown in the OP_CHECKSIG opcode, rather than in the
123 // implicit final VERIFY. The error message is registered in the next instruction, so we need to increment the

Callers 1

debugTemplateFunction · 0.85

Calls 10

createProgramFunction · 0.85
findLastIndexFunction · 0.85
decodeLogDataEntryFunction · 0.85
logConsoleLogStatementFunction · 0.85
getBitauthUriFunction · 0.85
failedFinalVerifyFunction · 0.85
getFinalExecutedVerifyIpFunction · 0.85
debugMethod · 0.65

Tested by

no test coverage detected