Skip to content

Commit a7a37e1

Browse files
mainnet-patrkalis
andauthored
Update libauth, allow to set debugger's target VM version (#353)
Co-authored-by: Rosco Kalis <roscokalis@gmail.com>
1 parent 3ad11e4 commit a7a37e1

10 files changed

Lines changed: 90 additions & 20 deletions

File tree

packages/cashc/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
"test": "NODE_OPTIONS='--experimental-vm-modules --no-warnings' jest"
5252
},
5353
"dependencies": {
54-
"@bitauth/libauth": "^3.1.0-next.2",
54+
"@bitauth/libauth": "^3.1.0-next.8",
5555
"@cashscript/utils": "^0.11.5",
5656
"antlr4": "^4.13.2",
5757
"commander": "^14.0.0",

packages/cashscript/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
"test": "NODE_OPTIONS='--experimental-vm-modules --no-warnings' jest"
4646
},
4747
"dependencies": {
48-
"@bitauth/libauth": "^3.1.0-next.2",
48+
"@bitauth/libauth": "^3.1.0-next.8",
4949
"@cashscript/utils": "^0.11.5",
5050
"@electrum-cash/network": "^4.1.3",
5151
"@mr-zwets/bchn-api-wrapper": "^1.0.1",

packages/cashscript/src/LibauthTemplate.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,13 @@ import {
4242
TokenDetails,
4343
UnlockableUtxo,
4444
Utxo,
45+
VmTarget,
4546
} from './interfaces.js';
4647
import SignatureTemplate from './SignatureTemplate.js';
4748
import { addressToLockScript, extendedStringify, getSignatureAndPubkeyFromP2PKHInput, zip } from './utils.js';
4849
import { TransactionBuilder } from './TransactionBuilder.js';
4950
import { deflate } from 'pako';
51+
import MockNetworkProvider from './network/MockNetworkProvider.js';
5052

5153
// TODO: Add / improve descriptions throughout the template generation
5254

@@ -60,11 +62,13 @@ export const getLibauthTemplates = (
6062
const libauthTransaction = txn.buildLibauthTransaction();
6163
const csTransaction = createTransactionTypeFromTransactionBuilder(txn);
6264

65+
const vmTarget = txn.provider instanceof MockNetworkProvider ? txn.provider.vmTarget : VmTarget.BCH_2025_05;
66+
6367
const baseTemplate: WalletTemplate = {
6468
$schema: 'https://ide.bitauth.com/authentication-template-v0.schema.json',
6569
description: 'Imported from cashscript',
6670
name: 'CashScript Generated Debugging Template',
67-
supported: ['BCH_2025_05'],
71+
supported: [vmTarget],
6872
version: 0,
6973
entities: {},
7074
scripts: {},

packages/cashscript/src/debugging.ts

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,37 @@
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, 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';
55
import { getBitauthUri } from './LibauthTemplate.js';
6+
import { VmTarget } from './interfaces.js';
67

78
export type DebugResult = AuthenticationProgramStateCommon[];
89
export type DebugResults = Record<string, DebugResult>;
910

11+
/* eslint-disable @typescript-eslint/indent */
12+
type VM = AuthenticationVirtualMachine<
13+
ResolvedTransactionCommon,
14+
AuthenticationProgramCommon,
15+
AuthenticationProgramStateCommon
16+
>;
17+
/* eslint-enable @typescript-eslint/indent */
18+
19+
const createVirtualMachine = (vmTarget: VmTarget): VM => {
20+
switch (vmTarget) {
21+
case 'BCH_2023_05':
22+
return createVirtualMachineBch2023();
23+
case 'BCH_2025_05':
24+
return createVirtualMachineBch2025();
25+
case 'BCH_2026_05':
26+
return createVirtualMachineBch2026();
27+
case 'BCH_SPEC':
28+
// TODO: This typecast is shitty, but it's hard to fix
29+
return createVirtualMachineBchSpec() as unknown as VM;
30+
default:
31+
throw new Error(`Debugging is not supported for the ${vmTarget} virtual machine.`);
32+
}
33+
};
34+
1035
// debugs the template, optionally logging the execution data
1136
export const debugTemplate = (template: WalletTemplate, artifacts: Artifact[]): DebugResults => {
1237
// If a contract has the same name, but a different bytecode, then it is considered a name collision
@@ -61,7 +86,7 @@ const debugSingleScenario = (
6186

6287
for (const log of executedLogs) {
6388
const inputIndex = extractInputIndexFromScenario(scenarioId);
64-
logConsoleLogStatement(log, executedDebugSteps, artifact, inputIndex);
89+
logConsoleLogStatement(log, executedDebugSteps, artifact, inputIndex, vm);
6590
}
6691
}
6792

@@ -157,21 +182,13 @@ const extractInputIndexFromScenario = (scenarioId: string): number => {
157182
return parseInt(match[1]);
158183
};
159184

160-
/* eslint-disable @typescript-eslint/indent */
161-
type VM = AuthenticationVirtualMachine<
162-
ResolvedTransactionCommon,
163-
AuthenticationProgramCommon,
164-
AuthenticationProgramStateCommon
165-
>;
166-
/* eslint-enable @typescript-eslint/indent */
167-
168185
type Program = AuthenticationProgramCommon;
169186
type CreateProgramResult = { vm: VM, program: Program };
170187

171188
// internal util. instantiates the virtual machine and compiles the template into a program
172189
const createProgram = (template: WalletTemplate, unlockingScriptId: string, scenarioId: string): CreateProgramResult => {
173190
const configuration = walletTemplateToCompilerConfiguration(template);
174-
const vm = createVirtualMachineBch2025();
191+
const vm = createVirtualMachine(template.supported[0] as VmTarget);
175192
const compiler = createCompiler(configuration);
176193

177194
if (!template.scripts[unlockingScriptId]) {
@@ -204,13 +221,14 @@ const logConsoleLogStatement = (
204221
debugSteps: AuthenticationProgramStateCommon[],
205222
artifact: Artifact,
206223
inputIndex: number,
224+
vm: VM,
207225
): void => {
208226
let line = `${artifact.contractName}.cash:${log.line}`;
209227
const decodedData = log.data.map((element) => {
210228
if (typeof element === 'string') return element;
211229

212230
const debugStep = debugSteps.find((step) => step.ip === element.ip)!;
213-
const transformedDebugStep = applyStackItemTransformations(element, debugStep);
231+
const transformedDebugStep = applyStackItemTransformations(element, debugStep, vm);
214232
return decodeStackItem(element, transformedDebugStep.stack);
215233
});
216234
console.log(`[Input #${inputIndex}] ${line} ${decodedData.join(' ')}`);
@@ -219,6 +237,7 @@ const logConsoleLogStatement = (
219237
const applyStackItemTransformations = (
220238
element: StackItem,
221239
debugStep: AuthenticationProgramStateCommon,
240+
vm: VM,
222241
): AuthenticationProgramStateCommon => {
223242
if (!element.transformations) return debugStep;
224243

@@ -236,9 +255,10 @@ const applyStackItemTransformations = (
236255
instructions: transformationsAuthenticationInstructions,
237256
signedMessages: [],
238257
program: { ...debugStep.program },
258+
functionTable: debugStep.functionTable ?? {},
259+
functionCount: debugStep.functionCount ?? 0,
239260
};
240261

241-
const vm = createVirtualMachineBch2025();
242262
const transformationsEndState = vm.stateEvaluate(transformationsStartState);
243263

244264
return transformationsEndState;

packages/cashscript/src/interfaces.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,15 @@ export const Network = {
144144

145145
export type Network = (typeof Network)[keyof typeof Network];
146146

147+
export const VmTarget = {
148+
BCH_2023_05: literal('BCH_2023_05'),
149+
BCH_2025_05: literal('BCH_2025_05'),
150+
BCH_2026_05: literal('BCH_2026_05'),
151+
BCH_SPEC: literal('BCH_SPEC'),
152+
};
153+
154+
export type VmTarget = (typeof VmTarget)[keyof typeof VmTarget];
155+
147156
export interface TransactionDetails extends Transaction {
148157
txid: string;
149158
hex: string;

packages/cashscript/src/network/MockNetworkProvider.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { binToHex, decodeTransactionUnsafe, hexToBin, isHex } from '@bitauth/libauth';
22
import { sha256 } from '@cashscript/utils';
3-
import { Utxo, Network } from '../interfaces.js';
3+
import { Utxo, Network, VmTarget } 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

1112
export default class MockNetworkProvider implements NetworkProvider {
@@ -15,9 +16,11 @@ export default class MockNetworkProvider implements NetworkProvider {
1516
public network: Network = Network.MOCKNET;
1617
public blockHeight: number = 133700;
1718
public options: MockNetworkProviderOptions;
19+
public vmTarget: VmTarget;
1820

1921
constructor(options?: Partial<MockNetworkProviderOptions>) {
2022
this.options = { updateUtxoSet: true, ...options };
23+
this.vmTarget = this.options.vmTarget ?? VmTarget.BCH_2025_05;
2124
}
2225

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

packages/cashscript/test/debugging.test.ts

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

packages/utils/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
"test": "NODE_OPTIONS='--experimental-vm-modules --no-warnings' jest"
4545
},
4646
"dependencies": {
47-
"@bitauth/libauth": "^3.1.0-next.2"
47+
"@bitauth/libauth": "^3.1.0-next.8"
4848
},
4949
"devDependencies": {
5050
"@jest/globals": "^29.7.0",

website/docs/releases/release-notes.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ title: Release Notes
99
- :boom: **BREAKING**: Make `provider` a required option in `Contract` constructor.
1010
- :boom: **BREAKING**: Remove deprecated "old" transaction builder (`contract.functions`).
1111
- :boom: **BREAKING**: No longer seed the MockNetworkProvider with any test UTXOs.
12+
- :sparkles: Add a configurable `vmTarget` option to `MockNetworkProvider`.
1213
- :hammer_and_wrench: Improve libauth template generation.
1314

1415
## v0.11.5

yarn.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,11 @@
630630
resolved "https://registry.yarnpkg.com/@bitauth/libauth/-/libauth-3.1.0-next.2.tgz#121782b38774d9fba8226406db9b9af0c8d8e464"
631631
integrity sha512-XRtk9p8UHvtjSPS38rsfHXzaPHG5j9FpN4qHqqGLoAuZYy675PBiOy9zP6ah8lTnnIVaCFl2ekct8w0Hy1oefw==
632632

633+
"@bitauth/libauth@^3.1.0-next.8":
634+
version "3.1.0-next.8"
635+
resolved "https://registry.yarnpkg.com/@bitauth/libauth/-/libauth-3.1.0-next.8.tgz#d130e5db6c3c8b24731c8d04c4091be07f48b0ee"
636+
integrity sha512-Pm+Ju+YP3JeBLLTiVrBnia2wwE4G17r4XqpvPRMcklElJTe8J6x3JgKRg1by0Xm3ZY6UFxACkEAoSA+x419/zA==
637+
633638
"@chris.troutner/bip32-utils@1.0.5":
634639
version "1.0.5"
635640
resolved "https://registry.yarnpkg.com/@chris.troutner/bip32-utils/-/bip32-utils-1.0.5.tgz#b6722aeaad5fcda6fba69cbeda7e2a5e8afbd692"

0 commit comments

Comments
 (0)