diff --git a/package.json b/package.json
index c392f3e..e2d16f3 100644
--- a/package.json
+++ b/package.json
@@ -3,7 +3,7 @@
"version": "1.0.0",
"private": true,
"devDependencies": {
- "@bitauth/libauth": "3.1.0-next.0",
+ "@bitauth/libauth": "3.1.0-next.1",
"@blueprintjs/core": "^5.8.2",
"@blueprintjs/icons": "^5.7.0",
"@blueprintjs/select": "^5.0.23",
diff --git a/src/editor/Editor.tsx b/src/editor/Editor.tsx
index 1153a8d..fe1251d 100644
--- a/src/editor/Editor.tsx
+++ b/src/editor/Editor.tsx
@@ -190,7 +190,7 @@ export const Editor = connect(
deleteScript={props.deleteScript}
editScript={props.editScript}
frame={computed.scriptEditorFrames[indexFromTop]!}
- isP2SH={computed.lockingType === 'p2sh20'}
+ lockingType={computed.lockingType}
isPushed={computed.isPushed}
scriptDetails={computed.scriptDetails}
setCursorLine={setCursorLine[indexFromTop]!}
diff --git a/src/editor/dialogs/edit-script-dialog/EditScriptDialog.tsx b/src/editor/dialogs/edit-script-dialog/EditScriptDialog.tsx
index 95f229f..195f35b 100644
--- a/src/editor/dialogs/edit-script-dialog/EditScriptDialog.tsx
+++ b/src/editor/dialogs/edit-script-dialog/EditScriptDialog.tsx
@@ -1,6 +1,11 @@
import '../editor-dialog.css';
import { ActionCreators } from '../../../state/reducer';
-import { ScriptType } from '../../../state/types';
+import {
+ LockingType,
+ lockingTypeDescriptions,
+ lockingTypes,
+ ScriptType,
+} from '../../../state/types';
import { toConventionalId } from '../../common';
import {
@@ -9,6 +14,7 @@ import {
Classes,
Dialog,
FormGroup,
+ HTMLSelect,
InputGroup,
Intent,
Switch,
@@ -21,7 +27,7 @@ export const EditScriptDialog = ({
name,
internalId,
id,
- isP2SH,
+ lockingType,
isPushed,
isOpen,
closeDialog,
@@ -33,8 +39,8 @@ export const EditScriptDialog = ({
name: string;
internalId: string;
id: string;
- isP2SH?: boolean;
- isPushed?: boolean;
+ lockingType: LockingType;
+ isPushed: boolean;
usedIds: string[];
editScript: typeof ActionCreators.editScript;
deleteScript: typeof ActionCreators.deleteScript;
@@ -43,7 +49,7 @@ export const EditScriptDialog = ({
}) => {
const [scriptName, setScriptName] = useState(name);
const [scriptId, setScriptId] = useState(id);
- const [scriptIsP2SH, setScriptIsP2SH] = useState(isP2SH);
+ const [scriptLockingType, setScriptLockingType] = useState(lockingType);
const [scriptIsPushed, setScriptIsPushed] = useState(isPushed);
const [nonUniqueId, setNonUniqueId] = useState('');
const [promptDelete, setPromptDelete] = useState(false);
@@ -55,7 +61,7 @@ export const EditScriptDialog = ({
onOpening={() => {
setScriptName(name);
setScriptId(id);
- setScriptIsP2SH(isP2SH);
+ setScriptLockingType(lockingType);
setNonUniqueId('');
}}
onClose={() => {
@@ -117,22 +123,16 @@ export const EditScriptDialog = ({
)}
{scriptType === 'locking' && (
- If enabled, this script will be nested in the standard P2SH
- template.
-
- }
+ helperText={lockingTypeDescriptions[scriptLockingType]}
label="Script Mode"
labelFor="script-p2sh"
inline={true}
>
- {
- setScriptIsP2SH(!scriptIsP2SH);
+ options={lockingTypes}
+ onChange={(e) => {
+ setScriptLockingType(e.currentTarget.value as LockingType);
}}
/>
@@ -212,7 +212,7 @@ export const EditScriptDialog = ({
scriptName === '' ||
(scriptName === name &&
scriptId === id &&
- scriptIsP2SH === isP2SH &&
+ scriptLockingType === lockingType &&
scriptIsPushed === isPushed) ||
(!isTest && scriptId === '')
}
@@ -224,7 +224,7 @@ export const EditScriptDialog = ({
internalId,
name: scriptName,
id: scriptId,
- lockingType: scriptIsP2SH ? 'p2sh20' : 'standard',
+ lockingType: scriptLockingType,
isPushed: scriptIsPushed,
});
closeDialog();
diff --git a/src/editor/dialogs/new-script-dialog/NewScriptDialog.tsx b/src/editor/dialogs/new-script-dialog/NewScriptDialog.tsx
index 52fe1bf..07b6202 100644
--- a/src/editor/dialogs/new-script-dialog/NewScriptDialog.tsx
+++ b/src/editor/dialogs/new-script-dialog/NewScriptDialog.tsx
@@ -4,7 +4,8 @@ import {
ActiveDialog,
BaseScriptType,
CurrentScripts,
- ScriptType,
+ scriptTypes,
+ typeDescriptions,
} from '../../../state/types';
import { createInsecureUuidV4 } from '../../../utils';
import { toConventionalId } from '../../common';
@@ -20,28 +21,6 @@ import {
import { WarningSign } from '@blueprintjs/icons';
import React, { useState } from 'react';
-const scriptTypes: { label: string; value: ScriptType }[] = [
- { label: 'Locking Script', value: 'locking' },
- { label: 'Unlocking Script', value: 'unlocking' },
- { label: 'Isolated Script', value: 'isolated' },
- { label: 'Script Test', value: 'test-setup' },
-];
-
-const typeDescriptions: { [key in ScriptType]: string } = {
- locking:
- 'Locking scripts hold funds. A locking script is the “challenge” which must be unlocked to spend a transaction output. An “Address” is simply an abstraction for a specific locking script.',
- unlocking:
- 'An unlocking script spends from a locking script. To create a transaction, the spender must provide a valid unlocking script for each input being spent. (A locking script can be unlocked by multiple unlocking scripts.)',
- isolated:
- 'An isolated script is useful for constructions like checksums or re-usable utility scripts (which can be used inside other scripts). Isolated scripts can have script tests, e.g. utility scripts can be tested to ensure they perform a series of operations properly.',
- 'test-setup':
- 'A script test is applied to an isolated script. Each script test has a “setup” phase which is evaluated before the tested script, and a “check” phase which is evaluated after. The test passes if the “check” script leaves a single Script Number 1 on the stack.',
- tested:
- 'Something is broken: tested scripts should be created by assigning a test-setup script to an isolated script.',
- 'test-check':
- 'Something is broken: script tests should use the `test-setup` type in this dialog.',
-};
-
const hasParent = (scriptType: BaseScriptType) =>
scriptType === 'unlocking' || scriptType === 'test-setup';
diff --git a/src/editor/editor-state.ts b/src/editor/editor-state.ts
index d4cf02e..3445266 100644
--- a/src/editor/editor-state.ts
+++ b/src/editor/editor-state.ts
@@ -26,6 +26,8 @@ import {
CompilationResultSuccess,
createCompiler,
createVirtualMachineBch2023,
+ createVirtualMachineBch2025,
+ createVirtualMachineBch2026,
createVirtualMachineBchSpec,
encodeDataPush,
EvaluationSample,
@@ -106,7 +108,11 @@ export const computeEditorState = <
const vm =
state.currentVmId === 'BCH_2023_05'
? createVirtualMachineBch2023()
- : createVirtualMachineBchSpec();
+ : state.currentVmId === 'BCH_2025_05'
+ ? createVirtualMachineBch2025()
+ : state.currentVmId === 'BCH_2026_05'
+ ? createVirtualMachineBch2026()
+ : createVirtualMachineBchSpec();
const compiler = createCompiler(configuration);
/**
diff --git a/src/editor/evaluation-viewer/EvaluationViewer.tsx b/src/editor/evaluation-viewer/EvaluationViewer.tsx
index 3162130..443569d 100644
--- a/src/editor/evaluation-viewer/EvaluationViewer.tsx
+++ b/src/editor/evaluation-viewer/EvaluationViewer.tsx
@@ -104,6 +104,17 @@ const stackItem = (
);
+const elideAt = 200;
+const splitAt = 100;
+const elideDigits = (digits: string) =>
+ digits.length < elideAt
+ ? digits
+ : `${digits.slice(0, splitAt)} \u2026 (${digits.length - elideAt} total digits) \u2026 ${digits.slice(-splitAt)}`;
+const elideHex = (characters: string) =>
+ characters.length < elideAt
+ ? characters
+ : `${characters.slice(0, splitAt)} \u2026 (${(characters.length - 2) / 2} total bytes) \u2026 ${characters.slice(-splitAt)}`;
+
const getStackItemDisplaySettings = (
item: Uint8Array,
settings: EvaluationViewerSettings,
@@ -122,7 +133,7 @@ const getStackItemDisplaySettings = (
const number = vmNumberToBigInt(item, {
maximumVmNumberByteLength:
settings.vmNumbersDisplayFormat === 'bigint'
- ? 258
+ ? 10_000
: settings.supportBigInt
? 19
: 8,
@@ -132,17 +143,17 @@ const getStackItemDisplaySettings = (
settings.vmNumbersDisplayFormat === 'integer' ||
settings.vmNumbersDisplayFormat === 'bigint'
) {
- return { hex, type: 'number' as const, label: `${number}` };
+ return { hex, type: 'number' as const, label: elideDigits(`${number}`) };
}
if (settings.vmNumbersDisplayFormat === 'binary') {
return {
hex,
type: 'binary' as const,
- label: `0b${binToBinString(item)}`,
+ label: elideDigits(`0b${binToBinString(item)}`),
};
}
}
- return { hex, type: 'hex' as const, label: hex };
+ return { hex, type: 'hex' as const, label: elideHex(hex) };
};
// TODO: modernize
@@ -378,7 +389,7 @@ const EvaluationLine = ({
);
return stackItem(
itemIndex,
- hex,
+ elideHex(hex),
{settings.abbreviateLongStackItems
? abbreviateStackItem(label)
@@ -654,7 +665,7 @@ export const ViewerControls = ({
) : evaluationViewerSettings.vmNumbersDisplayFormat === 'bigint' ? (
diff --git a/src/editor/script-editor/ScriptEditor.css b/src/editor/script-editor/ScriptEditor.css
index 6ab656a..a1cfe47 100644
--- a/src/editor/script-editor/ScriptEditor.css
+++ b/src/editor/script-editor/ScriptEditor.css
@@ -47,16 +47,15 @@
.script-tag {
font-size: 0.7em;
- background-color: #2e7105;
border-radius: 3px;
display: inline-block;
padding: 0.1em 0.5em;
margin-left: 1em;
}
- .p2sh-tag {
+ .locking-type-tag {
text-transform: uppercase;
- background-color: #2e7105;
+ background-color: var(--editor-background-color);
}
.pushed-tag {
diff --git a/src/editor/script-editor/ScriptEditor.tsx b/src/editor/script-editor/ScriptEditor.tsx
index be8e853..0e5c628 100644
--- a/src/editor/script-editor/ScriptEditor.tsx
+++ b/src/editor/script-editor/ScriptEditor.tsx
@@ -3,6 +3,8 @@ import { MonacoMarkerDataRequired } from '../../cash-assembly/editor-tooling';
import { ActionCreators } from '../../state/reducer';
import {
IDESupportedProgramState,
+ LockingType,
+ lockingTypeDescriptions,
ScriptDetails,
VariableDetails,
} from '../../state/types';
@@ -202,7 +204,7 @@ const updateMarkers =
export const ScriptEditor = (props: {
frame: ScriptEditorFrame;
- isP2SH: boolean;
+ lockingType: LockingType;
isPushed: boolean;
scriptDetails: ScriptDetails;
variableDetails: VariableDetails;
@@ -803,12 +805,26 @@ export const ScriptEditor = (props: {
{name}
{scriptType === 'test-setup' && (Setup)}
{scriptType === 'test-check' && (Check)}
- {props.isP2SH && (
+ {props.lockingType === 'p2sh20' ? (
- P2SH
+ P2SH20
+
+ ) : props.lockingType === 'p2sh32' ? (
+
+ P2SH32
+
+ ) : (
+
+ bare
)}
{props.isPushed && scriptType === 'tested' && (
@@ -870,7 +886,7 @@ export const ScriptEditor = (props: {
id={id}
name={name}
scriptType={scriptType}
- isP2SH={props.isP2SH}
+ lockingType={props.lockingType}
isPushed={props.isPushed}
closeDialog={() => {
setEditScriptDialogIsOpen(false);
diff --git a/src/header/HeaderBar.tsx b/src/header/HeaderBar.tsx
index 93481ba..4a83b68 100644
--- a/src/header/HeaderBar.tsx
+++ b/src/header/HeaderBar.tsx
@@ -47,8 +47,8 @@ const ideModes: IDESupportedModes[] = [
const vms: IDESupportedVirtualMachine[] = [
{ id: 'BCH_2023_05', name: 'BCH 2023 VM', disabled: false },
- // { id: 'BCH_2025_05', name: 'BCH 2025 VM', disabled: false },
- // { id: 'BCH_2026_05', name: 'BCH 2026 VM', disabled: false },
+ { id: 'BCH_2025_05', name: 'BCH 2025 VM', disabled: false },
+ { id: 'BCH_2026_05', name: 'BCH 2026 VM', disabled: false },
{ id: 'BCH_SPEC', name: 'BCH SPEC VM', disabled: false },
{ id: 'BTC_2017_08', name: 'BTC 2017 VM', disabled: true },
{ id: 'BSV_2020_02', name: 'BSV 2020 VM', disabled: true },
diff --git a/src/state/defaults.ts b/src/state/defaults.ts
index 8574d2d..e0e9d63 100644
--- a/src/state/defaults.ts
+++ b/src/state/defaults.ts
@@ -15,7 +15,12 @@ export const emptyTemplate: WalletTemplate = {
name: 'Untitled',
entities: {},
scripts: {},
- supported: ['BCH_2023_05', 'BCH_SPEC'] as IDESupportedVM[],
+ supported: [
+ 'BCH_2023_05',
+ 'BCH_2025_05',
+ 'BCH_2026_05',
+ 'BCH_SPEC',
+ ] as IDESupportedVM[],
version: 0 as const,
};
diff --git a/src/state/reducer.ts b/src/state/reducer.ts
index 5b89d67..02ca9ea 100644
--- a/src/state/reducer.ts
+++ b/src/state/reducer.ts
@@ -527,7 +527,7 @@ class App extends ImmerReducer {
) {
this.draftState.currentVmId = firstSupportedVm;
this.draftState.evaluationViewerSettings.supportBigInt =
- firstSupportedVm === 'BCH_SPEC';
+ firstSupportedVm !== 'BCH_2023_05';
}
this.draftState.templateLoadTime = new Date();
this.draftState.currentTemplate = template;
@@ -559,7 +559,8 @@ class App extends ImmerReducer {
}
activateVm(vm: IDESupportedVM) {
this.draftState.currentVmId = vm;
- this.draftState.evaluationViewerSettings.supportBigInt = vm === 'BCH_SPEC';
+ this.draftState.evaluationViewerSettings.supportBigInt =
+ vm !== 'BCH_2023_05';
}
}
diff --git a/src/state/types.ts b/src/state/types.ts
index 38d54c6..2232ce6 100644
--- a/src/state/types.ts
+++ b/src/state/types.ts
@@ -115,6 +115,47 @@ export type ScenarioDetails = {
export type ScriptType = BaseScriptType | 'tested' | 'test-check';
+export const scriptTypes: { label: string; value: ScriptType }[] = [
+ { label: 'Locking Script', value: 'locking' },
+ { label: 'Unlocking Script', value: 'unlocking' },
+ { label: 'Isolated Script', value: 'isolated' },
+ { label: 'Script Test', value: 'test-setup' },
+];
+
+export const typeDescriptions: { [key in ScriptType]: string } = {
+ locking:
+ 'Locking scripts hold funds. A locking script is the “challenge” which must be unlocked to spend a transaction output. An “Address” is simply an abstraction for a specific locking script.',
+ unlocking:
+ 'An unlocking script spends from a locking script. To create a transaction, the spender must provide a valid unlocking script for each input being spent. (A locking script can be unlocked by multiple unlocking scripts.)',
+ isolated:
+ 'An isolated script is useful for constructions like checksums or re-usable utility scripts (which can be used inside other scripts). Isolated scripts can have script tests, e.g. utility scripts can be tested to ensure they perform a series of operations properly.',
+ 'test-setup':
+ 'A script test is applied to an isolated script. Each script test has a “setup” phase which is evaluated before the tested script, and a “check” phase which is evaluated after. The test passes if the “check” script leaves a single Script Number 1 on the stack.',
+ tested:
+ 'Something is broken: tested scripts should be created by assigning a test-setup script to an isolated script.',
+ 'test-check':
+ 'Something is broken: script tests should use the `test-setup` type in this dialog.',
+};
+
+export type LockingType = WalletTemplateScriptLocking['lockingType'];
+
+export const lockingTypes: { label: string; value: LockingType }[] = [
+ { label: 'P2SH20', value: 'p2sh20' },
+ { label: 'P2SH32', value: 'p2sh32' },
+ { label: 'Bare (non-P2SH)', value: 'standard' },
+];
+
+export const lockingTypeDescriptions: {
+ [key in LockingType]: string;
+} = {
+ p2sh20:
+ 'This is a P2SH20 script: P2SH20-wrapping bytecode is automatically included during compilation.',
+ p2sh32:
+ 'This is a P2SH32 script. The P2SH32-wrapping bytecode is automatically included during compilation.',
+ standard:
+ 'This is a bare (non-P2SH) script: it is compiled directly into the transaction output without P2SH-wrapping bytecode.',
+};
+
export type BaseScriptType =
| 'locking'
| 'unlocking'