Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/cashc/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"test": "NODE_OPTIONS='--experimental-vm-modules --no-warnings' jest"
},
"dependencies": {
"@bitauth/libauth": "^3.1.0-next.2",
"@bitauth/libauth": "^3.1.0-next.8",
"@cashscript/utils": "^0.11.5",
"antlr4": "^4.13.2",
"commander": "^14.0.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/cashscript/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"test": "NODE_OPTIONS='--experimental-vm-modules --no-warnings' jest"
},
"dependencies": {
"@bitauth/libauth": "^3.1.0-next.2",
"@bitauth/libauth": "^3.1.0-next.8",
"@cashscript/utils": "^0.11.5",
"@electrum-cash/network": "^4.1.3",
"@mr-zwets/bchn-api-wrapper": "^1.0.1",
Expand Down
6 changes: 5 additions & 1 deletion packages/cashscript/src/LibauthTemplate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,13 @@ import {
TokenDetails,
UnlockableUtxo,
Utxo,
VmTarget,
} from './interfaces.js';
import SignatureTemplate from './SignatureTemplate.js';
import { addressToLockScript, extendedStringify, getSignatureAndPubkeyFromP2PKHInput, zip } from './utils.js';
import { TransactionBuilder } from './TransactionBuilder.js';
import { deflate } from 'pako';
import MockNetworkProvider from './network/MockNetworkProvider.js';

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

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

const vmTarget = txn.provider instanceof MockNetworkProvider ? txn.provider.vmTarget : VmTarget.BCH_2025_05;

const baseTemplate: WalletTemplate = {
$schema: 'https://ide.bitauth.com/authentication-template-v0.schema.json',
description: 'Imported from cashscript',
name: 'CashScript Generated Debugging Template',
supported: ['BCH_2025_05'],
supported: [vmTarget],
version: 0,
entities: {},
scripts: {},
Expand Down
46 changes: 33 additions & 13 deletions packages/cashscript/src/debugging.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,37 @@
import { AuthenticationErrorCommon, AuthenticationInstruction, AuthenticationProgramCommon, AuthenticationProgramStateCommon, AuthenticationVirtualMachine, ResolvedTransactionCommon, WalletTemplate, WalletTemplateScriptUnlocking, binToHex, createCompiler, createVirtualMachineBch2025, decodeAuthenticationInstructions, encodeAuthenticationInstruction, walletTemplateToCompilerConfiguration } from '@bitauth/libauth';
import { AuthenticationErrorCommon, AuthenticationInstruction, AuthenticationProgramCommon, AuthenticationProgramStateCommon, AuthenticationVirtualMachine, ResolvedTransactionCommon, WalletTemplate, WalletTemplateScriptUnlocking, binToHex, createCompiler, createVirtualMachineBch2023, createVirtualMachineBch2025, createVirtualMachineBch2026, createVirtualMachineBchSpec, decodeAuthenticationInstructions, encodeAuthenticationInstruction, walletTemplateToCompilerConfiguration } from '@bitauth/libauth';
import { Artifact, LogEntry, Op, PrimitiveType, StackItem, asmToBytecode, bytecodeToAsm, decodeBool, decodeInt, decodeString } from '@cashscript/utils';
import { findLastIndex, toRegExp } from './utils.js';
import { FailedRequireError, FailedTransactionError, FailedTransactionEvaluationError } from './Errors.js';
import { getBitauthUri } from './LibauthTemplate.js';
import { VmTarget } from './interfaces.js';

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

/* eslint-disable @typescript-eslint/indent */
type VM = AuthenticationVirtualMachine<
ResolvedTransactionCommon,
AuthenticationProgramCommon,
AuthenticationProgramStateCommon
>;
/* eslint-enable @typescript-eslint/indent */

const createVirtualMachine = (vmTarget: VmTarget): VM => {
switch (vmTarget) {
case 'BCH_2023_05':
return createVirtualMachineBch2023();
case 'BCH_2025_05':
return createVirtualMachineBch2025();
case 'BCH_2026_05':
return createVirtualMachineBch2026();
case 'BCH_SPEC':
// TODO: This typecast is shitty, but it's hard to fix
return createVirtualMachineBchSpec() as unknown as VM;
default:
throw new Error(`Debugging is not supported for the ${vmTarget} virtual machine.`);
}
};

// debugs the template, optionally logging the execution data
export const debugTemplate = (template: WalletTemplate, artifacts: Artifact[]): DebugResults => {
// If a contract has the same name, but a different bytecode, then it is considered a name collision
Expand Down Expand Up @@ -61,7 +86,7 @@ const debugSingleScenario = (

for (const log of executedLogs) {
const inputIndex = extractInputIndexFromScenario(scenarioId);
logConsoleLogStatement(log, executedDebugSteps, artifact, inputIndex);
logConsoleLogStatement(log, executedDebugSteps, artifact, inputIndex, vm);
}
}

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

/* eslint-disable @typescript-eslint/indent */
type VM = AuthenticationVirtualMachine<
ResolvedTransactionCommon,
AuthenticationProgramCommon,
AuthenticationProgramStateCommon
>;
/* eslint-enable @typescript-eslint/indent */

type Program = AuthenticationProgramCommon;
type CreateProgramResult = { vm: VM, program: Program };

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

if (!template.scripts[unlockingScriptId]) {
Expand Down Expand Up @@ -204,13 +221,14 @@ const logConsoleLogStatement = (
debugSteps: AuthenticationProgramStateCommon[],
artifact: Artifact,
inputIndex: number,
vm: VM,
): void => {
let line = `${artifact.contractName}.cash:${log.line}`;
const decodedData = log.data.map((element) => {
if (typeof element === 'string') return element;

const debugStep = debugSteps.find((step) => step.ip === element.ip)!;
const transformedDebugStep = applyStackItemTransformations(element, debugStep);
const transformedDebugStep = applyStackItemTransformations(element, debugStep, vm);
return decodeStackItem(element, transformedDebugStep.stack);
});
console.log(`[Input #${inputIndex}] ${line} ${decodedData.join(' ')}`);
Expand All @@ -219,6 +237,7 @@ const logConsoleLogStatement = (
const applyStackItemTransformations = (
element: StackItem,
debugStep: AuthenticationProgramStateCommon,
vm: VM,
): AuthenticationProgramStateCommon => {
if (!element.transformations) return debugStep;

Expand All @@ -236,9 +255,10 @@ const applyStackItemTransformations = (
instructions: transformationsAuthenticationInstructions,
signedMessages: [],
program: { ...debugStep.program },
functionTable: debugStep.functionTable ?? {},
functionCount: debugStep.functionCount ?? 0,
};

const vm = createVirtualMachineBch2025();
const transformationsEndState = vm.stateEvaluate(transformationsStartState);

return transformationsEndState;
Expand Down
9 changes: 9 additions & 0 deletions packages/cashscript/src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,15 @@ export const Network = {

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

export const VmTarget = {
BCH_2023_05: literal('BCH_2023_05'),
BCH_2025_05: literal('BCH_2025_05'),
BCH_2026_05: literal('BCH_2026_05'),
BCH_SPEC: literal('BCH_SPEC'),
};

export type VmTarget = (typeof VmTarget)[keyof typeof VmTarget];

export interface TransactionDetails extends Transaction {
txid: string;
hex: string;
Expand Down
7 changes: 5 additions & 2 deletions packages/cashscript/src/network/MockNetworkProvider.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { binToHex, decodeTransactionUnsafe, hexToBin, isHex } from '@bitauth/libauth';
import { sha256 } from '@cashscript/utils';
import { Utxo, Network } from '../interfaces.js';
import { Utxo, Network, VmTarget } from '../interfaces.js';
import NetworkProvider from './NetworkProvider.js';
import { addressToLockScript, libauthTokenDetailsToCashScriptTokenDetails } from '../utils.js';

interface MockNetworkProviderOptions {
export interface MockNetworkProviderOptions {
updateUtxoSet: boolean;
vmTarget?: VmTarget;
}

export default class MockNetworkProvider implements NetworkProvider {
Expand All @@ -15,9 +16,11 @@ export default class MockNetworkProvider implements NetworkProvider {
public network: Network = Network.MOCKNET;
public blockHeight: number = 133700;
public options: MockNetworkProviderOptions;
public vmTarget: VmTarget;

constructor(options?: Partial<MockNetworkProviderOptions>) {
this.options = { updateUtxoSet: true, ...options };
this.vmTarget = this.options.vmTarget ?? VmTarget.BCH_2025_05;
}

async getUtxos(address: string): Promise<Utxo[]> {
Expand Down
30 changes: 29 additions & 1 deletion packages/cashscript/test/debugging.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Contract, FailedTransactionError, MockNetworkProvider, SignatureAlgorithm, SignatureTemplate, TransactionBuilder } from '../src/index.js';
import { Contract, FailedTransactionError, MockNetworkProvider, SignatureAlgorithm, SignatureTemplate, TransactionBuilder, VmTarget } from '../src/index.js';
import { aliceAddress, alicePriv, alicePub, bobPriv, bobPub } from './fixture/vars.js';
import '../src/test/JestExtensions.js';
import { randomUtxo } from '../src/utils.js';
Expand Down Expand Up @@ -649,4 +649,32 @@ describe('Debugging tests', () => {
expect(() => transactionBuilder.debug()).toThrow(FailedTransactionError);
});
});

describe('VmTargets', () => {
const vmTargets = [
undefined,
VmTarget.BCH_2023_05,
VmTarget.BCH_2025_05,
VmTarget.BCH_2026_05,
VmTarget.BCH_SPEC,
] as const;

for (const vmTarget of vmTargets) {
it(`should execute and log correctly with vmTarget ${vmTarget}`, async () => {
const provider = new MockNetworkProvider({ vmTarget });
const contractTestLogs = new Contract(artifactTestLogs, [alicePub], { provider });
const contractUtxo = randomUtxo();
provider.addUtxo(contractTestLogs.address, contractUtxo);

const transaction = new TransactionBuilder({ provider })
.addInput(contractUtxo, contractTestLogs.unlock.transfer(new SignatureTemplate(alicePriv), 1000n))
.addOutput({ to: contractTestLogs.address, amount: 10000n });

expect(transaction.getLibauthTemplate().supported[0]).toBe(vmTarget ?? 'BCH_2025_05');

const expectedLog = new RegExp(`^\\[Input #0] Test.cash:10 0x[0-9a-f]{130} 0x${binToHex(alicePub)} 1000 0xbeef 1 test true$`);
expect(transaction).toLog(expectedLog);
});
}
});
});
2 changes: 1 addition & 1 deletion packages/utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
"test": "NODE_OPTIONS='--experimental-vm-modules --no-warnings' jest"
},
"dependencies": {
"@bitauth/libauth": "^3.1.0-next.2"
"@bitauth/libauth": "^3.1.0-next.8"
},
"devDependencies": {
"@jest/globals": "^29.7.0",
Expand Down
1 change: 1 addition & 0 deletions website/docs/releases/release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ title: Release Notes
- :boom: **BREAKING**: Make `provider` a required option in `Contract` constructor.
- :boom: **BREAKING**: Remove deprecated "old" transaction builder (`contract.functions`).
- :boom: **BREAKING**: No longer seed the MockNetworkProvider with any test UTXOs.
- :sparkles: Add a configurable `vmTarget` option to `MockNetworkProvider`.
- :hammer_and_wrench: Improve libauth template generation.

## v0.11.5
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,11 @@
resolved "https://registry.yarnpkg.com/@bitauth/libauth/-/libauth-3.1.0-next.2.tgz#121782b38774d9fba8226406db9b9af0c8d8e464"
integrity sha512-XRtk9p8UHvtjSPS38rsfHXzaPHG5j9FpN4qHqqGLoAuZYy675PBiOy9zP6ah8lTnnIVaCFl2ekct8w0Hy1oefw==

"@bitauth/libauth@^3.1.0-next.8":
version "3.1.0-next.8"
resolved "https://registry.yarnpkg.com/@bitauth/libauth/-/libauth-3.1.0-next.8.tgz#d130e5db6c3c8b24731c8d04c4091be07f48b0ee"
integrity sha512-Pm+Ju+YP3JeBLLTiVrBnia2wwE4G17r4XqpvPRMcklElJTe8J6x3JgKRg1by0Xm3ZY6UFxACkEAoSA+x419/zA==

"@chris.troutner/bip32-utils@1.0.5":
version "1.0.5"
resolved "https://registry.yarnpkg.com/@chris.troutner/bip32-utils/-/bip32-utils-1.0.5.tgz#b6722aeaad5fcda6fba69cbeda7e2a5e8afbd692"
Expand Down
Loading