<p>If we look at <a href="https://en.bitcoin.it/wiki/Transaction#General_format_.28inside_a_block.29_of_each_input_of_a_transaction_-_Txin" rel="nofollow noreferrer">the network format of the input section of a transaction message</a> we see</p>
<blockquote>
<div class="s-table-container"><table class="s-table">
<thead>
<tr>
<th>Field</th>
<th>Description</th>
<th>Size</th>
</tr>
</thead>
<tbody>
<tr>
<td>Previous Transaction hash</td>
<td>doubled SHA256-hashed of a (previous) to-be-used &gt; transaction</td>
<td>32 bytes</td>
</tr>
<tr>
<td>Previous Txout-index</td>
<td>non negative integer indexing an output of the to-&gt; be-used transaction</td>
<td>4 bytes</td>
</tr>
<tr>
<td><strong>Txin-script length</strong></td>
<td><strong>non negative integer VI = VarInt</strong></td>
<td><strong>1 - 9 bytes</strong></td>
</tr>
<tr>
<td>Txin-script / scriptSig</td>
<td>Script</td>
<td>&lt;in-script length&gt;-many bytes</td>
</tr>
<tr>
<td>sequence_no</td>
<td>normally 0xFFFFFFFF; irrelevant unless transaction's lock_time is &gt; 0</td>
<td>4 bytes</td>
</tr>
</tbody>
</table></div>
</blockquote>
<p>So the Txin-script length is of type Varint.</p>
<blockquote>
<p>Variable length integer</p>
<p>Integer can be encoded depending on the represented value to save space. Variable length integers always precede an array/vector of a type of data that may vary in length. Longer numbers are encoded in <strong>little endian</strong>.</p>
<div class="s-table-container"><table class="s-table">
<thead>
<tr>
<th>Value</th>
<th>Storage length</th>
<th>Format</th>
</tr>
</thead>
<tbody>
<tr>
<td>&lt; 0xFD</td>
<td>1</td>
<td>uint8_t</td>
</tr>
<tr>
<td>&lt;= 0xFFFF</td>
<td>3</td>
<td><strong>0xFD followed by the length as uint16_t</strong></td>
</tr>
<tr>
<td>&lt;= 0xFFFF FFFF</td>
<td>5</td>
<td>0xFE followed by the length as uint32_t</td>
</tr>
<tr>
<td>-</td>
<td>9</td>
<td>0xFF followed by the length as uint64_t</td>
</tr>
</tbody>
</table></div>
</blockquote>
<p>(my emphasis)</p>
<p>So for script-lengths longer than 0xfc and less than 0xffff the script-length is represented as a Varint with three bytes, the first byte of which must be 0xfd so that the format can be unambiguously differentiated from other lengths of Varint.</p>
<ul>
<li><p>If the first byte we read is lower than 253 (0xFD) we know the Varint is one byte long and the value we just read is the length of the script.</p>
</li>
<li><p>If the first byte we read is <em>253 (0xFD)</em> we know the Varint is <em>three bytes</em> long and we need to discard this byte and read the <em>next two</em> bytes as the length of the script.</p>
</li>
<li><p>Ditto <em>254 (0xFE), five bytes, next four</em>.</p>
</li>
<li><p>Ditto <em>255 (0xFF), nine bytes, next eight</em>.</p>
</li>
</ul>
<p>So we can't represent a script length of 254 in a one-byte Varint because 254 (0xFE) is a special marker byte-value for a five-byte Varint. Instead of using a one-byte Varint, we have to go to the next size up of Varint - a three-byte Varint, and use it's special marker byte value to prefix a two-byte (Uint16_t) length value.</p>
<p>The <a href="https://en.wikipedia.org/wiki/Endianness" rel="nofollow noreferrer">endianness</a> of the Uint16_t is why the first byte of the last two is the lowest part of the Uint16_t value. 254 is 0x00FE but in little-endian byte-order that is 0xFE00.</p>
<hr />
<p>What this teaches us is that the developers of this network protocol prioritised compactness of message size over clarity and simplicity.</p>
<p>Given the prevalence of other protocols that take the opposite approach to message size (consider SMTP with XML payloads like DOCX etc or HTTP with HTML payloads) it must be debateable whether this was a necessary or good choice. Maybe a simpler, less confusing choice could have been used, optionally wrapped in a compression envelope. But the choice was made and I guess it is one that Bitcoin developers  must live with.</p>

