Skip to content

Commit 370b52f

Browse files
authored
Merge pull request #58 from jrakibi/tx-fields
add topics for the rest of Tx fields
2 parents ede00fc + 16ef38c commit 370b52f

24 files changed

+1048
-19
lines changed

decoding/inputs-output-index.mdx

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
---
2-
title: "Vout: Output index"
2+
title: "Inputs: Output Index (vout)"
33
date: 2024-01-25T15:32:14Z
44
lastmod: "2024-07-26"
55
draft: false
66
category: Transactions
77
layout: TopicBanner
88
order: 3.3
99
icon: "FaClipboardList"
10-
images: ["/bitcoin-topics/static/images/topics/thumbnails/transaction-module/fees-thumbnail-vout.jpg"]
10+
images:
11+
[
12+
"/bitcoin-topics/static/images/topics/thumbnails/transaction-module/fees-thumbnail-vout.jpg"
13+
]
1114
parent: "transaction-structure"
1215
---
1316

decoding/inputs-scriptsig.mdx

+216
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
---
2+
title: "Inputs: ScriptSig"
3+
date: 2024-01-25T15:32:14Z
4+
lastmod: "2024-07-26"
5+
draft: false
6+
category: Transactions
7+
layout: TopicBanner
8+
order: 3.3
9+
icon: "FaClipboardList"
10+
images:
11+
[
12+
"/bitcoin-topics/static/images/topics/thumbnails/transaction-module/tx-thumbnail-scriptsig.jpg"
13+
]
14+
parent: "transaction-structure"
15+
---
16+
17+
<TransactionCreation enabledFields={["scriptsig"]} />
18+
19+
The ScriptSig is a variable-length field in transaction inputs that provides the "unlocking" data needed to spend a previous output. Let's examine our transaction to understand this better:
20+
21+
<div className="dark:hidden w-full rounded-xl overflow-hidden">
22+
<SvgDisplay
23+
src="/bitcoin-topics/static/images/topics/transactions/fees/tx-scriptsig.png"
24+
width="100%"
25+
height="auto"
26+
/>
27+
</div>
28+
<div className="hidden dark:block w-full rounded-xl overflow-hidden">
29+
<SvgDisplay
30+
src="/bitcoin-topics/static/images/topics/transactions/fees/tx-scriptsig.png"
31+
width="100%"
32+
height="auto"
33+
/>
34+
</div>
35+
36+
Let's break down the highlighted hex string from our transaction:
37+
38+
<CodeSnippet code={` 48 3045...126c01 21 02cd...259d2`} language="text" />
39+
40+
<div className="overflow-x-auto">
41+
<table className="min-w-full bg-white dark:bg-gray-900 rounded-lg overflow-hidden">
42+
<thead className="bg-orange-100 dark:bg-orange-900">
43+
<tr>
44+
<th className="px-6 py-3 text-left text-sm font-semibold">
45+
Hex Value
46+
</th>
47+
<th className="px-6 py-3 text-left text-sm font-semibold">
48+
Length
49+
</th>
50+
<th className="px-6 py-3 text-left text-sm font-semibold">
51+
Description
52+
</th>
53+
</tr>
54+
</thead>
55+
<tbody className="divide-y divide-gray-200 dark:divide-gray-800">
56+
<tr className="hover:bg-gray-100 dark:hover:bg-gray-800">
57+
<td className="px-6 py-4 whitespace-nowrap">
58+
<code>48</code>
59+
</td>
60+
<td className="px-6 py-4">1 byte</td>
61+
<td className="px-6 py-4">
62+
Script length in hex (72 bytes in decimal)
63+
</td>
64+
</tr>
65+
<tr className="hover:bg-gray-100 dark:hover:bg-gray-800">
66+
<td className="px-6 py-4 whitespace-nowrap">
67+
<code>3045...126c01</code>
68+
</td>
69+
<td className="px-6 py-4">71 bytes + 1 byte</td>
70+
<td className="px-6 py-4">
71+
DER-encoded signature (71 bytes) + SIGHASH_ALL byte (01)
72+
</td>
73+
</tr>
74+
<tr className="hover:bg-gray-100 dark:hover:bg-gray-800">
75+
<td className="px-6 py-4 whitespace-nowrap">
76+
<code>21</code>
77+
</td>
78+
<td className="px-6 py-4">1 byte</td>
79+
<td className="px-6 py-4">
80+
Public key length in hex (33 bytes in decimal)
81+
</td>
82+
</tr>
83+
<tr className="hover:bg-gray-100 dark:hover:bg-gray-800">
84+
<td className="px-6 py-4 whitespace-nowrap">
85+
<code>02cd...259d2</code>
86+
</td>
87+
<td className="px-6 py-4">33 bytes</td>
88+
<td className="px-6 py-4">
89+
Compressed public key (02 prefix indicates even
90+
y-coordinate)
91+
</td>
92+
</tr>
93+
</tbody>
94+
</table>
95+
</div>
96+
97+
This ScriptSig follows the standard P2PKH (Pay to Public Key Hash) pattern, which we can identify by its two key components:
98+
99+
1. A DER-encoded signature followed by SIGHASH byte (`3045...126c01`)
100+
2. A compressed public key (`02cd...259d2`)
101+
102+
<CodeSnippet code={` <signature> <pubkey>`} language="text" />
103+
104+
The signature proves ownership of the private key, while the public key must hash to match the address in the previous output's ScriptPubKey.
105+
106+
## 1- Purpose and Structure
107+
108+
The ScriptSig serves as the "key" that unlocks the previous output's "lock" (ScriptPubKey). It typically contains:
109+
110+
- Digital signatures proving ownership
111+
- Public keys or other data required by the previous output's script
112+
113+
For legacy transactions, the ScriptSig contains both the signature and any other data needed to satisfy the previous output's spending conditions. For segwit transactions, most of this data moves to the witness field, leaving the ScriptSig empty or minimal.
114+
115+
## 2- Implementation Example
116+
117+
Here's how you might parse a ScriptSig:
118+
119+
<CodeSnippet
120+
code={`def parse_scriptsig(raw_tx: bytes, offset: int = 0) -> tuple[bytes, int]:
121+
"""
122+
Parse a ScriptSig from raw transaction bytes
123+
124+
Args:
125+
raw_tx: Raw transaction bytes
126+
offset: Starting position in bytes
127+
128+
Returns:
129+
(scriptsig, new_offset)
130+
"""
131+
# Read the script size (varint)
132+
script_size, offset = read_varint(raw_tx, offset)
133+
134+
# Read the actual script bytes
135+
script = raw_tx[offset:offset + script_size]
136+
137+
return script, offset + script_size
138+
139+
def decode_der_signature(sig_bytes: bytes) -> tuple[int, int]:
140+
"""
141+
Decode a DER-encoded ECDSA signature into r and s values
142+
""" # Skip sequence byte
143+
pos = 1 # Skip length byte
144+
pos += 1 # Skip marker for r value
145+
pos += 1 # Get r length
146+
r_len = sig_bytes[pos]
147+
pos += 1 # Get r value
148+
r = int.from_bytes(sig_bytes[pos:pos + r_len], 'big')
149+
pos += r_len # Skip marker for s value
150+
pos += 1 # Get s length
151+
s_len = sig_bytes[pos]
152+
pos += 1 # Get s value
153+
s = int.from_bytes(sig_bytes[pos:pos + s_len], 'big')
154+
155+
return r, s`}
156+
language="python"
157+
158+
/>
159+
160+
<ExpandableAlert title="Note" type="info">
161+
The ScriptSig format varies depending on the type of transaction. This
162+
example shows a P2PKH (Pay to Public Key Hash) input, which is the most
163+
common type.
164+
</ExpandableAlert>
165+
166+
## 3- Common Script Types
167+
168+
### P2PKH (Pay to Public Key Hash)
169+
170+
The most common legacy transaction type has this ScriptSig pattern:
171+
172+
<CodeSnippet code={` <signature> <pubkey>`} language="text" />
173+
174+
### P2SH (Pay to Script Hash)
175+
176+
For P2SH inputs, the ScriptSig contains:
177+
178+
<CodeSnippet code={` <signatures...> <redeem script>`} language="text" />
179+
180+
### Segwit Transactions
181+
182+
For native segwit transactions (P2WPKH/P2WSH), the ScriptSig is empty as the unlocking data moves to the witness field.
183+
184+
<ExpandableAlert title="Note" type="info">
185+
For P2SH-wrapped segwit transactions, the ScriptSig contains only the
186+
witness program, while the actual unlocking data is in the witness field.
187+
</ExpandableAlert>
188+
189+
## 4- Size Considerations
190+
191+
The ScriptSig size is encoded as a varint before the actual script data. Common sizes are:
192+
193+
- P2PKH: ~107 bytes
194+
- P2SH: Variable (depends on redeem script complexity)
195+
- Native Segwit: 0 bytes
196+
- P2SH-wrapped Segwit: ~23 bytes
197+
198+
<ExpandableAlert title="Warning" type="warning">
199+
Large ScriptSigs increase transaction size and therefore fees. Segwit moves
200+
this data to the witness, which receives a fee discount.
201+
</ExpandableAlert>
202+
203+
## 5- Validation Rules
204+
205+
When validating a ScriptSig:
206+
207+
1. The script must parse successfully
208+
2. The combined script (ScriptSig + ScriptPubKey) must execute without errors
209+
3. The final stack must contain a true value
210+
4. The script size must not exceed the maximum allowed size
211+
212+
<ExpandableAlert title="Historical Note" type="info">
213+
The original Bitcoin design allowed more complex operations in ScriptSig,
214+
but many were disabled to prevent transaction malleability. This led to the
215+
development of segregated witness (segwit).
216+
</ExpandableAlert>

0 commit comments

Comments
 (0)