Skip to content

Commit 9bf5c3c

Browse files
mainnet-patrkalis
authored andcommitted
Add support to set debugger's target VM version
1 parent 529ec0a commit 9bf5c3c

6 files changed

Lines changed: 64 additions & 11 deletions

File tree

packages/cashscript/src/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
binToBase64,
34
binToHex,
45
decodeCashAddress,
@@ -60,11 +61,16 @@ export const getLibauthTemplates = (
6061
const libauthTransaction = txn.buildLibauthTransaction();
6162
const csTransaction = createTransactionTypeFromTransactionBuilder(txn);
6263

64+
let vmTarget: AuthenticationVirtualMachineIdentifier = 'BCH_2025_05';
65+
if ('vmTarget' in txn.provider) {
66+
vmTarget = txn.provider.vmTarget as AuthenticationVirtualMachineIdentifier;
67+
}
68+
6369
const baseTemplate: WalletTemplate = {
6470
$schema: 'https://ide.bitauth.com/authentication-template-v0.schema.json',
6571
description: 'Imported from cashscript',
6672
name: 'CashScript Generated Debugging Template',
67-
supported: ['BCH_2025_05'],
73+
supported: [vmTarget],
6874
version: 0,
6975
entities: {},
7076
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, 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
@@ -61,7 +76,7 @@ const debugSingleScenario = (
6176

6277
for (const log of executedLogs) {
6378
const inputIndex = extractInputIndexFromScenario(scenarioId);
64-
logConsoleLogStatement(log, executedDebugSteps, artifact, inputIndex);
79+
logConsoleLogStatement(log, executedDebugSteps, artifact, inputIndex, vm);
6580
}
6681
}
6782

@@ -171,7 +186,7 @@ type CreateProgramResult = { vm: VM, program: Program };
171186
// internal util. instantiates the virtual machine and compiles the template into a program
172187
const createProgram = (template: WalletTemplate, unlockingScriptId: string, scenarioId: string): CreateProgramResult => {
173188
const configuration = walletTemplateToCompilerConfiguration(template);
174-
const vm = createVirtualMachineBch2025();
189+
const vm = createVirualMachine(template.supported[0]);
175190
const compiler = createCompiler(configuration);
176191

177192
if (!template.scripts[unlockingScriptId]) {
@@ -196,21 +211,22 @@ const createProgram = (template: WalletTemplate, unlockingScriptId: string, scen
196211
throw new FailedTransactionError(scenarioGeneration.scenario, getBitauthUri(template));
197212
}
198213

199-
return { vm, program: scenarioGeneration.scenario.program };
214+
return { vm: vm as VM, program: scenarioGeneration.scenario.program };
200215
};
201216

202217
const logConsoleLogStatement = (
203218
log: LogEntry,
204219
debugSteps: AuthenticationProgramStateCommon[],
205220
artifact: Artifact,
206221
inputIndex: number,
222+
vm: VM,
207223
): void => {
208224
let line = `${artifact.contractName}.cash:${log.line}`;
209225
const decodedData = log.data.map((element) => {
210226
if (typeof element === 'string') return element;
211227

212228
const debugStep = debugSteps.find((step) => step.ip === element.ip)!;
213-
const transformedDebugStep = applyStackItemTransformations(element, debugStep);
229+
const transformedDebugStep = applyStackItemTransformations(element, debugStep, vm);
214230
return decodeStackItem(element, transformedDebugStep.stack);
215231
});
216232
console.log(`[Input #${inputIndex}] ${line} ${decodedData.join(' ')}`);
@@ -219,6 +235,7 @@ const logConsoleLogStatement = (
219235
const applyStackItemTransformations = (
220236
element: StackItem,
221237
debugStep: AuthenticationProgramStateCommon,
238+
vm: VM,
222239
): AuthenticationProgramStateCommon => {
223240
if (!element.transformations) return debugStep;
224241

@@ -240,7 +257,6 @@ const applyStackItemTransformations = (
240257
functionCount: debugStep.functionCount ?? 0,
241258
};
242259

243-
const vm = createVirtualMachineBch2025();
244260
const transformationsEndState = vm.stateEvaluate(transformationsStartState);
245261

246262
return transformationsEndState;

packages/cashscript/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export {
1818
ElectrumNetworkProvider,
1919
FullStackNetworkProvider,
2020
MockNetworkProvider,
21+
VmTarget,
2122
} from './network/index.js';
2223
export { randomUtxo, randomToken, randomNFT } from './utils.js';
2324
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,23 +1,28 @@
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';
55
import { addressToLockScript, libauthTokenDetailsToCashScriptTokenDetails } from '../utils.js';
66

7-
interface MockNetworkProviderOptions {
7+
export interface MockNetworkProviderOptions {
88
updateUtxoSet: boolean;
9+
vmTarget?: VmTarget;
910
}
1011

12+
export type VmTarget = AuthenticationVirtualMachineIdentifier;
13+
1114
export default class MockNetworkProvider implements NetworkProvider {
1215
// we use lockingBytecode hex as the key for utxoMap to make cash addresses and token addresses interchangeable
1316
private utxoSet: Array<[string, Utxo]> = [];
1417
private transactionMap: Record<string, string> = {};
1518
public network: Network = Network.MOCKNET;
1619
public blockHeight: number = 133700;
1720
public options: MockNetworkProviderOptions;
21+
public vmTarget: VmTarget;
1822

1923
constructor(options?: Partial<MockNetworkProviderOptions>) {
2024
this.options = { updateUtxoSet: true, ...options };
25+
this.vmTarget = this.options.vmTarget ?? "BCH_2025_05";
2126
}
2227

2328
async getUtxos(address: string): Promise<Utxo[]> {

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, FailedTransactionError, MockNetworkProvider, SignatureAlgorithm, SignatureTemplate, TransactionBuilder } from '../src/index.js';
1+
import { Contract, FailedTransactionError, 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';
@@ -649,4 +649,29 @@ describe('Debugging tests', () => {
649649
expect(() => transactionBuilder.debug()).toThrow(FailedTransactionError);
650650
});
651651
});
652+
653+
describe('VmTargets', () => {
654+
for (const vmTarget of ['BCH_2020_05', undefined, 'BCH_2023_05', 'BCH_2025_05', 'BCH_2026_05', 'BCH_SPEC'] as VmTarget[]) {
655+
it(`should execute and log correctly with vmTarget ${vmTarget}`, async () => {
656+
const provider = new MockNetworkProvider({ vmTarget });
657+
const contractTestLogs = new Contract(artifactTestLogs, [alicePub], { provider });
658+
const contractUtxo = randomUtxo();
659+
provider.addUtxo(contractTestLogs.address, contractUtxo);
660+
661+
const transaction = new TransactionBuilder({ provider })
662+
.addInput(contractUtxo, contractTestLogs.unlock.transfer(new SignatureTemplate(alicePriv), 1000n))
663+
.addOutput({ to: contractTestLogs.address, amount: 10000n });
664+
665+
if (vmTarget === 'BCH_2020_05') {
666+
expect(() => transaction.debug()).toThrow('Debugging is not supported for the BCH_2020_05 virtual machine.');
667+
return;
668+
}
669+
670+
expect(transaction.getLibauthTemplate().supported[0]).toBe(vmTarget ?? 'BCH_2025_05');
671+
672+
const expectedLog = new RegExp(`^\\[Input #0] Test.cash:10 0x[0-9a-f]{130} 0x${binToHex(alicePub)} 1000 0xbeef 1 test true$`);
673+
expect(transaction).toLog(expectedLog);
674+
});
675+
}
676+
});
652677
});

0 commit comments

Comments
 (0)