CC BY-SA 4.0
2022-09-27T13:26:39.460Z
@cc1cc1: If RedGrittyBrick answered your question fully, you can accept his answer as the most helpful by clicking the checkmark.
Murch
CC BY-SA 4.0
2022-03-04T12:30:35.033Z
2024-04-17T18:57:07.443Z
2024-04-17T18:57:07.443Z
RedGrittyBrick
<p>I'm looking at some raw txs (P2SH in that case) for learning, and I have one question about a particular tx:
tx hash 0aeae24fa55544da49ba06ec338c9beee592ab4bea71eb8085908f377dd46084, i use this tool for analysis:
<a href="https://hashxp.org/0aeae24fa55544da49ba06ec338c9beee592ab4bea71eb8085908f377dd46084" rel="nofollow noreferrer">https://hashxp.org/0aeae24fa55544da49ba06ec338c9beee592ab4bea71eb8085908f377dd46084</a></p>
<p>I don't understand its script length (<code>fd fe 00</code>). The value is analysed as 254 by the tool. So, why is the script length stored as 3 bytes, but only uses the value of the second byte?</p>
<p>Does anyone know a paper about how to build a standard P2SH tx?</p>

<p2sh><serialization>
Why does a script length of 254 need three bytes?
cc1cc1
# Why does a script length of 254 need three bytes?

(Asked by: username_0 on 2022-03-04)

I'm looking at some raw txs (P2SH in that case) for learning, and I have one question about a particular tx:
tx hash 0aeae24fa55544da49ba06ec338c9beee592ab4bea71eb8085908f377dd46084, i use this tool for analysis:
<https://hashxp.org/0aeae24fa55544da49ba06ec338c9beee592ab4bea71eb8085908f377dd46084>

I don't understand its script length (`fd fe 00`). The value is analysed as 254 by the tool. So, why is the script length stored as 3 bytes, but only uses the value of the second byte?

Does anyone know a paper about how to build a standard P2SH tx?

**Tags:** p2sh, serialization


---

## 1 answers

### Answer by username_1 on 2022-03-04. Score: 4

If we look at [the network format of the input section of a transaction message](https://en.bitcoin.it/wiki/Transaction#General_format_.28inside_a_block.29_of_each_input_of_a_transaction_-_Txin) we see

> | Field | Description | Size |
> | --- | --- | --- |
> | Previous Transaction hash | doubled SHA256-hashed of a (previous) to-be-used > transaction | 32 bytes |
> | Previous Txout-index | non negative integer indexing an output of the to-> be-used transaction | 4 bytes |
> | **Txin-script length** | **non negative integer VI = VarInt** | **1 - 9 bytes** |
> | Txin-script / scriptSig | Script | <in-script length>-many bytes |
> | sequence\_no | normally 0xFFFFFFFF; irrelevant unless transaction's lock\_time is > 0 | 4 bytes |

So the Txin-script length is of type Varint.

> Variable length integer
>
> Integer can be encoded depending on the represented value to save space. Variable length integers always precede an array/vector of a type of data that may vary in length. Longer numbers are encoded in **little endian**.
>
> | Value | Storage length | Format |
> | --- | --- | --- |
> | < 0xFD | 1 | uint8\_t |
> | <= 0xFFFF | 3 | **0xFD followed by the length as uint16\_t** |
> | <= 0xFFFF FFFF | 5 | 0xFE followed by the length as uint32\_t |
> | - | 9 | 0xFF followed by the length as uint64\_t |

(my emphasis)

So for script-lengths longer than 0xfc and less than 0xffff the script-length is represented as a Varint with three bytes, the first byte of which must be 0xfd so that the format can be unambiguously differentiated from other lengths of Varint.

* If the first byte we read is lower than 253 (0xFD) we know the Varint is one byte long and the value we just read is the length of the script.
* If the first byte we read is *253 (0xFD)* we know the Varint is *three bytes* long and we need to discard this byte and read the *next two* bytes as the length of the script.
* Ditto *254 (0xFE), five bytes, next four*.
* Ditto *255 (0xFF), nine bytes, next eight*.

So we can't represent a script length of 254 in a one-byte Varint because 254 (0xFE) is a special marker byte-value for a five-byte Varint. Instead of using a one-byte Varint, we have to go to the next size up of Varint - a three-byte Varint, and use it's special marker byte value to prefix a two-byte (Uint16\_t) length value.

The [endianness](https://en.wikipedia.org/wiki/Endianness) of the Uint16\_t is why the first byte of the last two is the lowest part of the Uint16\_t value. 254 is 0x00FE but in little-endian byte-order that is 0xFE00.

---

What this teaches us is that the developers of this network protocol prioritised compactness of message size over clarity and simplicity.

Given the prevalence of other protocols that take the opposite approach to message size (consider SMTP with XML payloads like DOCX etc or HTTP with HTML payloads) it must be debateable whether this was a necessary or good choice. Maybe a simpler, less confusing choice could have been used, optionally wrapped in a compression envelope. But the choice was made and I guess it is one that Bitcoin developers must live with.

> **Comments:**
> **username_2**: @username_0: If username_1 answered your question fully, you can accept his answer as the most helpful by clicking the checkmark.  

---

