Skip to content

Commit 899efc8

Browse files
committed
Add support to set debugger's target VM version
1 parent 76af8f5 commit 899efc8

6 files changed

Lines changed: 64 additions & 11 deletions

File tree

packages/cashscript/src/advanced/LibauthTemplate.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
AuthenticationVirtualMachineIdentifier,
23
binToHex,
34
decodeCashAddress,
45
TransactionBch,
@@ -379,11 +380,16 @@ export const getLibauthTemplates = (
379380
const libauthTransaction = txn.buildLibauthTransaction();
380381
const csTransaction = createCSTransaction(txn);
381382

383+
let vmTarget: AuthenticationVirtualMachineIdentifier = 'BCH_2025_05';
384+
if ('vmTarget' in txn.provider) {
385+
vmTarget = txn.provider.vmTarget as AuthenticationVirtualMachineIdentifier;
386+
}
387+
382388
const baseTemplate: WalletTemplate = {
383389
$schema: 'https://ide.bitauth.com/authentication-template-v0.schema.json',
384390
description: 'Imported from cashscript',
385391
name: 'CashScript Generated Debugging Template',
386-
supported: ['BCH_2025_05'],
392+
supported: [vmTarget],
387393
version: 0,
388394
entities: {},
389395
scripts: {},

packages/cashscript/src/debugging.ts

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { AuthenticationErrorCommon, AuthenticationInstruction, AuthenticationProgramCommon, AuthenticationProgramStateCommon, AuthenticationVirtualMachine, ResolvedTransactionCommon, WalletTemplate, WalletTemplateScriptUnlocking, binToHex, createCompiler, createVirtualMachineBch2025, decodeAuthenticationInstructions, encodeAuthenticationInstruction, walletTemplateToCompilerConfiguration } from '@bitauth/libauth';
1+
import { AuthenticationErrorCommon, AuthenticationInstruction, AuthenticationProgramCommon, AuthenticationProgramStateBchSpec, AuthenticationProgramStateCommon, AuthenticationVirtualMachine, AuthenticationVirtualMachineIdentifier, ResolvedTransactionCommon, WalletTemplate, WalletTemplateScriptUnlocking, binToHex, createCompiler, createVirtualMachineBch2023, createVirtualMachineBch2025, createVirtualMachineBch2026, createVirtualMachineBchSpec, decodeAuthenticationInstructions, encodeAuthenticationInstruction, walletTemplateToCompilerConfiguration } from '@bitauth/libauth';
22
import { Artifact, LogEntry, Op, PrimitiveType, StackItem, asmToBytecode, bytecodeToAsm, decodeBool, decodeInt, decodeString } from '@cashscript/utils';
33
import { findLastIndex, toRegExp } from './utils.js';
44
import { FailedRequireError, FailedTransactionError, FailedTransactionEvaluationError } from './Errors.js';
@@ -7,6 +7,21 @@ import { getBitauthUri } from './LibauthTemplate.js';
77
export type DebugResult = AuthenticationProgramStateCommon[];
88
export type DebugResults = Record<string, DebugResult>;
99

10+
const createVirualMachine = (vmTarget: AuthenticationVirtualMachineIdentifier) => {
11+
switch (vmTarget) {
12+
case 'BCH_2023_05':
13+
return createVirtualMachineBch2023();
14+
case 'BCH_2025_05':
15+
return createVirtualMachineBch2025();
16+
case 'BCH_2026_05':
17+
return createVirtualMachineBch2026();
18+
case 'BCH_SPEC':
19+
return createVirtualMachineBchSpec();
20+
default:
21+
throw new Error(`Debugging is not supported for the ${vmTarget} virtual machine.`);;
22+
}
23+
}
24+
1025
// debugs the template, optionally logging the execution data
1126
export const debugTemplate = (template: WalletTemplate, artifacts: Artifact[]): DebugResults => {
1227
// If a contract has the same name, but a different bytecode, then it is considered a name collision
@@ -65,7 +80,7 @@ const debugSingleScenario = (
6580

6681
for (const log of executedLogs) {
6782
const inputIndex = extractInputIndexFromScenario(scenarioId);
68-
logConsoleLogStatement(log, executedDebugSteps, artifact, inputIndex);
83+
logConsoleLogStatement(log, executedDebugSteps, artifact, inputIndex, vm);
6984
}
7085

7186
const lastExecutedDebugStep = executedDebugSteps[executedDebugSteps.length - 1];
@@ -161,7 +176,7 @@ type CreateProgramResult = { vm: VM, program: Program };
161176
// internal util. instantiates the virtual machine and compiles the template into a program
162177
const createProgram = (template: WalletTemplate, unlockingScriptId: string, scenarioId: string): CreateProgramResult => {
163178
const configuration = walletTemplateToCompilerConfiguration(template);
164-
const vm = createVirtualMachineBch2025();
179+
const vm = createVirualMachine(template.supported[0]);
165180
const compiler = createCompiler(configuration);
166181

167182
if (!template.scripts[unlockingScriptId]) {
@@ -186,21 +201,22 @@ const createProgram = (template: WalletTemplate, unlockingScriptId: string, scen
186201
throw new FailedTransactionError(scenarioGeneration.scenario, getBitauthUri(template));
187202
}
188203

189-
return { vm, program: scenarioGeneration.scenario.program };
204+
return { vm: vm as VM, program: scenarioGeneration.scenario.program };
190205
};
191206

192207
const logConsoleLogStatement = (
193208
log: LogEntry,
194209
debugSteps: AuthenticationProgramStateCommon[],
195210
artifact: Artifact,
196211
inputIndex: number,
212+
vm: VM,
197213
): void => {
198214
let line = `${artifact.contractName}.cash:${log.line}`;
199215
const decodedData = log.data.map((element) => {
200216
if (typeof element === 'string') return element;
201217

202218
const debugStep = debugSteps.find((step) => step.ip === element.ip)!;
203-
const transformedDebugStep = applyStackItemTransformations(element, debugStep);
219+
const transformedDebugStep = applyStackItemTransformations(element, debugStep, vm);
204220
return decodeStackItem(element, transformedDebugStep.stack);
205221
});
206222
console.log(`[Input #${inputIndex}] ${line} ${decodedData.join(' ')}`);
@@ -209,6 +225,7 @@ const logConsoleLogStatement = (
209225
const applyStackItemTransformations = (
210226
element: StackItem,
211227
debugStep: AuthenticationProgramStateCommon,
228+
vm: VM,
212229
): AuthenticationProgramStateCommon => {
213230
if (!element.transformations) return debugStep;
214231

@@ -230,7 +247,6 @@ const applyStackItemTransformations = (
230247
functionCount: debugStep.functionCount ?? 0,
231248
};
232249

233-
const vm = createVirtualMachineBch2025();
234250
const transformationsEndState = vm.stateEvaluate(transformationsStartState);
235251

236252
return transformationsEndState;

packages/cashscript/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export {
1919
ElectrumNetworkProvider,
2020
FullStackNetworkProvider,
2121
MockNetworkProvider,
22+
VmTarget,
2223
} from './network/index.js';
2324
export { randomUtxo, randomToken, randomNFT } from './utils.js';
2425
export * from './walletconnect-utils.js';

packages/cashscript/src/network/MockNetworkProvider.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { binToHex, decodeTransactionUnsafe, hexToBin, isHex } from '@bitauth/libauth';
1+
import { AuthenticationVirtualMachineIdentifier, binToHex, decodeTransactionUnsafe, hexToBin, isHex } from '@bitauth/libauth';
22
import { sha256 } from '@cashscript/utils';
33
import { Utxo, Network } from '../interfaces.js';
44
import NetworkProvider from './NetworkProvider.js';
@@ -9,10 +9,13 @@ const aliceAddress = 'bchtest:qpgjmwev3spwlwkgmyjrr2s2cvlkkzlewq62mzgjnp';
99
const bobAddress = 'bchtest:qz6q5gqnxdldkr07xpls5474mmzmlesd6qnux4skuc';
1010
const carolAddress = 'bchtest:qqsr7nqwe6rq5crj63gy5gdqchpnwmguusmr7tfmsj';
1111

12-
interface MockNetworkProviderOptions {
12+
export interface MockNetworkProviderOptions {
1313
updateUtxoSet: boolean;
14+
vmTarget?: VmTarget;
1415
}
1516

17+
export type VmTarget = AuthenticationVirtualMachineIdentifier;
18+
1619
// We are setting the default updateUtxoSet to 'false' so that it doesn't break the current behaviour
1720
// TODO: in a future breaking release we want to set this to 'true' by default
1821
export default class MockNetworkProvider implements NetworkProvider {
@@ -22,9 +25,11 @@ export default class MockNetworkProvider implements NetworkProvider {
2225
public network: Network = Network.MOCKNET;
2326
public blockHeight: number = 133700;
2427
public options: MockNetworkProviderOptions;
28+
public vmTarget: VmTarget;
2529

2630
constructor(options?: Partial<MockNetworkProviderOptions>) {
2731
this.options = { updateUtxoSet: false, ...options };
32+
this.vmTarget = this.options.vmTarget ?? "BCH_2025_05";
2833

2934
for (let i = 0; i < 3; i += 1) {
3035
this.addUtxo(aliceAddress, randomUtxo());

packages/cashscript/src/network/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ export type { default as NetworkProvider } from './NetworkProvider.js';
22
export { default as BitcoinRpcNetworkProvider } from './BitcoinRpcNetworkProvider.js';
33
export { default as ElectrumNetworkProvider } from './ElectrumNetworkProvider.js';
44
export { default as FullStackNetworkProvider } from './FullStackNetworkProvider.js';
5-
export { default as MockNetworkProvider } from './MockNetworkProvider.js';
5+
export { default as MockNetworkProvider, VmTarget } from './MockNetworkProvider.js';

packages/cashscript/test/debugging.test.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Contract, MockNetworkProvider, SignatureAlgorithm, SignatureTemplate, TransactionBuilder } from '../src/index.js';
1+
import { Contract, MockNetworkProvider, SignatureAlgorithm, SignatureTemplate, TransactionBuilder, VmTarget } from '../src/index.js';
22
import { aliceAddress, alicePriv, alicePub, bobPriv, bobPub } from './fixture/vars.js';
33
import '../src/test/JestExtensions.js';
44
import { randomUtxo } from '../src/utils.js';
@@ -637,4 +637,29 @@ describe('Debugging tests', () => {
637637
).toThrow('The CashScript JestExtensions do not support the old transaction builder since v0.11.0. Please use the new TransactionBuilder class.');
638638
});
639639
});
640+
641+
describe('VmTargets', () => {
642+
for (const vmTarget of ['BCH_2020_05', undefined, 'BCH_2023_05', 'BCH_2025_05', 'BCH_2026_05', 'BCH_SPEC'] as VmTarget[]) {
643+
it(`should execute and log correctly with vmTarget ${vmTarget}`, async () => {
644+
const provider = new MockNetworkProvider({ vmTarget });
645+
const contractTestLogs = new Contract(artifactTestLogs, [alicePub], { provider });
646+
const contractUtxo = randomUtxo();
647+
provider.addUtxo(contractTestLogs.address, contractUtxo);
648+
649+
const transaction = new TransactionBuilder({ provider })
650+
.addInput(contractUtxo, contractTestLogs.unlock.transfer(new SignatureTemplate(alicePriv), 1000n))
651+
.addOutput({ to: contractTestLogs.address, amount: 10000n });
652+
653+
if (vmTarget === 'BCH_2020_05') {
654+
expect(() => transaction.debug()).toThrow('Debugging is not supported for the BCH_2020_05 virtual machine.');
655+
return;
656+
}
657+
658+
expect(transaction.getLibauthTemplate().supported[0]).toBe(vmTarget ?? 'BCH_2025_05');
659+
660+
const expectedLog = new RegExp(`^\\[Input #0] Test.cash:10 0x[0-9a-f]{130} 0x${binToHex(alicePub)} 1000 0xbeef 1 test true$`);
661+
expect(transaction).toLog(expectedLog);
662+
});
663+
}
664+
});
640665
});

0 commit comments

Comments
 (0)