Sequence

TransactionSequence
Structure
Version
4 bytes
Segwit (Optional)
Marker
1 byte
Flag
1 byte
Structure
Input Count
variable
Input Structure
Previous TXID
32 bytes
Output Index
4 bytes
ScriptSig Size
variable
ScriptSig
variable
Sequence
4 bytes
Structure
Output Count
variable
Output Structure
Amount
8 bytes
ScriptPubKey Size
variable
ScriptPubKey
variable
Structure
Witness
variable
Structure
Locktime
4 bytes

Size

4 bytes

Format

Little-Endian

Description

Transaction version as defined by the sender.

Example

ffffffff

Byte Visualization

ff
Byte 1
ff
Byte 2
ff
Byte 3
ff
Byte 4

The sequence field is a 4-byte unsigned integer that appears in each transaction input.
Originally intended for "high-frequency trades". it now serves different purposes including Replace-By-Fee (RBF) and relative timelocks.

Let's examine our transaction to understand this better:

SVG Image

In our example transaction, we can see the sequence value is 0xffffffff. This is the default sequence value (4294967295 in decimal) which:

  • Disables relative timelocks (BIP 68)
  • Indicates RBF (Replace-By-Fee) is not enabled
  • Represents the traditional "final" sequence number

1- Sequence Values

Value RangeDecimal RangeDescriptionCommon Use Cases
0xffffffff4294967295Default value
  • Standard transactions
  • Disables relative timelocks
  • RBF disabled
< 0xf0000000< 4026531840RBF signaling
  • Fee bumping
  • Transaction replacement
  • Unconfirmed tx updates
< 0x80000000< 2147483648Relative timelock
  • Payment channels
  • Time-based scripts
  • Relative block/time locks
00Minimum value
  • Maximum replaceability
  • No timelock restrictions

We will cover Replace-By-Fee (RBF) and relative timelocks in detail in separate topics. Now just understand what a sequence number is and its range.

Note

These ranges are hierarchical - a value that enables relative timelocks (< 0x80000000) also automatically enables RBF (< 0xf0000000).

2- Implementation Example

Here's how you might parse a transaction input's sequence number:

python
def parse_sequence(raw_tx: bytes, offset: int = 0) -> tuple[int, int]:
    """
    Parse a sequence number from raw transaction bytes
    
    Args:
        raw_tx: Raw transaction bytes
        offset: Starting position in bytes
        
    Returns:
        (sequence, new_offset)
    """
    # Read 4 bytes for sequence
    sequence_bytes = raw_tx[offset:offset + 4]
    
    # Convert to integer (little-endian)
    sequence = int.from_bytes(sequence_bytes, 'little')
    
    return sequence, offset + 4

3- Historical Context

Original Design

Satoshi originally designed the sequence number for "high-frequency trades" - a way to update transactions before they were mined. The idea was to create payment channels between parties, where each new payment would increment the sequence number. However, this design was vulnerable to miner manipulation and was later replaced by better payment channel designs like the Lightning Network.

4- Modern Uses

Replace-By-Fee (RBF)

When a transaction's input has a sequence number below 0xf0000000, it signals that the transaction can be replaced by a version with higher fees. This is useful when network fees increase and you want to speed up confirmation of your transaction.

Relative Timelocks

BIP 68 introduced relative timelocks using sequence numbers below 0x80000000. This allows an input to specify a minimum age (in blocks or time) relative to its previous output before it can be spent.

python
def is_rbf_enabled(sequence: int) -> bool:
    """Check if RBF is enabled for this sequence number"""
    return sequence < 0xf0000000

def is_relative_timelock(sequence: int) -> bool:
    """Check if relative timelock is enabled"""
    return sequence < 0x80000000

Note

The sequence field must be interpreted differently depending on the transaction version. Relative timelocks (BIP 68) only apply to transactions version 2 or higher.

Suggest Edits
View our public visitor count
Built with 🧡 by the Bitcoin Dev Project
We'd love to hear your feedback on this project?Give Feedback