Skip to content

Commit 35c37df

Browse files
committed
Update BCH_2026 VM and VMB tests
1 parent 0955b4c commit 35c37df

File tree

187 files changed

+61627
-4258
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

187 files changed

+61627
-4258
lines changed

.changeset/strange-paws-decide.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@bitauth/libauth': minor
3+
---
4+
5+
Update BCH_2026 VM and VMB tests

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
"bchn:cmake": "cd wasm/bitcoin-cash-node/build && cmake -GNinja .. -DBUILD_BITCOIN_WALLET=OFF -DBUILD_BITCOIN_QT=OFF -DENABLE_NATPMP=OFF -DENABLE_MAN=OFF -DCMAKE_BUILD_TYPE=Release",
4545
"bchn:build": "cd wasm/bitcoin-cash-node/build && ninja",
4646
"bchn:setup": "cd wasm/bitcoin-cash-node && mkdir build && yarn bchn:cmake && yarn bchn:build",
47+
"bchn:bench": "cd wasm/bitcoin-cash-node/build && ninja && ninja bench_bitcoin && echo 'Running BCHN benchmarks (fast)...' && ./src/bench/bench_bitcoin -libauth -filter=\"^LibAuth_(2025|2026)_.*\"",
48+
"bchn:bench:slow": "cd wasm/bitcoin-cash-node/build && ninja && ninja bench_bitcoin && echo 'Running BCHN benchmarks (slow, ~6-24 hrs)...' && src/bench/bench_bitcoin -libauth=all_slow -filter=\"^LibAuth_(2025|2026)_.*\"",
4749
"bchn:remove-old-vmb-tests": "rm -r wasm/bitcoin-cash-node/src/test/data/vmb_tests/bch_{2023,2025,2026}_{invalid,nonstandard,standard} && echo 'Removed old VMB tests from: wasm/bitcoin-cash-node/src/test/data/vmb_tests'",
4850
"bchn:add-new-vmb-tests": "cp -r src/lib/vmb-tests/generated/bch_{2023,2025,2026}_{invalid,nonstandard,standard} wasm/bitcoin-cash-node/src/test/data/vmb_tests && echo 'Added new VMB tests.'",
4951
"bchn:replace-vmb-tests": "yarn bchn:remove-old-vmb-tests && yarn bchn:add-new-vmb-tests",

src/lib/vm/instruction-sets/bch/2023/bch-2023-instruction-set.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,10 @@ export const createInstructionSetBch2023 = <
298298
},
299299
} as AuthenticationProgramState);
300300

