Skip to content

Commit

Permalink
support for OP_PUSHNUM_X (aka "minimal push codes") and OP_1NEGATE
Browse files Browse the repository at this point in the history
Thanks to @arik-so for pointing this out!

see ordinals/ord#2497
see also ordinals/ord#2505
  • Loading branch information
hans-crypto committed Jan 8, 2024
1 parent 53a9f51 commit 94512f4
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 13 deletions.
16 changes: 11 additions & 5 deletions src/inscription-parser.service.helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,17 @@ export const OP_FALSE = 0x00;
export const OP_IF = 0x63;
export const OP_0 = 0x00;

export const OP_PUSHBYTES_3 = 0x03; // not an actual opcode, but used in documentation --> pushes the next 3 bytes onto the stack.
export const OP_PUSHDATA1 = 0x4c; // The next byte contains the number of bytes to be pushed onto the stack.
export const OP_PUSHDATA2 = 0x4d; // The next two bytes contain the number of bytes to be pushed onto the stack in little endian order.
export const OP_PUSHDATA4 = 0x4e; // The next four bytes contain the number of bytes to be pushed onto the stack in little endian order.
export const OP_ENDIF = 0x68; // Ends an if/else block.
export const OP_PUSHBYTES_3 = 0x03; // 3 -- not an actual opcode, but used in documentation --> pushes the next 3 bytes onto the stack.
export const OP_PUSHDATA1 = 0x4c; // 76 -- The next byte contains the number of bytes to be pushed onto the stack.
export const OP_PUSHDATA2 = 0x4d; // 77 -- The next two bytes contain the number of bytes to be pushed onto the stack in little endian order.
export const OP_PUSHDATA4 = 0x4e; // 78 -- The next four bytes contain the number of bytes to be pushed onto the stack in little endian order.
export const OP_ENDIF = 0x68; // 104 -- Ends an if/else block.

export const OP_1NEGATE = 0x4f; // 79 -- The number -1 is pushed onto the stack.
export const OP_RESERVED = 0x50; // 80 -- Transaction is invalid unless occuring in an unexecuted OP_IF branch
export const OP_PUSHNUM_1 = 0x51; // 81 -- also known as OP_1
// OP_PUSHNUM_2 to OP_PUSHNUM_15 would be here
export const OP_PUSHNUM_16 = 0x60; // 96 -- also known as OP_16

/**
* Inscriptions may include fields before an optional body. Each field consists of two data pushes, a tag and a value.
Expand Down
26 changes: 18 additions & 8 deletions src/lib/reader.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { OP_PUSHDATA1, OP_PUSHDATA2, OP_PUSHDATA4 } from "../inscription-parser.service.helper";
import { OP_1NEGATE, OP_PUSHDATA1, OP_PUSHDATA2, OP_PUSHDATA4, OP_PUSHNUM_1, OP_PUSHNUM_16, OP_RESERVED } from "../inscription-parser.service.helper";

import { littleEndianBytesToNumber } from "./conversions";

Expand All @@ -17,9 +17,7 @@ export function readBytes(raw: Uint8Array, pointer: number, n: number): [Uint8Ar

/**
* Reads data based on the Bitcoin script push opcode starting from a specified pointer in the raw data.
*
* This function handles different opcodes (OP_PUSHDATA1, OP_PUSHDATA2, OP_PUSHDATA4)
* and the direct push (where the opcode itself signifies the number of bytes to push).
* Handles different opcodes and direct push (where the opcode itself signifies the number of bytes to push).
*
* @param raw - The raw transaction data as a Uint8Array.
* @param pointer - The current position in the raw data array.
Expand All @@ -30,10 +28,22 @@ export function readPushdata(raw: Uint8Array, pointer: number): [Uint8Array, num
let [opcodeSlice, newPointer] = readBytes(raw, pointer, 1);
const opcode = opcodeSlice[0];

// Opcodes from 0x01 to 0x4b (decimal values 1 to 75) are special opcodes that indicate a data push is happening.
// Specifically, they indicate the number of bytes to be pushed onto the stack.
// This checks if the current opcode represents a direct data push of 1 to 75 bytes.
// If this condition is true, then read the next opcode number of bytes and treat them as data
// Handle the special case of OP_1NEGATE (-1)
if (opcode === OP_1NEGATE) {
// OP_1NEGATE pushes the value -1 onto the stack, represented as 0x81 in Bitcoin Script
return [new Uint8Array([0x81]), newPointer];
}

// Handle minimal push numbers OP_PUSHNUM_1 (0x51) to OP_PUSHNUM_16 (0x60)
// which are used to push the values 0x01 (decimal 1) through 0x10 (decimal 16) onto the stack.
// To get the value, we can subtract OP_RESERVED (0x50) from the opcode to get the value to be pushed.
if (opcode >= OP_PUSHNUM_1 && opcode <= OP_PUSHNUM_16) {
// Convert opcode to corresponding byte value
const byteValue = opcode - OP_RESERVED;
return [Uint8Array.from([byteValue]), newPointer];
}

// Handle direct push of 1 to 75 bytes (OP_PUSHBYTES_1 to OP_PUSHBYTES_75)
if (1 <= opcode && opcode <= 75) {
return readBytes(raw, newPointer, opcode);
}
Expand Down

0 comments on commit 94512f4

Please sign in to comment.