diff --git a/.changeset/tidy-pandas-shout.md b/.changeset/tidy-pandas-shout.md new file mode 100644 index 00000000..2a64e215 --- /dev/null +++ b/.changeset/tidy-pandas-shout.md @@ -0,0 +1,5 @@ +--- +'@bitauth/libauth': minor +--- + +Add BCH_2027 VM with OP_SIGHASH (CHIP-2026-06) diff --git a/src/lib/compiler/standard/p2pkh.ts b/src/lib/compiler/standard/p2pkh.ts index a865a7be..15f849d3 100644 --- a/src/lib/compiler/standard/p2pkh.ts +++ b/src/lib/compiler/standard/p2pkh.ts @@ -51,6 +51,7 @@ export const walletTemplateP2pkhNonHd: WalletTemplate = { 'BCH_2024_05', 'BCH_2025_05', 'BCH_2026_05', + 'BCH_2027_05', 'BCH_SPEC', ], }; @@ -106,6 +107,7 @@ export const walletTemplateP2pkh: WalletTemplate = { 'BCH_2024_05', 'BCH_2025_05', 'BCH_2026_05', + 'BCH_2027_05', 'BCH_SPEC', ], }; diff --git a/src/lib/transaction/fixtures/template.2-of-3.spec.helper.ts b/src/lib/transaction/fixtures/template.2-of-3.spec.helper.ts index 467260bf..be119e9d 100644 --- a/src/lib/transaction/fixtures/template.2-of-3.spec.helper.ts +++ b/src/lib/transaction/fixtures/template.2-of-3.spec.helper.ts @@ -56,5 +56,6 @@ export const twoOfThree: WalletTemplate = { 'BCH_2024_05', 'BCH_2025_05', 'BCH_2026_05', + 'BCH_2027_05', ], }; diff --git a/src/lib/vm/instruction-sets/bch/2027/bch-2027-consensus.ts b/src/lib/vm/instruction-sets/bch/2027/bch-2027-consensus.ts new file mode 100644 index 00000000..f150262c --- /dev/null +++ b/src/lib/vm/instruction-sets/bch/2027/bch-2027-consensus.ts @@ -0,0 +1,16 @@ +import { ConsensusBch2026 } from '../2026/bch-2026-consensus.js'; + +/** + * Consensus setting overrides for the `BCH_2027_05` instruction set. + */ +// eslint-disable-next-line @typescript-eslint/naming-convention +export const ConsensusBch2027Overrides = {}; + +/** + * Consensus settings for the `BCH_2027_05` instruction set. + */ +// eslint-disable-next-line @typescript-eslint/naming-convention +export const ConsensusBch2027 = { + ...ConsensusBch2026, + ...ConsensusBch2027Overrides, +}; diff --git a/src/lib/vm/instruction-sets/bch/2027/bch-2027-descriptions.ts b/src/lib/vm/instruction-sets/bch/2027/bch-2027-descriptions.ts new file mode 100644 index 00000000..3a0b9c6a --- /dev/null +++ b/src/lib/vm/instruction-sets/bch/2027/bch-2027-descriptions.ts @@ -0,0 +1,18 @@ +import { OpcodeDescriptionsBch2026 } from '../2026/bch-2026-descriptions.js'; + +/** + * Descriptions for the opcodes added to the `BCH_2027_05` instruction set + * beyond those present in `BCH_2026_05`. + */ +export enum OpcodeDescriptionsBch2027Additions { + OP_SIGHASH = 'Pop the top item from the stack as a sighash type (signing serialization type). Push the 32-byte sighash digest (a single SHA256 of the signing serialization) to the stack. The sighash preimage computation is identical to that of OP_CHECKSIG (including the same valid sighash types and scriptCode conventions).', +} + +/** + * Descriptions for the `BCH_2027_05` instruction set. + */ +// eslint-disable-next-line @typescript-eslint/naming-convention +export const OpcodeDescriptionsBch2027 = { + ...OpcodeDescriptionsBch2026, + ...OpcodeDescriptionsBch2027Additions, +}; diff --git a/src/lib/vm/instruction-sets/bch/2027/bch-2027-errors.ts b/src/lib/vm/instruction-sets/bch/2027/bch-2027-errors.ts new file mode 100644 index 00000000..e1d11abd --- /dev/null +++ b/src/lib/vm/instruction-sets/bch/2027/bch-2027-errors.ts @@ -0,0 +1,14 @@ +import { AuthenticationErrorBch2026 } from '../2026/bch-2026-errors.js'; + +export enum AuthenticationErrorBch2027Additions { + invalidSighashType = 'Program attempted an OP_SIGHASH operation with an invalid sighash type.', +} + +/** + * Errors for the `BCH_2027_05` instruction set. + */ +// eslint-disable-next-line @typescript-eslint/naming-convention +export const AuthenticationErrorBch2027 = { + ...AuthenticationErrorBch2026, + ...AuthenticationErrorBch2027Additions, +}; diff --git a/src/lib/vm/instruction-sets/bch/2027/bch-2027-instruction-set.ts b/src/lib/vm/instruction-sets/bch/2027/bch-2027-instruction-set.ts new file mode 100644 index 00000000..0e503bae --- /dev/null +++ b/src/lib/vm/instruction-sets/bch/2027/bch-2027-instruction-set.ts @@ -0,0 +1,90 @@ +import { + ripemd160 as internalRipemd160, + secp256k1 as internalSecp256k1, + sha1 as internalSha1, + sha256 as internalSha256, +} from '../../../../crypto/crypto.js'; +import type { + AuthenticationProgramBch, + AuthenticationProgramStateBch2027, + InstructionSet, + ResolvedTransactionBch, + Ripemd160, + Secp256k1, + Sha1, + Sha256, +} from '../../../../lib.js'; +import { conditionallyEvaluate } from '../../common/common.js'; +import { createInstructionSetBch2026 } from '../2026/bch-2026-instruction-set.js'; + +import { ConsensusBch2027 } from './bch-2027-consensus.js'; +import { OpcodesBch2027 } from './bch-2027-opcodes.js'; +import { opSighash } from './bch-2027-sighash.js'; + +/** + * Initialize a virtual machine using the `BCH_2027_05` instruction set. + * + * @param standard - If `true`, the additional `isStandard` validations will be + * enabled. Transactions that fail these rules are often called "non-standard" + * and can technically be included by miners in valid blocks, but most network + * nodes will refuse to relay them. (Default: `true`) + */ +export const createInstructionSetBch2027 = < + AuthenticationProgramState extends AuthenticationProgramStateBch2027, + Consensus extends typeof ConsensusBch2027 = typeof ConsensusBch2027, +>( + standard = true, + { + consensus = ConsensusBch2027 as Consensus, + ripemd160, + secp256k1, + sha1, + sha256, + }: { + consensus?: Consensus; + /** + * a Ripemd160 implementation + */ + ripemd160: { hash: Ripemd160['hash'] }; + /** + * a Secp256k1 implementation + */ + secp256k1: { + verifySignatureSchnorr: Secp256k1['verifySignatureSchnorr']; + verifySignatureDERLowS: Secp256k1['verifySignatureDERLowS']; + }; + /** + * a Sha1 implementation + */ + sha1: { hash: Sha1['hash'] }; + /** + * a Sha256 implementation + */ + sha256: { hash: Sha256['hash'] }; + } = { + ripemd160: internalRipemd160, + secp256k1: internalSecp256k1, + sha1: internalSha1, + sha256: internalSha256, + }, +): InstructionSet< + ResolvedTransactionBch, + AuthenticationProgramBch, + AuthenticationProgramState +> => { + const instructionSet = + createInstructionSetBch2026(standard, { + consensus, + ripemd160, + secp256k1, + sha1, + sha256, + }); + return { + ...instructionSet, + operations: { + ...instructionSet.operations, + [OpcodesBch2027.OP_SIGHASH]: conditionallyEvaluate(opSighash({ sha256 })), + }, + }; +}; diff --git a/src/lib/vm/instruction-sets/bch/2027/bch-2027-opcodes.ts b/src/lib/vm/instruction-sets/bch/2027/bch-2027-opcodes.ts new file mode 100644 index 00000000..af4ccad4 --- /dev/null +++ b/src/lib/vm/instruction-sets/bch/2027/bch-2027-opcodes.ts @@ -0,0 +1,28 @@ +import { OpcodesBch2026 } from '../2026/bch-2026-opcodes.js'; + +/** + * The opcodes added to the `BCH_2027_05` instruction set beyond those present + * in `BCH_2026_05`. + */ +export enum OpcodesBch2027Additions { + /** + * Formerly `OP_UNKNOWN189` + * + * See CHIP-2026-06 OP_SIGHASH: + * https://gitlab.com/0353F40E/sighash + */ + OP_SIGHASH = 0xbd, +} + +/** + * The `BCH_2027_05` instruction set. + * + * Note: to maximize script compilation compatibility, this instruction set + * also includes the previous names for new opcodes (e.g. `OP_UNKNOWN189` for + * `OP_SIGHASH`). + */ +// eslint-disable-next-line @typescript-eslint/naming-convention +export const OpcodesBch2027 = { + ...OpcodesBch2026, + ...OpcodesBch2027Additions, +}; diff --git a/src/lib/vm/instruction-sets/bch/2027/bch-2027-sighash.ts b/src/lib/vm/instruction-sets/bch/2027/bch-2027-sighash.ts new file mode 100644 index 00000000..717177e1 --- /dev/null +++ b/src/lib/vm/instruction-sets/bch/2027/bch-2027-sighash.ts @@ -0,0 +1,76 @@ +import { sha256 as internalSha256 } from '../../../../crypto/crypto.js'; +import { binToHex } from '../../../../format/format.js'; +import type { + AuthenticationProgramStateCommon, + Sha256, +} from '../../../../lib.js'; +import { + applyError, + encodeAuthenticationInstructions, + lengthToHashDigestIterationCount, + pushToStack, + useOneStackItem, +} from '../../common/common.js'; +import { SigningSerializationTypesBch } from '../../common/consensus.js'; +import { generateSigningSerializationBch } from '../../common/signing-serialization.js'; + +import { AuthenticationErrorBch2027 } from './bch-2027-errors.js'; + +/** + * The `OP_SIGHASH` operation (CHIP-2026-06 OP_SIGHASH). + * + * This is the first half of `OP_CHECKSIG`: pop one byte from the stack as the + * sighash type, compute the sighash preimage exactly as `OP_CHECKSIG` would, + * and push the resulting 32-byte sighash digest to the stack. + * + * The one difference from `OP_CHECKSIG` is the final hash: a single SHA256 + * instead of a double SHA256 (`hash256`), so the result drops straight into + * `OP_CHECKDATASIG` (which hashes the message once before verifying). + * + * Note, unlike `OP_CHECKSIG` and `OP_CHECKDATASIG`, `OP_SIGHASH` does not + * verify a signature, so it does not increment `signatureCheckCount`. Like + * `OP_CHECKSIG` internally, the worst-case hashing cost of the preimage + * computation is always charged to `hashDigestIterations`, even when a cached + * digest can be returned. + * + * See CHIP-2026-06 OP_SIGHASH: https://gitlab.com/0353F40E/sighash + */ +export const opSighash = + ( + { sha256 }: { sha256: { hash: Sha256['hash'] } } = { + sha256: internalSha256, + }, + ): ((state: State) => State) => + (state: State) => + useOneStackItem(state, (nextState, [sighashType]) => { + if ( + sighashType.length !== 1 || + !SigningSerializationTypesBch.includes( + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + sighashType[0]!, + ) + ) { + return applyError( + nextState, + AuthenticationErrorBch2027.invalidSighashType, + `Valid sighash types: [${SigningSerializationTypesBch.map( + (type) => `0x${binToHex(Uint8Array.of(type))}`, + ).join(', ')}].`, + ); + } + const coveredBytecode = encodeAuthenticationInstructions( + nextState.instructions.slice(nextState.lastCodeSeparator + 1), + ); + const signingSerializationType = sighashType; + const serialization = generateSigningSerializationBch( + nextState.program, + { coveredBytecode, signingSerializationType }, + sha256, + ); + const digest = sha256.hash(serialization); + /* eslint-disable functional/no-expression-statements, functional/immutable-data */ + nextState.metrics.hashDigestIterations += + lengthToHashDigestIterationCount(serialization.length); + /* eslint-enable functional/no-expression-statements, functional/immutable-data */ + return pushToStack(nextState, [digest], { pushedBytes: 32 }); + }); diff --git a/src/lib/vm/instruction-sets/bch/2027/bch-2027-types.ts b/src/lib/vm/instruction-sets/bch/2027/bch-2027-types.ts new file mode 100644 index 00000000..76b7dabe --- /dev/null +++ b/src/lib/vm/instruction-sets/bch/2027/bch-2027-types.ts @@ -0,0 +1,15 @@ +import type { + AuthenticationProgramBch, + AuthenticationProgramStateBch2026, + AuthenticationVirtualMachine, + ResolvedTransactionBch, +} from '../../../../lib.js'; + +export type AuthenticationProgramStateBch2027 = + AuthenticationProgramStateBch2026; + +export type AuthenticationVirtualMachineBch2027 = AuthenticationVirtualMachine< + ResolvedTransactionBch, + AuthenticationProgramBch, + AuthenticationProgramStateBch2027 +>; diff --git a/src/lib/vm/instruction-sets/bch/2027/bch-2027-vm.ts b/src/lib/vm/instruction-sets/bch/2027/bch-2027-vm.ts new file mode 100644 index 00000000..1acf9890 --- /dev/null +++ b/src/lib/vm/instruction-sets/bch/2027/bch-2027-vm.ts @@ -0,0 +1,14 @@ +import { createVirtualMachine } from '../../../virtual-machine.js'; + +import { createInstructionSetBch2027 } from './bch-2027-instruction-set.js'; + +/** + * Initialize a virtual machine using the `BCH_2027_05` instruction set. + * + * @param standard - If `true`, the additional `isStandard` validations will be + * enabled. Transactions that fail these rules are often called "non-standard" + * and can technically be included by miners in valid blocks, but most network + * nodes will refuse to relay them. (Default: `true`) + */ +export const createVirtualMachineBch2027 = (standard = true) => + createVirtualMachine(createInstructionSetBch2027(standard)); diff --git a/src/lib/vm/instruction-sets/bch/2027/bch-2027.spec.ts b/src/lib/vm/instruction-sets/bch/2027/bch-2027.spec.ts new file mode 100644 index 00000000..4e58592e --- /dev/null +++ b/src/lib/vm/instruction-sets/bch/2027/bch-2027.spec.ts @@ -0,0 +1,105 @@ +import test from 'ava'; + +import type { AuthenticationProgramBch } from '../../../../lib.js'; +import { + AuthenticationErrorBch2027, + createInstructionSetBch2023, + createInstructionSetBch2027, + createVirtualMachineBch2027, + disassembleBytecodeBch, + generateSigningSerializationBch, + hexToBin, + OpcodesBch2023, + OpcodesBch2027, + sha256, +} from '../../../../lib.js'; + +const programWithBytecode = ( + lockingBytecode: Uint8Array, + unlockingBytecode: Uint8Array, +): AuthenticationProgramBch => ({ + inputIndex: 0, + sourceOutputs: [{ lockingBytecode, token: undefined, valueSatoshis: 1000n }], + transaction: { + inputs: [ + { + outpointIndex: 0, + outpointTransactionHash: new Uint8Array(32).fill(1), + sequenceNumber: 0xffffffff, + unlockingBytecode, + }, + ], + locktime: 0, + outputs: [ + { + lockingBytecode: hexToBin('51'), + token: undefined, + valueSatoshis: 900n, + }, + ], + version: 2, + }, +}); + +test('BCH_2027_05: OP_SIGHASH is assigned to 0xbd (formerly OP_UNKNOWN189)', (t) => { + t.is(OpcodesBch2027.OP_SIGHASH, 0xbd); + t.is(OpcodesBch2023.OP_UNKNOWN189, 0xbd); + t.is(OpcodesBch2027.OP_UNKNOWN189, 0xbd); + t.true( + createInstructionSetBch2027().operations[0xbd] !== undefined && + createInstructionSetBch2023().operations[0xbd] !== + createInstructionSetBch2027().operations[0xbd], + ); +}); + +test('BCH_2027_05: OP_SIGHASH pushes the single-SHA256 sighash digest', (t) => { + const vm = createVirtualMachineBch2027(false); + // `<0x41> OP_SIGHASH`: push sighash type 0x41, compute digest + const program = programWithBytecode(hexToBin('0141bd'), new Uint8Array()); + const result = vm.evaluate(program); + t.is(result.error, undefined); + const expected = sha256.hash( + generateSigningSerializationBch(program, { + coveredBytecode: hexToBin('0141bd'), + signingSerializationType: Uint8Array.of(0x41), + }), + ); + t.deepEqual(result.stack.at(-1), expected); + const top = result.stack.at(-1); + t.true(top instanceof Uint8Array && top.length === 32); +}); + +test('BCH_2027_05: OP_SIGHASH rejects invalid sighash types', (t) => { + const vm = createVirtualMachineBch2027(false); + // `OP_1 OP_SIGHASH`: 0x01 lacks SIGHASH_FORKID, must fail + const program = programWithBytecode(hexToBin('51bd'), new Uint8Array()); + const result = vm.evaluate(program); + t.true( + typeof result.error === 'string' && + result.error.includes(AuthenticationErrorBch2027.invalidSighashType), + ); +}); + +test('BCH_2027_05: OP_SIGHASH requires exactly one sighash-type byte', (t) => { + const vm = createVirtualMachineBch2027(false); + const emptyResult = vm.evaluate( + programWithBytecode(hexToBin('00bd'), new Uint8Array()), + ); + t.true( + typeof emptyResult.error === 'string' && + emptyResult.error.includes(AuthenticationErrorBch2027.invalidSighashType), + ); + const twoByteResult = vm.evaluate( + programWithBytecode(hexToBin('024141bd'), new Uint8Array()), + ); + t.true( + typeof twoByteResult.error === 'string' && + twoByteResult.error.includes( + AuthenticationErrorBch2027.invalidSighashType, + ), + ); +}); + +test('BCH_2027_05: disassembly uses OP_SIGHASH', (t) => { + t.is(disassembleBytecodeBch(hexToBin('bd')), 'OP_SIGHASH'); +}); diff --git a/src/lib/vm/instruction-sets/bch/2027/bch-2027.ts b/src/lib/vm/instruction-sets/bch/2027/bch-2027.ts new file mode 100644 index 00000000..fecd8b15 --- /dev/null +++ b/src/lib/vm/instruction-sets/bch/2027/bch-2027.ts @@ -0,0 +1,8 @@ +export * from './bch-2027-consensus.js'; +export * from './bch-2027-descriptions.js'; +export * from './bch-2027-errors.js'; +export * from './bch-2027-instruction-set.js'; +export * from './bch-2027-opcodes.js'; +export * from './bch-2027-sighash.js'; +export * from './bch-2027-types.js'; +export * from './bch-2027-vm.js'; diff --git a/src/lib/vm/instruction-sets/bch/2027/readme.md b/src/lib/vm/instruction-sets/bch/2027/readme.md new file mode 100644 index 00000000..9db6244a --- /dev/null +++ b/src/lib/vm/instruction-sets/bch/2027/readme.md @@ -0,0 +1,5 @@ +# `BCH_2027_05` Virtual Machine + +This draft version of the Bitcoin Cash Virtual Machine integrates proposals that might activate on mainnet on May 15, 2027. + +Beyond `BCH_2026_05`, this VM adds a single opcode, `OP_SIGHASH` (CHIP-2026-06 OP_SIGHASH). diff --git a/src/lib/vm/instruction-sets/bch/bch.ts b/src/lib/vm/instruction-sets/bch/bch.ts index 07e1be72..2104bfd2 100644 --- a/src/lib/vm/instruction-sets/bch/bch.ts +++ b/src/lib/vm/instruction-sets/bch/bch.ts @@ -17,6 +17,7 @@ import { export * from './2023/bch-2023.js'; export * from './2025/bch-2025.js'; export * from './2026/bch-2026.js'; +export * from './2027/bch-2027.js'; export * from './spec/bch-spec.js'; export const createVirtualMachineBch = createVirtualMachineBch2023; diff --git a/src/lib/vm/instruction-sets/bch/spec/bch-spec-consensus.ts b/src/lib/vm/instruction-sets/bch/spec/bch-spec-consensus.ts index ab9e7a2f..2e1c532c 100644 --- a/src/lib/vm/instruction-sets/bch/spec/bch-spec-consensus.ts +++ b/src/lib/vm/instruction-sets/bch/spec/bch-spec-consensus.ts @@ -1,4 +1,4 @@ -import { ConsensusBch2026 } from '../2026/bch-2026-consensus.js'; +import { ConsensusBch2027 } from '../2027/bch-2027-consensus.js'; /** * Consensus setting overrides for the `BCH_SPEC` instruction set. @@ -23,6 +23,6 @@ export const ConsensusBchSpecOverrides = { */ // eslint-disable-next-line @typescript-eslint/naming-convention export const ConsensusBchSpec = { - ...ConsensusBch2026, + ...ConsensusBch2027, ...ConsensusBchSpecOverrides, }; diff --git a/src/lib/vm/instruction-sets/bch/spec/bch-spec-descriptions.ts b/src/lib/vm/instruction-sets/bch/spec/bch-spec-descriptions.ts index c7a25eb3..7b5670ee 100644 --- a/src/lib/vm/instruction-sets/bch/spec/bch-spec-descriptions.ts +++ b/src/lib/vm/instruction-sets/bch/spec/bch-spec-descriptions.ts @@ -1,8 +1,8 @@ -import { OpcodeDescriptionsBch2026 } from '../2026/bch-2026-descriptions.js'; +import { OpcodeDescriptionsBch2027 } from '../2027/bch-2027-descriptions.js'; /** * Descriptions for the opcodes added to the `BCH_SPEC` instruction set beyond - * those present in `BCH_2026_05`. + * those present in `BCH_2027_05`. */ export enum OpcodeDescriptionsBchSpecAdditions { OP_EVAL = 'Pop the top item from the stack as bytecode. Preserve the active bytecode at the top of the control stack, then evaluate the stack-provided bytecode as if it were the active bytecode (without modifying the stack, alternate stack, or evaluation limits). When the evaluation is complete, restore the original bytecode and continue evaluation after the OP_EVAL instruction. If the bytecode is malformed, error. (Note: OP_EVAL is only available for experimentation in the Libauth BCH_SPEC VM, it is not currently proposed for BCH consensus upgrade.)', @@ -14,6 +14,6 @@ export enum OpcodeDescriptionsBchSpecAdditions { */ // eslint-disable-next-line @typescript-eslint/naming-convention export const OpcodeDescriptionsBchSpec = { - ...OpcodeDescriptionsBch2026, + ...OpcodeDescriptionsBch2027, ...OpcodeDescriptionsBchSpecAdditions, }; diff --git a/src/lib/vm/instruction-sets/bch/spec/bch-spec-errors.ts b/src/lib/vm/instruction-sets/bch/spec/bch-spec-errors.ts index a2b22c33..533ebf94 100644 --- a/src/lib/vm/instruction-sets/bch/spec/bch-spec-errors.ts +++ b/src/lib/vm/instruction-sets/bch/spec/bch-spec-errors.ts @@ -1,4 +1,4 @@ -import { AuthenticationErrorBch2026 } from '../2026/bch-2026-errors.js'; +import { AuthenticationErrorBch2027 } from '../2027/bch-2027-errors.js'; export enum AuthenticationErrorBchSpecAdditions { excessiveOperationCostOpPow = 'Program attempted an OP_POW operation that would have exceed the operation cost density limit.', @@ -10,6 +10,6 @@ export enum AuthenticationErrorBchSpecAdditions { */ // eslint-disable-next-line @typescript-eslint/naming-convention export const AuthenticationErrorBchSpec = { - ...AuthenticationErrorBch2026, + ...AuthenticationErrorBch2027, ...AuthenticationErrorBchSpecAdditions, }; diff --git a/src/lib/vm/instruction-sets/bch/spec/bch-spec-eval.ts b/src/lib/vm/instruction-sets/bch/spec/bch-spec-eval.ts index f19fbc96..2a461c4a 100644 --- a/src/lib/vm/instruction-sets/bch/spec/bch-spec-eval.ts +++ b/src/lib/vm/instruction-sets/bch/spec/bch-spec-eval.ts @@ -1,6 +1,6 @@ import type { AuthenticationInstructionMalformed, - AuthenticationProgramStateBch2026, + AuthenticationProgramStateBch2027, } from '../../../../lib.js'; import { applyError, @@ -15,7 +15,7 @@ import { import { AuthenticationErrorBchSpec } from './bch-spec-errors.js'; import { OpcodesBchSpec } from './bch-spec-opcodes.js'; -export const opEval = ( +export const opEval = ( state: State, ) => { if (executionIsActive(state)) { diff --git a/src/lib/vm/instruction-sets/bch/spec/bch-spec-instruction-set.ts b/src/lib/vm/instruction-sets/bch/spec/bch-spec-instruction-set.ts index 33544bcf..bcc03dc4 100644 --- a/src/lib/vm/instruction-sets/bch/spec/bch-spec-instruction-set.ts +++ b/src/lib/vm/instruction-sets/bch/spec/bch-spec-instruction-set.ts @@ -18,7 +18,7 @@ import { conditionallyEvaluate, incrementOperationCount, } from '../../common/common.js'; -import { createInstructionSetBch2026 } from '../2026/bch-2026-instruction-set.js'; +import { createInstructionSetBch2027 } from '../2027/bch-2027-instruction-set.js'; import { ConsensusBchSpec } from './bch-spec-consensus.js'; import { opEval } from './bch-spec-eval.js'; @@ -79,7 +79,7 @@ export const createInstructionSetBchSpec = < AuthenticationProgramState > => { const instructionSet = - createInstructionSetBch2026(standard, { + createInstructionSetBch2027(standard, { consensus, ripemd160, secp256k1, diff --git a/src/lib/vm/instruction-sets/bch/spec/bch-spec-opcodes.ts b/src/lib/vm/instruction-sets/bch/spec/bch-spec-opcodes.ts index bb5e4812..53894fa0 100644 --- a/src/lib/vm/instruction-sets/bch/spec/bch-spec-opcodes.ts +++ b/src/lib/vm/instruction-sets/bch/spec/bch-spec-opcodes.ts @@ -1,8 +1,8 @@ -import { OpcodesBch2026 } from '../2026/bch-2026-opcodes.js'; +import { OpcodesBch2027 } from '../2027/bch-2027-opcodes.js'; /** * The opcodes added to the `BCH_SPEC` instruction set beyond those present in - * `BCH_2026_05`. + * `BCH_2027_05`. * * These opcodes are exposed for testing and not currently expected to become * part of a known upgrade. `BCH_SPEC` opcodes may be removed or modified by @@ -26,4 +26,4 @@ export enum OpcodesBchSpecAdditions { * includes the previous names for new opcodes (e.g. `OP_VERIF` for `OP_BEGIN`). */ // eslint-disable-next-line @typescript-eslint/naming-convention -export const OpcodesBchSpec = { ...OpcodesBch2026, ...OpcodesBchSpecAdditions }; +export const OpcodesBchSpec = { ...OpcodesBch2027, ...OpcodesBchSpecAdditions }; diff --git a/src/lib/vm/instruction-sets/bch/spec/bch-spec-types.ts b/src/lib/vm/instruction-sets/bch/spec/bch-spec-types.ts index 935d3936..5f7126da 100644 --- a/src/lib/vm/instruction-sets/bch/spec/bch-spec-types.ts +++ b/src/lib/vm/instruction-sets/bch/spec/bch-spec-types.ts @@ -1,6 +1,6 @@ import type { AuthenticationProgramBch, - AuthenticationProgramStateBch2026, + AuthenticationProgramStateBch2027, AuthenticationVirtualMachine, ResolvedTransactionBch, } from '../../../../lib.js'; @@ -18,7 +18,7 @@ export type AuthenticationProgramStateResourceLimitsBchSpec = { }; export type AuthenticationProgramStateBchSpec = - AuthenticationProgramStateBch2026 & + AuthenticationProgramStateBch2027 & AuthenticationProgramStateResourceLimitsBchSpec; export type AuthenticationVirtualMachineBchSpec = AuthenticationVirtualMachine< diff --git a/src/lib/vmb-tests/bch-vmb-test-utils.spec.ts b/src/lib/vmb-tests/bch-vmb-test-utils.spec.ts index 8cae4ff7..7ce35083 100644 --- a/src/lib/vmb-tests/bch-vmb-test-utils.spec.ts +++ b/src/lib/vmb-tests/bch-vmb-test-utils.spec.ts @@ -31,7 +31,12 @@ test('vmbTestGroupToVmbTests', (t) => { 'OP_SIZE <0> OP_EQUAL', '020000000201000000000000000000000000000000000000000000000000000000000000000000000064417dfb529d352908ee0a88a0074c216b09793d6aa8c94c7640bb4ced51eaefc75d0aef61f7685d0307491e2628da3d4f91e86329265a4a58ca27a41ec0b8910779c32103a524f43d6166ad3567f18b0a5c769c6ab4dc02149f4d5095ccf4e8ffa293e785000000000100000000000000000000000000000000000000000000000000000000000000010000000100000000000100000000000000000a6a08766d625f7465737400000000', '0210270000000000001976a91460011c6bf3f1dd98cff576437b9d85de780f497488ac102700000000000003820087', - ['2023_nonstandard', '2025_nonstandard', '2026_standard'], + [ + '2023_nonstandard', + '2025_nonstandard', + '2026_standard', + '2027_standard', + ], 1, ], [ @@ -41,7 +46,7 @@ test('vmbTestGroupToVmbTests', (t) => { 'OP_SIZE <0> OP_EQUAL', '020000000201000000000000000000000000000000000000000000000000000000000000000000000064417dfb529d352908ee0a88a0074c216b09793d6aa8c94c7640bb4ced51eaefc75d0aef61f7685d0307491e2628da3d4f91e86329265a4a58ca27a41ec0b8910779c32103a524f43d6166ad3567f18b0a5c769c6ab4dc02149f4d5095ccf4e8ffa293e78500000000010000000000000000000000000000000000000000000000000000000000000001000000050003820087000000000100000000000000000a6a08766d625f7465737400000000', '0210270000000000001976a91460011c6bf3f1dd98cff576437b9d85de780f497488ac102700000000000017a9146b14122b4b3cb280c9ec66f8e2827cf3384010a387', - ['2023_standard', '2025_standard', '2026_standard'], + ['2023_standard', '2025_standard', '2026_standard', '2027_standard'], 1, ], [ @@ -51,7 +56,7 @@ test('vmbTestGroupToVmbTests', (t) => { 'OP_SIZE <0> OP_EQUAL', '020000000201000000000000000000000000000000000000000000000000000000000000000000000064417dfb529d352908ee0a88a0074c216b09793d6aa8c94c7640bb4ced51eaefc75d0aef61f7685d0307491e2628da3d4f91e86329265a4a58ca27a41ec0b8910779c32103a524f43d6166ad3567f18b0a5c769c6ab4dc02149f4d5095ccf4e8ffa293e78500000000010000000000000000000000000000000000000000000000000000000000000001000000050003820087000000000100000000000000000a6a08766d625f7465737400000000', '0210270000000000001976a91460011c6bf3f1dd98cff576437b9d85de780f497488ac102700000000000023aa2058f29d1d690dc5a8e34ade0a6a3a18356b09b491d3d7e8bc7b2ea3ee2f471ce387', - ['2023_standard', '2025_standard', '2026_standard'], + ['2023_standard', '2025_standard', '2026_standard', '2027_standard'], 1, ], ], @@ -63,7 +68,7 @@ test('vmbTestGroupToVmbTests', (t) => { 'OP_SIZE <1> OP_EQUAL', '020000000201000000000000000000000000000000000000000000000000000000000000000000000064417dfb529d352908ee0a88a0074c216b09793d6aa8c94c7640bb4ced51eaefc75d0aef61f7685d0307491e2628da3d4f91e86329265a4a58ca27a41ec0b8910779c32103a524f43d6166ad3567f18b0a5c769c6ab4dc02149f4d5095ccf4e8ffa293e785000000000100000000000000000000000000000000000000000000000000000000000000010000000101000000000100000000000000000a6a08766d625f7465737400000000', '0210270000000000001976a91460011c6bf3f1dd98cff576437b9d85de780f497488ac102700000000000003825187', - ['2023_invalid', '2025_invalid', '2026_invalid'], + ['2023_invalid', '2025_invalid', '2026_invalid', '2027_invalid'], 1, ], ], diff --git a/src/lib/vmb-tests/bch-vmb-test-utils.ts b/src/lib/vmb-tests/bch-vmb-test-utils.ts index 7b9fc2ac..d18ae646 100644 --- a/src/lib/vmb-tests/bch-vmb-test-utils.ts +++ b/src/lib/vmb-tests/bch-vmb-test-utils.ts @@ -28,6 +28,7 @@ const vmVersionsBch = [ '2023', '2025', '2026', + '2027', 'spec', 'chip_eval', 'chip_bitwise', @@ -157,6 +158,7 @@ const testSetOverrideListBch = [ ['2023_p2sh_invalid'], ['2023_p2sh_nonstandard', '2025_p2sh_nonstandard'], ['2025_invalid'], + ['2026_invalid'], ['chip_bitwise'], ['chip_bitwise', 'p2s_invalid'], ['chip_bitwise', 'p2s_nonstandard'], @@ -234,13 +236,25 @@ const baseP2s = [ '2023_nonstandard', '2025_nonstandard', '2026_standard', + '2027_standard', +] as const; +const standard = [ + '2023_standard', + '2025_standard', + '2026_standard', + '2027_standard', +] as const; +const invalid = [ + '2023_invalid', + '2025_invalid', + '2026_invalid', + '2027_invalid', ] as const; -const standard = ['2023_standard', '2025_standard', '2026_standard'] as const; -const invalid = ['2023_invalid', '2025_invalid', '2026_invalid'] as const; const nonstandard = [ '2023_nonstandard', '2025_nonstandard', '2026_nonstandard', + '2027_nonstandard', ] as const; type TestPlan = { @@ -266,110 +280,164 @@ export const supportedTestSetOverridesBch: { '2023_invalid': [ { mode: 'P2S', - sets: ['2023_invalid', '2025_nonstandard', '2026_standard'], + sets: [ + '2023_invalid', + '2025_nonstandard', + '2026_standard', + '2027_standard', + ], }, { mode: 'P2SH20', - sets: ['2023_invalid', '2025_standard', '2026_standard'], + sets: ['2023_invalid', '2025_standard', '2026_standard', '2027_standard'], }, { mode: 'P2SH32', - sets: ['2023_invalid', '2025_standard', '2026_standard'], + sets: ['2023_invalid', '2025_standard', '2026_standard', '2027_standard'], }, ], '2023_invalid,2025_invalid': [ { mode: 'P2S', - sets: ['2023_invalid', '2025_invalid', '2026_standard'], + sets: ['2023_invalid', '2025_invalid', '2026_standard', '2027_standard'], }, { mode: 'P2SH20', - sets: ['2023_invalid', '2025_invalid', '2026_standard'], + sets: ['2023_invalid', '2025_invalid', '2026_standard', '2027_standard'], }, { mode: 'P2SH32', - sets: ['2023_invalid', '2025_invalid', '2026_standard'], + sets: ['2023_invalid', '2025_invalid', '2026_standard', '2027_standard'], }, ], '2023_invalid,2025_p2sh_nonstandard': [ { mode: 'P2S', - sets: ['2023_invalid', '2025_nonstandard', '2026_standard'], + sets: [ + '2023_invalid', + '2025_nonstandard', + '2026_standard', + '2027_standard', + ], }, { mode: 'P2SH20', - sets: ['2023_invalid', '2025_nonstandard', '2026_standard'], + sets: [ + '2023_invalid', + '2025_nonstandard', + '2026_standard', + '2027_standard', + ], }, { mode: 'P2SH32', - sets: ['2023_invalid', '2025_nonstandard', '2026_standard'], + sets: [ + '2023_invalid', + '2025_nonstandard', + '2026_standard', + '2027_standard', + ], }, ], '2023_invalid,p2s_ignore': [ { mode: 'P2SH20', - sets: ['2023_invalid', '2025_standard', '2026_standard'], + sets: ['2023_invalid', '2025_standard', '2026_standard', '2027_standard'], }, { mode: 'P2SH32', - sets: ['2023_invalid', '2025_standard', '2026_standard'], + sets: ['2023_invalid', '2025_standard', '2026_standard', '2027_standard'], }, ], '2023_invalid,p2s_ignore,p2sh20_ignore': [ { mode: 'P2SH32', - sets: ['2023_invalid', '2025_standard', '2026_standard'], + sets: ['2023_invalid', '2025_standard', '2026_standard', '2027_standard'], }, ], '2023_invalid,p2s_ignore,p2sh32_ignore': [ { mode: 'P2SH20', - sets: ['2023_invalid', '2025_standard', '2026_standard'], + sets: ['2023_invalid', '2025_standard', '2026_standard', '2027_standard'], }, ], '2023_invalid,p2sh_ignore': [ { mode: 'P2S', - sets: ['2023_invalid', '2025_nonstandard', '2026_standard'], + sets: [ + '2023_invalid', + '2025_nonstandard', + '2026_standard', + '2027_standard', + ], }, ], '2023_p2sh_invalid': [ { mode: 'P2S', sets: baseP2s }, { mode: 'P2SH20', - sets: ['2023_invalid', '2025_standard', '2026_standard'], + sets: ['2023_invalid', '2025_standard', '2026_standard', '2027_standard'], }, { mode: 'P2SH32', - sets: ['2023_invalid', '2025_standard', '2026_standard'], + sets: ['2023_invalid', '2025_standard', '2026_standard', '2027_standard'], }, ], '2023_p2sh_nonstandard,2025_p2sh_nonstandard': [ { mode: 'P2S', - sets: ['2023_nonstandard', '2025_nonstandard', '2026_standard'], + sets: [ + '2023_nonstandard', + '2025_nonstandard', + '2026_standard', + '2027_standard', + ], }, { mode: 'P2SH20', - sets: ['2023_nonstandard', '2025_nonstandard', '2026_standard'], + sets: [ + '2023_nonstandard', + '2025_nonstandard', + '2026_standard', + '2027_standard', + ], }, { mode: 'P2SH32', - sets: ['2023_nonstandard', '2025_nonstandard', '2026_standard'], + sets: [ + '2023_nonstandard', + '2025_nonstandard', + '2026_standard', + '2027_standard', + ], }, ], '2025_invalid': [ { mode: 'P2S', - sets: ['2023_invalid', '2025_invalid', '2026_standard'], + sets: ['2023_invalid', '2025_invalid', '2026_standard', '2027_standard'], }, { mode: 'P2SH20', - sets: ['2023_invalid', '2025_invalid', '2026_standard'], + sets: ['2023_invalid', '2025_invalid', '2026_standard', '2027_standard'], }, { mode: 'P2SH32', - sets: ['2023_invalid', '2025_invalid', '2026_standard'], + sets: ['2023_invalid', '2025_invalid', '2026_standard', '2027_standard'], + }, + ], + '2026_invalid': [ + { + mode: 'P2S', + sets: ['2023_invalid', '2025_invalid', '2026_invalid', '2027_standard'], + }, + { + mode: 'P2SH20', + sets: ['2023_invalid', '2025_invalid', '2026_invalid', '2027_standard'], + }, + { + mode: 'P2SH32', + sets: ['2023_invalid', '2025_invalid', '2026_invalid', '2027_standard'], }, ], /** @@ -379,70 +447,140 @@ export const supportedTestSetOverridesBch: { chip_bitwise: [ { mode: 'P2S', - sets: ['chip_bitwise_standard', '2025_invalid', '2026_standard'], + sets: [ + 'chip_bitwise_standard', + '2025_invalid', + '2026_standard', + '2027_standard', + ], }, { mode: 'P2SH20', - sets: ['chip_bitwise_standard', '2025_invalid', '2026_standard'], + sets: [ + 'chip_bitwise_standard', + '2025_invalid', + '2026_standard', + '2027_standard', + ], }, { mode: 'P2SH32', - sets: ['chip_bitwise_standard', '2025_invalid', '2026_standard'], + sets: [ + 'chip_bitwise_standard', + '2025_invalid', + '2026_standard', + '2027_standard', + ], }, ], 'chip_bitwise,p2s_invalid': [ { mode: 'P2S', - sets: ['chip_bitwise_invalid', '2025_invalid', '2026_invalid'], + sets: [ + 'chip_bitwise_invalid', + '2025_invalid', + '2026_invalid', + '2027_invalid', + ], }, { mode: 'P2SH20', - sets: ['chip_bitwise_standard', '2025_invalid', '2026_standard'], + sets: [ + 'chip_bitwise_standard', + '2025_invalid', + '2026_standard', + '2027_standard', + ], }, { mode: 'P2SH32', - sets: ['chip_bitwise_standard', '2025_invalid', '2026_standard'], + sets: [ + 'chip_bitwise_standard', + '2025_invalid', + '2026_standard', + '2027_standard', + ], }, ], 'chip_bitwise,p2s_nonstandard': [ { mode: 'P2S', - sets: ['chip_bitwise_nonstandard', '2025_invalid', '2026_nonstandard'], + sets: [ + 'chip_bitwise_nonstandard', + '2025_invalid', + '2026_nonstandard', + '2027_nonstandard', + ], }, { mode: 'P2SH20', - sets: ['chip_bitwise_standard', '2025_invalid', '2026_standard'], + sets: [ + 'chip_bitwise_standard', + '2025_invalid', + '2026_standard', + '2027_standard', + ], }, { mode: 'P2SH32', - sets: ['chip_bitwise_standard', '2025_invalid', '2026_standard'], + sets: [ + 'chip_bitwise_standard', + '2025_invalid', + '2026_standard', + '2027_standard', + ], }, ], 'chip_bitwise,p2sh_ignore': [ { mode: 'P2S', - sets: ['chip_bitwise_standard', '2025_invalid', '2026_standard'], + sets: [ + 'chip_bitwise_standard', + '2025_invalid', + '2026_standard', + '2027_standard', + ], }, ], chip_bitwise_invalid: [ { mode: 'P2S', - sets: ['chip_bitwise_invalid', '2025_invalid', '2026_invalid'], + sets: [ + 'chip_bitwise_invalid', + '2025_invalid', + '2026_invalid', + '2027_invalid', + ], }, { mode: 'P2SH20', - sets: ['chip_bitwise_invalid', '2025_invalid', '2026_invalid'], + sets: [ + 'chip_bitwise_invalid', + '2025_invalid', + '2026_invalid', + '2027_invalid', + ], }, { mode: 'P2SH32', - sets: ['chip_bitwise_invalid', '2025_invalid', '2026_invalid'], + sets: [ + 'chip_bitwise_invalid', + '2025_invalid', + '2026_invalid', + '2027_invalid', + ], }, ], 'chip_bitwise_invalid,p2sh_ignore': [ { mode: 'P2S', - sets: ['chip_bitwise_invalid', '2025_invalid', '2026_invalid'], + sets: [ + 'chip_bitwise_invalid', + '2025_invalid', + '2026_invalid', + '2027_invalid', + ], }, ], chip_eval: [ @@ -467,120 +605,248 @@ export const supportedTestSetOverridesBch: { chip_functions: [ { mode: 'P2S', - sets: ['chip_functions_standard', '2025_invalid', '2026_standard'], + sets: [ + 'chip_functions_standard', + '2025_invalid', + '2026_standard', + '2027_standard', + ], }, { mode: 'P2SH20', - sets: ['chip_functions_standard', '2025_invalid', '2026_standard'], + sets: [ + 'chip_functions_standard', + '2025_invalid', + '2026_standard', + '2027_standard', + ], }, { mode: 'P2SH32', - sets: ['chip_functions_standard', '2025_invalid', '2026_standard'], + sets: [ + 'chip_functions_standard', + '2025_invalid', + '2026_standard', + '2027_standard', + ], }, ], 'chip_functions,p2sh_ignore': [ { mode: 'P2S', - sets: ['chip_functions_standard', '2025_invalid', '2026_standard'], + sets: [ + 'chip_functions_standard', + '2025_invalid', + '2026_standard', + '2027_standard', + ], }, ], 'chip_functions,p2sh_invalid': [ { mode: 'P2S', - sets: ['chip_functions_standard', '2025_invalid', '2026_standard'], + sets: [ + 'chip_functions_standard', + '2025_invalid', + '2026_standard', + '2027_standard', + ], }, { mode: 'P2SH20', - sets: ['chip_functions_invalid', '2025_invalid', '2026_invalid'], + sets: [ + 'chip_functions_invalid', + '2025_invalid', + '2026_invalid', + '2027_invalid', + ], }, { mode: 'P2SH32', - sets: ['chip_functions_invalid', '2025_invalid', '2026_invalid'], + sets: [ + 'chip_functions_invalid', + '2025_invalid', + '2026_invalid', + '2027_invalid', + ], }, ], chip_functions_invalid: [ { mode: 'P2S', - sets: ['chip_functions_invalid', '2025_invalid', '2026_invalid'], + sets: [ + 'chip_functions_invalid', + '2025_invalid', + '2026_invalid', + '2027_invalid', + ], }, { mode: 'P2SH20', - sets: ['chip_functions_invalid', '2025_invalid', '2026_invalid'], + sets: [ + 'chip_functions_invalid', + '2025_invalid', + '2026_invalid', + '2027_invalid', + ], }, { mode: 'P2SH32', - sets: ['chip_functions_invalid', '2025_invalid', '2026_invalid'], + sets: [ + 'chip_functions_invalid', + '2025_invalid', + '2026_invalid', + '2027_invalid', + ], }, ], 'chip_functions_invalid,p2sh_ignore': [ { mode: 'P2S', - sets: ['chip_functions_invalid', '2025_invalid', '2026_invalid'], + sets: [ + 'chip_functions_invalid', + '2025_invalid', + '2026_invalid', + '2027_invalid', + ], }, ], chip_loops: [ { mode: 'P2S', - sets: ['chip_loops_standard', '2025_invalid', '2026_standard'], + sets: [ + 'chip_loops_standard', + '2025_invalid', + '2026_standard', + '2027_standard', + ], }, { mode: 'P2SH20', - sets: ['chip_loops_standard', '2025_invalid', '2026_standard'], + sets: [ + 'chip_loops_standard', + '2025_invalid', + '2026_standard', + '2027_standard', + ], }, { mode: 'P2SH32', - sets: ['chip_loops_standard', '2025_invalid', '2026_standard'], + sets: [ + 'chip_loops_standard', + '2025_invalid', + '2026_standard', + '2027_standard', + ], }, ], chip_loops_invalid: [ { mode: 'P2S', - sets: ['chip_loops_invalid', '2025_invalid', '2026_invalid'], + sets: [ + 'chip_loops_invalid', + '2025_invalid', + '2026_invalid', + '2027_invalid', + ], }, { mode: 'P2SH20', - sets: ['chip_loops_invalid', '2025_invalid', '2026_invalid'], + sets: [ + 'chip_loops_invalid', + '2025_invalid', + '2026_invalid', + '2027_invalid', + ], }, { mode: 'P2SH32', - sets: ['chip_loops_invalid', '2025_invalid', '2026_invalid'], + sets: [ + 'chip_loops_invalid', + '2025_invalid', + '2026_invalid', + '2027_invalid', + ], }, ], 'chip_loops_invalid,p2sh_ignore': [ { mode: 'P2S', - sets: ['chip_loops_invalid', '2025_invalid', '2026_invalid'], + sets: [ + 'chip_loops_invalid', + '2025_invalid', + '2026_invalid', + '2027_invalid', + ], }, ], chip_p2s: [ { mode: 'P2S', - sets: ['chip_p2s_standard', '2025_invalid', '2026_standard'], + sets: [ + 'chip_p2s_standard', + '2025_invalid', + '2026_standard', + '2027_standard', + ], }, { mode: 'P2SH20', - sets: ['chip_p2s_standard', '2025_invalid', '2026_standard'], + sets: [ + 'chip_p2s_standard', + '2025_invalid', + '2026_standard', + '2027_standard', + ], }, { mode: 'P2SH32', - sets: ['chip_p2s_standard', '2025_invalid', '2026_standard'], + sets: [ + 'chip_p2s_standard', + '2025_invalid', + '2026_standard', + '2027_standard', + ], }, ], 'chip_p2s,p2sh_ignore': [ { mode: 'P2S', - sets: ['chip_p2s_standard', '2025_invalid', '2026_standard'], + sets: [ + 'chip_p2s_standard', + '2025_invalid', + '2026_standard', + '2027_standard', + ], }, ], chip_p2s_invalid: [ - { mode: 'P2S', sets: ['chip_p2s_invalid', '2025_invalid', '2026_invalid'] }, + { + mode: 'P2S', + sets: [ + 'chip_p2s_invalid', + '2025_invalid', + '2026_invalid', + '2027_invalid', + ], + }, { mode: 'P2SH20', - sets: ['chip_p2s_invalid', '2025_invalid', '2026_invalid'], + sets: [ + 'chip_p2s_invalid', + '2025_invalid', + '2026_invalid', + '2027_invalid', + ], }, { mode: 'P2SH32', - sets: ['chip_p2s_invalid', '2025_invalid', '2026_invalid'], + sets: [ + 'chip_p2s_invalid', + '2025_invalid', + '2026_invalid', + '2027_invalid', + ], }, ], chip_pow: [ @@ -599,18 +865,44 @@ export const supportedTestSetOverridesBch: { { mode: 'P2SH32', sets: invalid }, ], 'invalid,2023_nonstandard': [ - { mode: 'P2S', sets: ['2023_nonstandard', '2025_invalid', '2026_invalid'] }, + { + mode: 'P2S', + sets: [ + '2023_nonstandard', + '2025_invalid', + '2026_invalid', + '2027_invalid', + ], + }, { mode: 'P2SH20', - sets: ['2023_nonstandard', '2025_invalid', '2026_invalid'], + sets: [ + '2023_nonstandard', + '2025_invalid', + '2026_invalid', + '2027_invalid', + ], }, { mode: 'P2SH32', - sets: ['2023_nonstandard', '2025_invalid', '2026_invalid'], + sets: [ + '2023_nonstandard', + '2025_invalid', + '2026_invalid', + '2027_invalid', + ], }, ], 'invalid,2023_nonstandard,p2sh_ignore': [ - { mode: 'P2S', sets: ['2023_nonstandard', '2025_invalid', '2026_invalid'] }, + { + mode: 'P2S', + sets: [ + '2023_nonstandard', + '2025_invalid', + '2026_invalid', + '2027_invalid', + ], + }, ], 'invalid,p2s_ignore': [ { mode: 'P2SH20', sets: invalid }, @@ -633,7 +925,15 @@ export const supportedTestSetOverridesBch: { ], 'invalid,p2sh_ignore': [{ mode: 'P2S', sets: invalid }], 'invalid,p2sh_ignore,2023_p2s_nonstandard': [ - { mode: 'P2S', sets: ['2023_nonstandard', '2025_invalid', '2026_invalid'] }, + { + mode: 'P2S', + sets: [ + '2023_nonstandard', + '2025_invalid', + '2026_invalid', + '2027_invalid', + ], + }, ], 'invalid,spec_standard': [ { @@ -657,38 +957,73 @@ export const supportedTestSetOverridesBch: { 'nonstandard,2023_invalid': [ { mode: 'P2S', - sets: ['2023_invalid', '2025_nonstandard', '2026_nonstandard'], + sets: [ + '2023_invalid', + '2025_nonstandard', + '2026_nonstandard', + '2027_nonstandard', + ], }, { mode: 'P2SH20', - sets: ['2023_invalid', '2025_nonstandard', '2026_nonstandard'], + sets: [ + '2023_invalid', + '2025_nonstandard', + '2026_nonstandard', + '2027_nonstandard', + ], }, { mode: 'P2SH32', - sets: ['2023_invalid', '2025_nonstandard', '2026_nonstandard'], + sets: [ + '2023_invalid', + '2025_nonstandard', + '2026_nonstandard', + '2027_nonstandard', + ], }, ], 'nonstandard,2023_invalid,p2sh_ignore': [ { mode: 'P2S', - sets: ['2023_invalid', '2025_nonstandard', '2026_nonstandard'], + sets: [ + '2023_invalid', + '2025_nonstandard', + '2026_nonstandard', + '2027_nonstandard', + ], }, ], 'nonstandard,2023_p2sh_standard,p2s_ignore': [ { mode: 'P2SH20', - sets: ['2023_standard', '2025_nonstandard', '2026_nonstandard'], + sets: [ + '2023_standard', + '2025_nonstandard', + '2026_nonstandard', + '2027_nonstandard', + ], }, { mode: 'P2SH32', - sets: ['2023_standard', '2025_nonstandard', '2026_nonstandard'], + sets: [ + '2023_standard', + '2025_nonstandard', + '2026_nonstandard', + '2027_nonstandard', + ], }, ], 'nonstandard,p2sh_ignore': [{ mode: 'P2S', sets: nonstandard }], 'nonstandard,p2sh_invalid,2023_invalid': [ { mode: 'P2S', - sets: ['2023_invalid', '2025_nonstandard', '2026_nonstandard'], + sets: [ + '2023_invalid', + '2025_nonstandard', + '2026_nonstandard', + '2027_nonstandard', + ], }, { mode: 'P2SH20', sets: invalid }, { mode: 'P2SH32', sets: invalid }, @@ -706,28 +1041,43 @@ export const supportedTestSetOverridesBch: { { mode: 'P2S', sets: invalid }, { mode: 'P2SH20', - sets: ['2023_invalid', '2025_standard', '2026_standard'], + sets: ['2023_invalid', '2025_standard', '2026_standard', '2027_standard'], }, { mode: 'P2SH32', - sets: ['2023_invalid', '2025_standard', '2026_standard'], + sets: ['2023_invalid', '2025_standard', '2026_standard', '2027_standard'], }, ], 'p2s_invalid,2023_invalid,2025_p2sh_nonstandard': [ { mode: 'P2S', sets: invalid }, { mode: 'P2SH20', - sets: ['2023_invalid', '2025_nonstandard', '2026_standard'], + sets: [ + '2023_invalid', + '2025_nonstandard', + '2026_standard', + '2027_standard', + ], }, { mode: 'P2SH32', - sets: ['2023_invalid', '2025_nonstandard', '2026_standard'], + sets: [ + '2023_invalid', + '2025_nonstandard', + '2026_standard', + '2027_standard', + ], }, ], 'p2s_invalid,2023_p2s_nonstandard': [ { mode: 'P2S', - sets: ['2023_nonstandard', '2025_invalid', '2026_invalid'], + sets: [ + '2023_nonstandard', + '2025_invalid', + '2026_invalid', + '2027_invalid', + ], }, { mode: 'P2SH20', sets: standard }, { mode: 'P2SH32', sets: standard }, @@ -735,15 +1085,20 @@ export const supportedTestSetOverridesBch: { 'p2s_invalid,2023_p2s_nonstandard,2023_p2sh_invalid': [ { mode: 'P2S', - sets: ['2023_nonstandard', '2025_invalid', '2026_invalid'], + sets: [ + '2023_nonstandard', + '2025_invalid', + '2026_invalid', + '2027_invalid', + ], }, { mode: 'P2SH20', - sets: ['2023_invalid', '2025_standard', '2026_standard'], + sets: ['2023_invalid', '2025_standard', '2026_standard', '2027_standard'], }, { mode: 'P2SH32', - sets: ['2023_invalid', '2025_standard', '2026_standard'], + sets: ['2023_invalid', '2025_standard', '2026_standard', '2027_standard'], }, ], p2s_nonstandard: [ @@ -754,49 +1109,79 @@ export const supportedTestSetOverridesBch: { 'p2s_nonstandard,2023_invalid': [ { mode: 'P2S', - sets: ['2023_invalid', '2025_nonstandard', '2026_nonstandard'], + sets: [ + '2023_invalid', + '2025_nonstandard', + '2026_nonstandard', + '2027_nonstandard', + ], }, { mode: 'P2SH20', - sets: ['2023_invalid', '2025_standard', '2026_standard'], + sets: ['2023_invalid', '2025_standard', '2026_standard', '2027_standard'], }, { mode: 'P2SH32', - sets: ['2023_invalid', '2025_standard', '2026_standard'], + sets: ['2023_invalid', '2025_standard', '2026_standard', '2027_standard'], }, ], 'p2s_nonstandard,2023_invalid,2025_p2sh_nonstandard': [ { mode: 'P2S', - sets: ['2023_invalid', '2025_nonstandard', '2026_nonstandard'], + sets: [ + '2023_invalid', + '2025_nonstandard', + '2026_nonstandard', + '2027_nonstandard', + ], }, { mode: 'P2SH20', - sets: ['2023_invalid', '2025_nonstandard', '2026_standard'], + sets: [ + '2023_invalid', + '2025_nonstandard', + '2026_standard', + '2027_standard', + ], }, { mode: 'P2SH32', - sets: ['2023_invalid', '2025_nonstandard', '2026_standard'], + sets: [ + '2023_invalid', + '2025_nonstandard', + '2026_standard', + '2027_standard', + ], }, ], 'p2s_nonstandard,2023_invalid,p2sh_ignore': [ { mode: 'P2S', - sets: ['2023_invalid', '2025_nonstandard', '2026_nonstandard'], + sets: [ + '2023_invalid', + '2025_nonstandard', + '2026_nonstandard', + '2027_nonstandard', + ], }, ], 'p2s_nonstandard,2023_p2sh_invalid': [ { mode: 'P2S', - sets: ['2023_nonstandard', '2025_nonstandard', '2026_nonstandard'], + sets: [ + '2023_nonstandard', + '2025_nonstandard', + '2026_nonstandard', + '2027_nonstandard', + ], }, { mode: 'P2SH20', - sets: ['2023_invalid', '2025_standard', '2026_standard'], + sets: ['2023_invalid', '2025_standard', '2026_standard', '2027_standard'], }, { mode: 'P2SH32', - sets: ['2023_invalid', '2025_standard', '2026_standard'], + sets: ['2023_invalid', '2025_standard', '2026_standard', '2027_standard'], }, ], 'p2s_nonstandard,p2sh_ignore': [{ mode: 'P2S', sets: nonstandard }], @@ -808,7 +1193,12 @@ export const supportedTestSetOverridesBch: { 'p2s_nonstandard,p2sh_invalid,2023_invalid': [ { mode: 'P2S', - sets: ['2023_invalid', '2025_nonstandard', '2026_nonstandard'], + sets: [ + '2023_invalid', + '2025_nonstandard', + '2026_nonstandard', + '2027_nonstandard', + ], }, { mode: 'P2SH20', sets: invalid }, { mode: 'P2SH32', sets: invalid }, @@ -844,7 +1234,12 @@ export const supportedTestSetOverridesBch: { 'p2sh_invalid,2023_invalid': [ { mode: 'P2S', - sets: ['2023_invalid', '2025_nonstandard', '2026_standard'], + sets: [ + '2023_invalid', + '2025_nonstandard', + '2026_standard', + '2027_standard', + ], }, { mode: 'P2SH20', sets: invalid }, { mode: 'P2SH32', sets: invalid }, @@ -858,11 +1253,21 @@ export const supportedTestSetOverridesBch: { { mode: 'P2S', sets: invalid }, { mode: 'P2SH20', - sets: ['2023_invalid', '2025_nonstandard', '2026_nonstandard'], + sets: [ + '2023_invalid', + '2025_nonstandard', + '2026_nonstandard', + '2027_nonstandard', + ], }, { mode: 'P2SH32', - sets: ['2023_invalid', '2025_nonstandard', '2026_nonstandard'], + sets: [ + '2023_invalid', + '2025_nonstandard', + '2026_nonstandard', + '2027_nonstandard', + ], }, ], spec: [ diff --git a/src/lib/vmb-tests/bchn/bchn-error-map.spec.helper.ts b/src/lib/vmb-tests/bchn/bchn-error-map.spec.helper.ts index 975d5171..5d76ddeb 100644 --- a/src/lib/vmb-tests/bchn/bchn-error-map.spec.helper.ts +++ b/src/lib/vmb-tests/bchn/bchn-error-map.spec.helper.ts @@ -56,6 +56,7 @@ export const libauthErrorPrefixToBchnErrorStandard: { invalidNaturalNumber: '', invalidPublicKeyEncoding: '', invalidShiftBitCount: '', + invalidSighashType: '', invalidSignatureEncoding: '', invalidSplitIndex: '', invalidStackIndex: '', @@ -187,6 +188,7 @@ export const libauthErrorPrefixToBchnErrorNonstandard: { invalidNaturalNumber: '', invalidPublicKeyEncoding: '', invalidShiftBitCount: '', + invalidSighashType: '', invalidSignatureEncoding: '', invalidSplitIndex: '', invalidStackIndex: '', diff --git a/src/lib/vmb-tests/sources/core.sighash.ts b/src/lib/vmb-tests/sources/core.sighash.ts new file mode 100644 index 00000000..8025a04b --- /dev/null +++ b/src/lib/vmb-tests/sources/core.sighash.ts @@ -0,0 +1,45 @@ +import type { PossibleTestValue, VmbTestDefinitionGroup } from '../../lib.js'; +import { generateTestCases, setExpectedResults } from '../bch-vmb-test-utils.js'; + +const sighashTypes: PossibleTestValue[] = [ + ['all_outputs (0x41)', '0x41'], + ['all_outputs_single_input (0xc1)', '0xc1'], + ['corresponding_output (0x43)', '0x43'], + ['corresponding_output_single_input (0xc3)', '0xc3'], + ['no_outputs (0x42)', '0x42'], + ['no_outputs_single_input (0xc2)', '0xc2'], + ['all_outputs_all_utxos (0x61)', '0x61'], + ['corresponding_output_all_utxos (0x63)', '0x63'], + ['no_outputs_all_utxos (0x62)', '0x62'], +]; + +const invalidSighashTypes: PossibleTestValue[] = [ + ['all_outputs without forkid (0x01)', '0x01'], + ['nonsensical sighash type (0xff)', '0xff'], + ['two bytes (0x4141)', '0x4141'], +]; + +export default [ + [ + 'OP_SIGHASH', + [ + ['', 'OP_SIZE OP_1SUB OP_SPLIT OP_SIGHASH OP_CHECKDATASIG', 'OP_SIGHASH checksig-equivalent: OP_SIGHASH combined with OP_CHECKDATASIG verifies like OP_CHECKSIG', ['2026_invalid']], + ...setExpectedResults(generateTestCases(['<$0>', 'OP_SIGHASH OP_SIZE <32> OP_EQUALVERIFY OP_DROP <1>', 'OP_SIGHASH $0'], [sighashTypes]), { + 'OP_SIGHASH all_outputs (0x41)': ['2026_invalid'], + 'OP_SIGHASH all_outputs_all_utxos (0x61)': ['2026_invalid'], + 'OP_SIGHASH all_outputs_single_input (0xc1)': ['2026_invalid'], + 'OP_SIGHASH corresponding_output (0x43)': ['2026_invalid'], + 'OP_SIGHASH corresponding_output_all_utxos (0x63)': ['2026_invalid'], + 'OP_SIGHASH corresponding_output_single_input (0xc3)': ['2026_invalid'], + 'OP_SIGHASH no_outputs (0x42)': ['2026_invalid'], + 'OP_SIGHASH no_outputs_all_utxos (0x62)': ['2026_invalid'], + 'OP_SIGHASH no_outputs_single_input (0xc2)': ['2026_invalid'], + }), + ...setExpectedResults(generateTestCases(['<$0>', 'OP_SIGHASH', 'OP_SIGHASH invalid $0'], [invalidSighashTypes]), { + 'OP_SIGHASH invalid all_outputs without forkid (0x01)': ['invalid'], + 'OP_SIGHASH invalid nonsensical sighash type (0xff)': ['invalid'], + 'OP_SIGHASH invalid two bytes (0x4141)': ['invalid'], + }), + ], + ], +] as const satisfies VmbTestDefinitionGroup[]; diff --git a/src/lib/vmb-tests/vmb-tests.spec.helper.ts b/src/lib/vmb-tests/vmb-tests.spec.helper.ts index 9c568f70..c9e51819 100644 --- a/src/lib/vmb-tests/vmb-tests.spec.helper.ts +++ b/src/lib/vmb-tests/vmb-tests.spec.helper.ts @@ -2,12 +2,14 @@ import { createVirtualMachineBch2023, createVirtualMachineBch2025, createVirtualMachineBch2026, + createVirtualMachineBch2027, createVirtualMachineBchSpec, } from '../lib.js'; import type { AuthenticationVirtualMachineBch, AuthenticationVirtualMachineBch2025, AuthenticationVirtualMachineBch2026, + AuthenticationVirtualMachineBch2027, AuthenticationVirtualMachineBchSpec, } from '../lib.js'; @@ -18,6 +20,8 @@ export type VmName = | 'bch_2025_standard' | 'bch_2026_nonstandard' | 'bch_2026_standard' + | 'bch_2027_nonstandard' + | 'bch_2027_standard' | 'bch_spec_nonstandard' | 'bch_spec_standard'; @@ -25,6 +29,7 @@ export type TestedVM = | AuthenticationVirtualMachineBch | AuthenticationVirtualMachineBch2025 | AuthenticationVirtualMachineBch2026 + | AuthenticationVirtualMachineBch2027 | AuthenticationVirtualMachineBchSpec; /** @@ -45,6 +50,8 @@ const baseVms = { bch_2025_standard: createVirtualMachineBch2025(true), bch_2026_nonstandard: createVirtualMachineBch2026(false), bch_2026_standard: createVirtualMachineBch2026(true), + bch_2027_nonstandard: createVirtualMachineBch2027(false), + bch_2027_standard: createVirtualMachineBch2027(true), bch_spec_nonstandard: createVirtualMachineBchSpec(false), bch_spec_standard: createVirtualMachineBchSpec(true), };