301+
if (lockingResult.error !== undefined) {
302+
return lockingResult;
303+
}
304+
301305
if (lockingResult.controlStack.length !== 0) {
302306
return applyError(
303307
lockingResult,
@@ -419,7 +423,8 @@ export const createInstructionSetBch2023 = <
419423
return {
420424
alternateStack: [],
421425
controlStack: [],
422-
functionTable: [],
426+
functionCount: 0,
427+
functionTable: {},
423428
ip: 0,
424429
lastCodeSeparator: -1,
425430
metrics: {

src/lib/vm/instruction-sets/bch/2026/bch-2026-bitwise.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ export const createOpLShiftNum =
7676
// eslint-disable-next-line no-bitwise
7777
numericValue << bitCount,
7878
{
79-
hasEncodingCost: true,
79+
hasEncodingCost: false,
8080
maximumVmNumberByteLength: maximumStackItemLength,
8181
},
8282
);
@@ -111,7 +111,7 @@ export const createOpRShiftNum =
111111
// eslint-disable-next-line no-bitwise
112112
numericValue >> bitCount,
113113
{
114-
hasEncodingCost: true,
114+
hasEncodingCost: false,
115115
maximumVmNumberByteLength: maximumStackItemLength,
116116
},
117117
);

src/lib/vm/instruction-sets/bch/2026/bch-2026-consensus.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@ import { ConsensusBch2025 } from '../2025/bch-2025-consensus.js';
66
// eslint-disable-next-line @typescript-eslint/naming-convention
77
export const ConsensusBch2026Overrides = {
88
baseInstructionCost: 100,
9-
maximumFunctionIdentifier: 999,
9+
maximumFunctionIdentifierLength: 7,
10+
/**
11+
* A.K.A. `MAX_MEMORY_SLOTS`
12+
*/
13+
maximumMemorySlots: 1000,
1014
maximumStandardLockingBytecodeLength: 201,
1115
maximumStandardUnlockingBytecodeLength: 10000,
1216
maximumTokenCommitmentLength: 128,
13-
minimumFunctionIdentifier: 0,
1417
};
1518

1619
/**

src/lib/vm/instruction-sets/bch/2026/bch-2026-errors.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ export enum AuthenticationErrorBch2026Additions {
44
unexpectedUntil = 'Encountered an OP_UNTIL that is not preceded by a matching OP_BEGIN.',
55
unexpectedUntilMissingEndIf = 'Encountered an OP_UNTIL before the previous OP_IF was closed by an OP_ENDIF.',
66
excessiveLooping = 'Program attempted an OP_UNTIL operation that would exceed the limit of repeated bytes.',
7-
functionIdentifierInvalid = 'Program attempted to OP_DEFINE an invalid function identifier.',
7+
exceededMaximumMemorySlots = 'Program attempted to use an excessive number of memory slots: stack items, alternate stack items, and/or defined functions.',
8+
functionIdentifierExcessiveLength = 'Program attempted to OP_DEFINE a function identifier of excessive length.',
89
functionIdentifierPreviouslyDefined = 'Program attempted to OP_DEFINE a previously-defined function identifier.',
910
functionIdentifierUndefined = 'Program attempted to OP_INVOKE an undefined function identifier.',
1011
malformedFunction = 'Program attempted to OP_INVOKE malformed bytecode.',

src/lib/vm/instruction-sets/bch/2026/bch-2026-functions.ts

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import {
1414
disassembleAuthenticationInstructionMalformed,
1515
pushToControlStack,
1616
useOneStackItem,
17-
useOneVmNumber,
1817
} from '../../common/common.js';
1918

2019
import { ConsensusBch2026 } from './bch-2026-consensus.js';
@@ -23,8 +22,7 @@ import { OpcodesBch2026 } from './bch-2026-opcodes.js';
2322

2423
export const createOpDefine =
2524
({
26-
maximumFunctionIdentifier = ConsensusBch2026.maximumFunctionIdentifier,
27-
minimumFunctionIdentifier = ConsensusBch2026.minimumFunctionIdentifier,
25+
maximumFunctionIdentifierLength = ConsensusBch2026.maximumFunctionIdentifierLength,
2826
} = {}) =>
2927
<
3028
State extends AuthenticationProgramStateError &
@@ -33,30 +31,29 @@ export const createOpDefine =
3331
>(
3432
state: State,
3533
) =>
36-
useOneVmNumber(state, (nextState, [providedInteger]) => {
37-
const functionIdentifier = Number(providedInteger);
38-
if (
39-
functionIdentifier < minimumFunctionIdentifier ||
40-
functionIdentifier > maximumFunctionIdentifier
41-
) {
34+
useOneStackItem(state, (nextState, [functionIdentifier]) => {
35+
const functionTableKey = binToHex(functionIdentifier);
36+
if (functionIdentifier.length > maximumFunctionIdentifierLength) {
4237
return applyError(
4338
nextState,
44-
AuthenticationErrorBch2026.functionIdentifierInvalid,
45-
`Function identifier (${functionIdentifier}) is outside of the valid range: ${minimumFunctionIdentifier} to ${maximumFunctionIdentifier} (inclusive).`,
39+
AuthenticationErrorBch2026.functionIdentifierExcessiveLength,
40+
`Function identifier has excessive length. Maximum length: ${maximumFunctionIdentifierLength}. Provided length: ${functionIdentifier.length}. Provided identifier: 0x${functionTableKey}.`,
4641
);
4742
}
48-
if (nextState.functionTable[functionIdentifier] !== undefined) {
43+
if (nextState.functionTable[functionTableKey] !== undefined) {
4944
return applyError(
5045
nextState,
5146
AuthenticationErrorBch2026.functionIdentifierPreviouslyDefined,
52-
`Function identifier: ${functionIdentifier}. Existing contents: ${binToHex(
53-
nextState.functionTable[functionIdentifier],
47+
`Function identifier: 0x${functionTableKey}. Existing contents: ${binToHex(
48+
nextState.functionTable[functionTableKey],
5449
)}.`,
5550
);
5651
}
5752
return useOneStackItem(nextState, (finalState, [functionBody]) => {
5853
// eslint-disable-next-line functional/no-expression-statements, functional/immutable-data
59-
finalState.functionTable[functionIdentifier] = functionBody;
54+
finalState.functionTable[functionTableKey] = functionBody;
55+
// eslint-disable-next-line functional/no-expression-statements, functional/immutable-data
56+
finalState.functionCount += 1;
6057
return finalState;
6158
});
6259
});
@@ -70,14 +67,14 @@ export const opInvoke = <
7067
>(
7168
state: State,
7269
) =>
73-
useOneVmNumber(state, (nextState, [providedInteger]) => {
74-
const functionTableIndex = Number(providedInteger);
75-
const functionBody = nextState.functionTable[functionTableIndex];
70+
useOneStackItem(state, (nextState, [functionIdentifier]) => {
71+
const functionTableKey = binToHex(functionIdentifier);
72+
const functionBody = nextState.functionTable[functionTableKey];
7673
if (functionBody === undefined) {
7774
return applyError(
7875
nextState,
7976
AuthenticationErrorBch2026.functionIdentifierUndefined,
80-
`Function identifier: ${functionTableIndex}.`,
77+
`Function identifier: 0x${functionTableKey}.`,
8178
);
8279
}
8380
const newInstructions = decodeAuthenticationInstructions(functionBody);

src/lib/vm/instruction-sets/bch/2026/bch-2026-instruction-set.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import type {
1414
Sha1,
1515
Sha256,
1616
} from '../../../../lib.js';
17-
import { conditionallyEvaluate } from '../../common/common.js';
17+
import { applyError, conditionallyEvaluate } from '../../common/common.js';
1818
import { createInstructionSetBch2025 } from '../2025/bch-2025-instruction-set.js';
1919
import { opBegin, opUntil } from '../2026/bch-2026-loops.js';
2020

@@ -26,6 +26,7 @@ import {
2626
opRShiftBin,
2727
} from './bch-2026-bitwise.js';
2828
import { ConsensusBch2026 } from './bch-2026-consensus.js';
29+
import { AuthenticationErrorBch2026 } from './bch-2026-errors.js';
2930
import { createOpDefine, opInvoke } from './bch-2026-functions.js';
3031
import { OpcodesBch2026 } from './bch-2026-opcodes.js';
3132
import type { AuthenticationProgramStateBch2026 } from './bch-2026-types.js';
@@ -105,6 +106,23 @@ export const createInstructionSetBch2026 = <
105106
}
106107
return state.ip < state.instructions.length;
107108
},
109+
every: (state) => {
110+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
111+
const nextState = instructionSet.every!(state);
112+
if (
113+
nextState.stack.length +
114+
nextState.alternateStack.length +
115+
nextState.functionCount >
116+
consensus.maximumMemorySlots
117+
) {
118+
return applyError(
119+
nextState,
120+
AuthenticationErrorBch2026.exceededMaximumMemorySlots,
121+
`Maximum memory slots: ${consensus.maximumMemorySlots}.`,
122+
);
123+
}
124+
return nextState;
125+
},
108126
/* eslint-enable functional/no-loop-statements, functional/immutable-data, functional/no-expression-statements */
109127
operations: {
110128
...instructionSet.operations,

src/lib/vm/vm-types.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,11 @@ export type AuthenticationProgramStateFunctionTable = {
6161
* The table of functions (in Forth parlance, "vocabulary of words") defined
6262
* over the course of the evaluation.
6363
*/
64-
functionTable: Uint8Array[];
64+
functionTable: { [hex: string]: Uint8Array };
65+
/**
66+
* The count of defined functions ("words") in the current evaluation.
67+
*/
68+
functionCount: number;
6569
};
6670

6771
export type AuthenticationProgramStateControlStack<

src/lib/vmb-tests/bch-vmb-test-utils.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,9 @@ const testSetOverrideListBch = [
169169
['chip_eval_invalid'],
170170
['chip_eval_invalid', 'p2sh_ignore'],
171171
['chip_functions'],
172+
['chip_functions', 'p2sh_invalid'],
173+
['chip_functions_invalid'],
174+
['chip_functions_invalid', 'p2sh_ignore'],
172175
['chip_loops_invalid'],
173176
['chip_loops_invalid', 'p2sh_ignore'],
174177
['chip_loops'],
@@ -461,6 +464,60 @@ export const supportedTestSetOverridesBch: {
461464
'chip_eval_invalid,p2sh_ignore': [
462465
{ mode: 'P2S', sets: ['chip_eval_invalid'] },
463466
],
467+
chip_functions: [
468+
{
469+
mode: 'P2S',
470+
sets: ['chip_functions_standard', '2025_invalid', '2026_standard'],
471+
},
472+
{
473+
mode: 'P2SH20',
474+
sets: ['chip_functions_standard', '2025_invalid', '2026_standard'],
475+
},
476+
{
477+
mode: 'P2SH32',
478+
sets: ['chip_functions_standard', '2025_invalid', '2026_standard'],
479+
},
480+
],
481+
'chip_functions,p2sh_ignore': [
482+
{
483+
mode: 'P2S',
484+
sets: ['chip_functions_standard', '2025_invalid', '2026_standard'],
485+
},
486+
],
487+
'chip_functions,p2sh_invalid': [
488+
{
489+
mode: 'P2S',
490+
sets: ['chip_functions_standard', '2025_invalid', '2026_standard'],
491+
},
492+
{
493+
mode: 'P2SH20',
494+
sets: ['chip_functions_invalid', '2025_invalid', '2026_invalid'],
495+
},
496+
{
497+
mode: 'P2SH32',
498+
sets: ['chip_functions_invalid', '2025_invalid', '2026_invalid'],
499+
},
500+
],
501+
chip_functions_invalid: [
502+
{
503+
mode: 'P2S',
504+
sets: ['chip_functions_invalid', '2025_invalid', '2026_invalid'],
505+
},
506+
{
507+
mode: 'P2SH20',
508+
sets: ['chip_functions_invalid', '2025_invalid', '2026_invalid'],
509+
},
510+
{
511+
mode: 'P2SH32',
512+
sets: ['chip_functions_invalid', '2025_invalid', '2026_invalid'],
513+
},
514+
],
515+
'chip_functions_invalid,p2sh_ignore': [
516+
{
517+
mode: 'P2S',
518+
sets: ['chip_functions_invalid', '2025_invalid', '2026_invalid'],
519+
},
520+
],
464521
chip_loops: [
465522
{
466523
mode: 'P2S',

0 commit comments

Comments
 (0)