Title: Function Definition and Invocation Operations
Type: Standards
Layer: Consensus
Maintainer: Jason Dreyzehner
Initial Publication Date: 2024-12-12
Latest Revision Date: 2025-09-05
Version: 2.0.2 (26e22566)
Status: Frozen for Lock-In
This proposal introduces the OP_DEFINE and OP_INVOKE opcodes, enabling Bitcoin Cash contract bytecode to be factored into reusable functions.
-
Reduced transaction sizes – By eliminating duplicated bytecode, contract lengths can be optimized for a wider variety of use cases: finite field arithmetic, pairing-based cryptography, zero-knowledge proof systems, homomorphic encryption, post-quantum cryptography, and other important applications for the future security and competitiveness of Bitcoin Cash.
-
Stronger privacy and operational security – By enabling contract designs which leak less information about security measures, current assets, and transaction history, this proposal strengthens privacy and operational security for a variety of use cases.
-
Improved auditability – Without reusable functions, contracts are forced to unnecessarily duplicate significant logic. This proposal enables contracts to be written using more succinct, auditable patterns.
Deployment of this specification is proposed for the May 2026 upgrade.
- Activation is proposed for
1763208000MTP, (2025-11-15T12:00:00.000Z) onchipnet. - Activation is proposed for
1778846400MTP, (2026-05-15T12:00:00.000Z) on the BCH network (mainnet),testnet3,testnet4, andscalenet.
The virtual machine is modified to add a Function Table of immutable functions, the OP_DEFINE opcode is defined at codepoint 0x89 (137), and the OP_INVOKE opcode is defined at 0x8a (138).
The virtual machine (VM) is modified to add a new data structure: the Function Table is a map that holds immutable byte vectors; it maps each defined function identifier to an immutable function body (the byte vector).
Due to VM limits, the function table does not exceed Maximum Memory Slots in defined function count, and the function table's held byte vectors do not exceed the Stack Element Length Limit.
A Defined Function Count counter is added to track the count of defined functions.
A function identifier – the function's key in the function table – is a byte string of length 0 to 7 (inclusive).
The existing cumulative stack and altstack depth limit (A.K.A. MAX_STACK_SIZE; 1000 items) is modified to incorporate Defined Function Count: the sum of stack depth, alternate stack depth, and Defined Function Count must be less than Maximum Memory Slots, set to 1000.
While unusual, it is possible to design pre-signed transactions, contract systems, and protocols which rely on the rejection of otherwise-valid transactions made invalid only by specifically exceeding one or more current VM limits. This proposal interprets such failure-reliant constructions as intentional – the constructions are designed to fail unless/until a possible future network upgrade in which such limits are increased, e.g. upgrade-activation futures contracts. Contract authors are advised that future upgrades may raise VM limits by increasing Maximum Memory Slots, or otherwise. See Limits CHIP Rationale: Inclusion of "Notice of Possible Future Expansion".
Prior to each phase of evaluation (unlocking bytecode, locking bytecode, and redeem bytecode), the Function Table and Defined Function Count must be reset to an empty table and 0, respectively.
<function_body> <function_identifier> OP_DEFINE
The OP_DEFINE opcode is defined at codepoint 0x89 (137) with the following behavior:
- Pop the top item from the stack to interpret as a function identifier (a binary string of length
0to7, inclusive).1 - Pop the next item from the stack to interpret as the function body2, and copy it to the function table at the key equal to the function identifier. If that function key is already defined, error.3
- Increment
Defined Function Countby one.4
- If the stack is empty (no
function_identifier), error. If the length of the popped item is outside of the range0to7(inclusive), error. See Rationale: Use of Stack-Based Parameters and Rationale: Format of Function Identifiers. - if the stack is empty (no
function_body), error. Note that any stack item is a valid function body (including empty stack items); implementations must not attempt to parse the function body until invoked byOP_INVOKE. See Rationale: Deferred Parsing of Function Bodies. - See Rationale: Immutability of Function Bodies. Note also that function identifiers/table keys may be defined in any order. See Rationale: Support for Skipping Function Identifiers.
- Note that the Operation Cost of
OP_DEFINEis equal to the Base Instruction Cost plus the Stack-Pushed Bytes cost for the function body.
<function_identifier> OP_INVOKE
The OP_INVOKE opcode is defined at codepoint 0x8a (138) with the following behavior:
- Pop the top item from the stack to interpret as a function identifier.1
- Preserve the active bytecode (A.K.A.
script), instruction pointer (A.K.A. program counter orpc), and index of the last executed code separator (A.K.A.pbegincodehash) by pushing them to the top of the control stack.2 (Note that this subjects function invocations to the existing control stack depth limit of100.) - Reset the instruction pointer and last executed code separator, then execute the function body as if it were the active bytecode.3 If the bytecode is malformed (i.e. a push operation requires more bytes than are available in the remaining segment of bytecode to be parsed), error.
- When the evaluation is complete4, restore the original bytecode, instruction pointer, and last executed code separator, then continue evaluation after the OP_INVOKE instruction.5
- If the stack is empty (no
function_identifier), error. If the popped item is not a VM Number representing a previously-defined function in the function table, error. If the referenced function body has a length of zero: error if the control stack depth limit of100would be exceeded by a non-empty evaluation; otherwise, continue after theOP_INVOKEinstruction. - Note that this requires the control stack to be capable of holding a new stack frame data type to preserve the state of the parent evaluation.
OP_INVOKEed bytecode otherwise shares the context of the parent evaluation:- Invoked functions may modify the stack, alternate stack, and function table. Note that invoked functions are subject to the following limits:
- Control stack usage (e.g.
OP_IF/OP_END_IFand/or furtherOP_INVOKEs) within the evaluation remains restricted by the 100-item depth limit (cumulatively applied to all nested function calls). - Stack depth + alternate stack depth + Defined Function Count must be no larger than Maximum Memory Slots (formerly:
MAX_STACK_SIZE), which is currently1000.
- Control stack usage (e.g.
- Executed
OP_CODESEPARATORoperations record the index of the current instruction pointer (A.K.A.pc) within theOP_INVOKEed bytecode as the last executed code separator (A.K.A.pbegincodehash). - The
OP_ACTIVEBYTECODEoperation produces the serialization of the active bytecode beginning from the last executed code separator. - In signature operations, the covered bytecode includes only the active bytecode beginning from the last executed code separator (or if none have been executed in the current evaluation, the full active bytecode).
- Invoked functions may modify the stack, alternate stack, and function table. Note that invoked functions are subject to the following limits:
- For an
OP_INVOKEevaluation to complete successfully, the top element remaining on the control stack must be a stack frame to resume after the evaluation. (E.g. Validation fails if anOP_IFwithin the evaluation is not resolved by a matchingOP_ENDIFwithin the same evaluation.) - After an active bytecode has been fully evaluated, the next stack frame is resumed (restoring its bytecode, instruction pointer, and last executed code separator values) until all stack frames are complete (the control stack is empty) or the evaluation has produced some error. Note that two or more
OP_INVOKEoperations may be resolved within the same virtual machine step (e.g. if a childOP_INVOKEis the final instruction of a parentOP_INVOKEevaluation). Note that the Operation Cost ofOP_INVOKEis equal to the Base Instruction Cost.
- Appendix: Rationale →
- Simple, Statically-Applicable Contract Length Optimizations
- Immutability of Function Bodies
- Deferred Parsing of Function Bodies
- Use of Stack-Based Parameters
- Use of Positive Integer-Based Function Identifiers
- Support for Skipping Function Identifiers
- Opcode Naming:
OP_DEFINEandOP_INVOKE - Preservation of Alternate Stack
- Preservation of
OP_CODESEPARATORSupport - Non-Impact on Performance or Static Analysis
- Appendix: Evaluations of Alternatives →
- Appendix: Risk Assessment →
This proposal includes a suite of functional tests and benchmarks to verify the performance of all operations within virtual machine implementations.
Please see the following implementations for examples and additional test vectors:
- C++:
- Bitcoin Cash Node (BCHN) – A professional, miner-friendly node that solves practical problems for Bitcoin Cash. Merge Request !1937.
- JavaScript/TypeScript:
- Libauth – An ultra-lightweight, zero-dependency JavaScript library for Bitcoin Cash. Branch
next. - Bitauth IDE – An online IDE for bitcoin (cash) contracts. Branch
next.
- Libauth – An ultra-lightweight, zero-dependency JavaScript library for Bitcoin Cash. Branch
- Functions CHIP Issues
CHIP-2025-05 Functions: Function Definition and Invocation Operations- Bitcoin Cash Research
This section summarizes the evolution of this proposal.
- v2.0.2 – 2025-09-05 (
26e22566– diff vs.master)- Add Rationale: Non-Impact on Code Mutability or Code Injection
- Review Alternative: CHIP-2025-08 Functions (Takes 2 & 3)
- Update VMB tests and benchmarks
- v2.0.1 – 2025-08-30 (
55704fae) - v2.0.0 – 2025-05-27 (
ed45ff15)- Split
OP_EVALintoOP_DEFINEandOP_INVOKE
- Split
- v1.0.1 – 2025-05-02 (
f551b3de)- Clarify description (#1)
- Add Rationale
- Add Evaluation of Alternatives
- Add Risk Assessment
- Commit latest test vectors
- Link to BCHN implementation
- v1.0.0 – 2024-12-12 (
e2aa5e28)- Initial publication
This document is placed in the public domain.