Step 8: Final Transaction Structure
Our final signed transaction hex:
01000000000102fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f00000000494830450221008b9d1dc26ba6a9cb62127b02742fa9d754cd3bebf337f7a55d114c8e5cdd30be022040529b194ba3f9281a99f2b1c0a19c0489bc22ede944ccf4ecbab4cc618ef3ed01eeffffffef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac000247304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee0121025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee635711000000
Let's break it down:
1Version: 01000000
2Marker: 00
3Flag: 01
4
5Input Count: 02
6Input 1:
7 Previous TXID: fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f
8 Output Index: 00000000
9 ScriptSig: 4830450221008b9d1dc26ba6a9cb62127b02742fa9d754cd3bebf337f7a55d114c8e5cdd30be022040529b194ba3f9281a99f2b1c0a19c0489bc22ede944ccf4ecbab4cc618ef3ed01
10 Sequence: eeffffff
11Input 2:
12 Previous TXID: ef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a
13 Output Index: 01000000
14 ScriptSig: (empty)
15 Sequence: ffffffff
16
17
18Output Count: 02
19Output 1:
20 Amount: 202cb206000000
21 ScriptPubKey: 76a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac
22
23Output 2:
24 Amount: 9093510d000000
25 ScriptPubKey: 76a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac
26
27Witness:
28 Input 1: 00
29 Input 2: 02 (items)
30 47 304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee01
31 21 025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee6357
32
33Locktime: 11000000
About Input 1's ScriptSig
You might notice that we didn't explain how we filled the scriptSig
for the first input.
This uses a legacy signature approach which is similar but slightly different from segwit signature.
Don't worry, we'll have a GitHub Classroom exercise where we'll explain how legacy signing works too!
Code Implementation
def assemble_transaction(
inputs: List[bytes],
outputs: List[bytes],
witnesses: List[bytes]
) -> bytes:
"""
Assemble the final SegWit transaction.
Args:
inputs: List of serialized inputs
outputs: List of serialized outputs
witnesses: List of witness data (one per input, empty bytes for non-witness inputs)
"""
# 4-byte version
version = int_to_little_endian(1, 4)
# Marker and flag for SegWit
marker_flag = b'\x00\x01'
# Input count and serialized inputs
input_count = varint(len(inputs))
serialized_inputs = b''.join(inputs)
# Output count and serialized outputs
output_count = varint(len(outputs))
serialized_outputs = b''.join(outputs)
# Witness data (already includes counts)
witness_data = b''.join(witnesses)
print("witness_data:", witness_data.hex()) # Debug print
# 4-byte locktime
locktime = int_to_little_endian(0x11, 4)
# Combine all parts
return (
version +
marker_flag +
input_count +
serialized_inputs +
output_count +
serialized_outputs +
witness_data +
locktime
)
BIP-143 Test Vector
Complete Test Vector Implementation
This is the complete implementation that generates the transaction matching BIP143 test vector. You can run this locally to verify the results.
Decoded Transaction
This is our final signed transaction hex:
# Unsigned Transaction (Before Signing)
unsigned_tx = "0100000002fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f0000000000eeffffffef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac11000000"
# Final Signed Transaction
signed_tx = "01000000000102fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f00000000494830450221008b9d1dc26ba6a9cb62127b02742fa9d754cd3bebf337f7a55d114c8e5cdd30be022040529b194ba3f9281a99f2b1c0a19c0489bc22ede944ccf4ecbab4cc618ef3ed01eeffffffef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac000247304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee0121025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee635711000000"
When we decode our final transaction using Bitcoin Core's decoderawtransaction
command, we can see all the components we've assembled:

