A bitcoin transaction is just a bunch of data that unlocks and locks up batches of bitcoins.
To be more precise, a transaction:
Selects existing batches of bitcoins (inputs) and unlocks them.
Creates new batches of bitcoins (outputs) and puts new locks on them.
You can have multiple inputs and outputs in a single transaction.
So you can think of a transaction as being part of a chain of outputs; one transaction creates an output, and then a future transaction selects that output (as an input) and unlocks it to create new outputs.
The locking and unlocking mechanism involves some cryptography. The lock on an output usually contains a public key, and if you want to unlock it, you'll need the corresponding private key for that public key to create a digital signature for it.
A digital coin contains the public key of its owner. To transfer it, the owner signs the coin together with the public key of the next owner. Anyone can check the signatures to verify the change of ownership.
This cryptography was not invented by Bitcoin; digital signature systems already existed, and Bitcoin utilizes one so that people can "own" and send each other quantities of bitcoin.
But whilst that's interesting, we don't need to know about this underlying cryptography if we just want to be able to understand the structure of bitcoin transactions and how they work, which is what this page is all about.
Structure
What does a raw bitcoin transaction look like?
A raw bitcoin transaction is made up of fields, each containing bytes of data.
All bitcoin transactions have the same basic structure, so to decode them you just need to know the size of each field and what format the data is in.
A basic transaction has a version number of 1, but most modern bitcoin transactions now use a version number of 2.
Marker & Flag (Optional)
Size: 2 bytes
The next two bytes can be used to indicate a segregated witness transaction.
These bytes are only required if you're unlocking inputs that have a P2WPKH, P2WSH, or P2TR lock on them (i.e. they require use of the witness field at the end of the transaction).
Marker
Size: 1 byte
Set this to 00 to indicate that this is a segregated witness transaction. This must always be 00.
Flag
Size: 1 byte
Set this to 01 for a segregated witness transaction. In the future this byte may be incremented to indicate newer transaction structures.
Older Bitcoin software that hasn't been upgraded to use segregated witness transactions will interpret these marker and flag bytes as indicating that the transaction has 0 inputs and 1 output, which would make the transaction invalid. However, old nodes wouldn't actually be sent these bytes when they are sent the transaction.
Input Count
Size: Variable
Type: Integer
Format: Compact Size
The input count field indicates the upcoming number of inputs in the transaction.
Each input in a transaction has its own inner structure. But all you're basically doing is selecting an output from a previous transaction and providing the unlocking code for it.
For each input you just need to repeat the following set of fields:
This is the TXID for the transaction that created the output you want to spend.
The TXID you use to reference a previous transaction in raw transaction data is in natural byte order, which is actually the reverse order of bytes you see on blockchain explorers. This is just a quirk of bitcoin.
A TXID is created by hashing the transaction data. Every transaction has its own unique TXID.
This is the index number for the output in the transaction you have just referenced.
A transaction can create multiple outputs, so you need to specify which output from the transaction you want to spend. This combination of a TXID:VOUT is referred to as an outpoint, which makes for a unique identifier for each individual batch of bitcoins inside the blockchain.
The output you want to spend must not have been spent in a previous transaction.
The first output of a transaction is at index number 0.
VOUT is short for "Vector Output". A "vector" is basically a programming term for a numbered list of items. It's a structure commonly used in C++, which is the language Bitcoin was originally programmed in.
ScriptSig Size
Size: Variable
Type: Integer
Format: Compact Size
Indicates the upcoming size of the unlocking code for this input.
The unlocking code can vary in length depending on the type of lock used, so that's why we need to specify how long the upcoming unlocking code is going to be so we know how much data we need to read.
The scriptsig field contains the unlocking code for the output you have just referenced. Every output has some form of lock on it, so you need to provide some data that will satisfy the conditions of the lock.
This field uses Script, and it typically contains a digital signature. This signature is created by signing the current transaction data using the private key that created the public key inside the lock.
This field is now only used for unlocking outputs with legacy locking scripts. These are:
It's called a "ScriptSig" because it's unlocked using Script, and it usually contains a signature.
If you are unlocking a modern P2WPKH or P2WSH locking script, the unlocking code must be placed inside the upcoming witness field instead. If this is the case, you should set the size of the scriptsig field for this input to 00.