-
Notifications
You must be signed in to change notification settings - Fork 1
Description
This is to help you
- create a raw, signable tx
- sign it
- compose the signature into a full tx
This project is cryptocurrency-agnostic (BTC, BSV, BCH, DASH, DOGE, etc).
Although this module was written for Dash, the examples come from https://bitcointalk.org/index.php?topic=651344.0.
Table of Contents
- Anatomy of a Transaction
- Overview
- Types of Types
- Byte-by-Byte
- Raw
- Ready-to-Hash
- Ready-to-Broadcast
- Transaction Examples by Type
- Raw
- Ready-to-Hash (Signable)
- Ready-to-Broadcast (Signed)
Basic Anatomy of a Transaction
In short, every transaction for wallet payments looks like this:
VERSION
#
of Inputs- List of
INPUT
s
(note: these vary wildly between Tx types) #
of Outputs- List of
OUTPUT
s LOCKTIME
- (only for hashing)
SIGHASH_TYPE
Types of Types
Type | Desc |
---|---|
VarInt |
"Compressed" (1-9 byte) Integers. The first byte is either 0-252 (1 byte), 253=3-, 254=5-, or 255=9- bytes |
Uint32LE | Fixed-width ints written in CPU-order (Little-Endian) rather than Network/Storage-order (Big-Endian)0x01000000 is 1 |
ASN.1 |
Like JSON (or XML) of the stone age binary type encoding for ECDSA |
ASN.1 BigInt s |
Padded with leading 0x00 if the first byte is >= 0x80 , unless the number is negative |
OP_ codes |
Stack-based Virtual CPU commands for the network nodes |
PubKeyHash (PKH) | 20-byte (0x14) RIPEMD160 hash of SHA256 hash of ECDSA Public Key X value |
Public Key X (& Y) | "Compressed" Public Keys have a 1-byte prefix (0x02 or 0x03, indicating quadrant of the graph, since the X value indicates two possible Y values) and are 32-byte BigInts (possibly 33 with padding) |
Signature R & S | ECDSA Signatures have R (32-byte) and S (32-byte) components calculated from the Data, Private Key, and K (seeded, possibly random) values |
Byte by Byte
Here's a look at each representation of a TX, byte by byte:
"Raw" Tx
Overview
- VERSION
- Number of Inputs (VarInt)
- List of neutered INPUTS
- Previous Output TX ID (256-bit, reversed)
- Previous Output Index (32-bit, LE)
- 0x00 (Script is not included, therefore Size is 0)
- Sequence Number (always
0xffffffff
)
- Number of Outputs (VarInt)
- List of OUTPUTS
- Units (Satoshis) 64-bit, LE
- 0x19 Lock Script Size (always 25 bytes for wallet payment Txes)
- Lock Script
- 0x76 (OP_DUP)
- 0xa9 (OP_HASH160)
- 0x14 (PubKeyHash Size)
- PubKeyHash (20 bytes)
- 0x88 (OP_EQUALVERIFY)
- 0xac (OP_CHECKSIG)
- LOCKTIME (32-bit, LE)
Example
0100000001a2bda7b7e967346fcf189cee2563b0846d7bec06bb6db6119054add1875bd3770000000000ffffffff0120f1610b000000001976a914f93af105187d21ed6adfa5d71bfada7d7324e53c88ac00000000
Decoded
01000000 # Version Number (32-bit, Little-Endian)
# INPUTS SECTION
01 # Number of Inputs (VarInt)
# Input 1 of 1
a2bda7b7 # Previous TX ID (256-bit, reversed)
e967346f
cf189cee
2563b084
6d7bec06
bb6db611
9054add1
875bd377
00000000 # Previous Output Index (32-bit, LE)
00 # Signature Script Size (VarInt)
ffffffff # Sequence Number (always ffffffff)
# OUTPUTS SECTION
01 # Number of Outputs (VarInt)
# Output 1 of 1
20f1610b00000000 # Output Value / Satoshis (64-bit, LE)
19 # Lock Script Size (25 bytes)
76a9 # OP_DUP, OP_HASH160
14 # PubKeyHash (PKH) Size (20 bytes)
f93af105187d21ed6adf # PubKeyHash
a5d71bfada7d7324e53c
88ac # OP_EQUALVERIFY, OP_CHECKSIG
00000000 # Lock Time
"Hashable" Tx
- VERSION
- Number of Inputs (VarInt)
- List of Hashable INPUTS
- Previous Output TX ID (256-bit, reversed)
- Previous Output Index (32-bit, LE)
- 0x19 (Script Size VarInt, always 25)
- Previous Lock Script
- 0x76 (OP_DUP)
- 0xa9 (OP_HASH160)
- 0x14 (PubKeyHash Size)
- PubKeyHash (20 bytes)
- 0x88 (OP_EQUALVERIFY)
- 0xac (OP_CHECKSIG)
- Sequence Number (always
0xffffffff
)
- Number of Outputs (VarInt)
- List of OUTPUTS
- Units (Satoshis) 64-bit, LE
- 0x19 Lock Script Size (always 25 bytes for wallet payment Txes)
- Lock Script
- 0x76 (OP_DUP)
- 0xa9 (OP_HASH160)
- 0x14 (PubKeyHash Size)
- PubKeyHash (20 bytes)
- 0x88 (OP_EQUALVERIFY)
- 0xac (OP_CHECKSIG)
- LOCKTIME (32-bit, LE)
- Signature Hash Type (32-bit LE, always 0x01000000)
- (computed value) Tx Hash
"Signed" (Ready-to-Broadcast) Tx
- VERSION
- Number of Inputs (VarInt)
- List of Signed INPUTS
- Previous Output TX ID (256-bit, reversed)
- Previous Output Index (32-bit, LE)
- Script Byte Size (VarInt)
106 to 109, varies due to BigInt padding - Signature Script
- Signature + SigHashType Size (71, 72, or 73 bytes total)
- ASN.1 ECDSA Signature (70, 71, or 72 bytes, due to BigInt padding)
- 0x30 (ASN.1 Sequence Type) + Size (1 + 1 bytes)
- 0x02 (ASN.1 Byte Type) + Size (1 + 1 bytes)
- Signature R value (32 or 33 bytes)
- 0x02 (ASN.1 Byte Type) + Size (1 + 1 bytes)
- Signature S value (32 or 33 bytes)
- Sig Hash Type (always 0x01)
- Public Key Size (33 or 34)
- Public Key (compression bit + 32 or 33 bytes)
- Sequence Number (always
0xffffffff
)
- Number of Outputs (VarInt)
- List of OUTPUTS
- Units (Satoshis) 64-bit, LE
- 0x19 Lock Script Size (always 25 bytes for wallet payment Txes)
- Lock Script
- 0x76 (OP_DUP)
- 0xa9 (OP_HASH160)
- 0x14 (PubKeyHash Size)
- PubKeyHash (20 bytes)
- 0x88 (OP_EQUALVERIFY)
- 0xac (OP_CHECKSIG)
- LOCKTIME (32-bit, LE)
- (computed value) Tx ID (reverse Tx Hash, all sigs included)
Amalgam (all 3 types together)
- VERSION
- Number of Inputs (VarInt)
- List of INPUTS
- Previous Output TX ID (256-bit, reversed)
- Previous Output Index (32-bit, LE)
- Script Byte Size (VarInt)
- 0 for "Raw" transactions
- 25 for "Hashable" transactions
- 106 to 109 for "Ready-to-Broadcast" transactions
- Script (1 of these 3 options)
- (for "Raw" Tx) omitted
- (for "Hashable" Tx) Previous Lock Script
- 0x76 (OP_DUP)
- 0xa9 (OP_HASH160)
- 0x14 (PubKeyHash Size)
- PubKeyHash (20 bytes)
- 0x88 (OP_EQUALVERIFY)
- 0xac (OP_CHECKSIG)
- Signature Script
- Signature + SigHashType Size (71, 72, or 73 bytes total)
- ASN.1 ECDSA Signature (70, 71, or 72 bytes, due to BigInt padding)
- 0x30 (ASN.1 Sequence Type) + Size (1 + 1 bytes)
- 0x02 (ASN.1 Byte Type) + Size (1 + 1 bytes)
- Signature R value (32 or 33 bytes)
- 0x02 (ASN.1 Byte Type) + Size (1 + 1 bytes)
- Signature S value (32 or 33 bytes)
- Sig Hash Type (always 0x01)
- Public Key Size (33 or 34)
- Public Key (compression bit + 32 or 33 bytes)
- Sequence Number (always
0xffffffff
)
- Number of Outputs (VarInt)
- List of OUTPUTS
- Units (Satoshis) 64-bit, LE
- 0x19 Lock Script Size (always 25 bytes for wallet payment Txes)
- Lock Script
- 0x76 (OP_DUP)
- 0xa9 (OP_HASH160)
- 0x14 (PubKeyHash Size)
- PubKeyHash (20 bytes)
- 0x88 (OP_EQUALVERIFY)
- 0xac (OP_CHECKSIG)
- LOCKTIME (32-bit, LE)
- (for Tx Hashes only) Signature Hash Type
- (computed values, not in byte sequence)
- Tx Hashes (only for ready-to-sign Txes)
- Tx ID (only for signed Txes)
Types of Transactions (in Bytes)
There are 3 different byte structures for the same basic transaction:
- The "Raw" Tx
This is just inputs (tx ids and indexes from previous outputs) and outputs.
It's pretty much useless. I have no idea why you'd ever want this. - The "Ready-to-Hash" (Signable) Tx
There is one "Ready-to-Hash" Tx (Signable Tx) for each input (even if from the same address)
These are generated in order to creating unique Tx Hashes and verify signatures - The "Ready-to-Broadcast" (Spendable) Tx
These contain enough information to lookup what is needed to reconstruct the Tx Hashes from the info that exists in the blockchain indexes. These have a Tx ID.
Raw Tx (Useless)
There's nothing interesting you can do with these other than pass unit tests.
This format cannot be used to sign or broadcast. It lacks the necessary information to construct either of the useful Tx types.
That said..., here's what a Raw TX looks like, in bytes:
0100000001a2bda7b7e967346fcf189cee2563b0846d7bec06bb6db6119054add1875bd3770000000000ffffffff0120f1610b000000001976a914f93af105187d21ed6adfa5d71bfada7d7324e53c88ac00000000
If we break that down cleanly into 4 sections:
- VERSION
- INPUTS
- OUTPUTS
- LOCKTIME
01 00 00 00 # Version Number (32-bit, Little-Endian)
# INPUTS SECTION
01 # Number of Inputs (VarInt)
# Input 1 of 1
a2bda7b7 # Previous TX ID (256-bit, reversed)
e967346f
cf189cee
2563b084
6d7bec06
bb6db611
9054add1
875bd377
00 00 00 00 # Previous Output Index (32-bit, LE)
00 # Signature Script Size (VarInt)
ffffffff # Sequence Number (always ffffffff)
# OUTPUTS SECTION
01 # Number of Outputs (VarInt)
# Output 1 of 1
20f1610b00000000 # Output Value / Satoshis (64-bit, LE)
19 # Lock Script Size (25 bytes)
76a9 # OP_DUP, OP_HASH160
14 # PubKeyHash (PKH) Size (20 bytes)
f93af105187d21ed6adf # PubKeyHash
a5d71bfada7d7324e53c
88ac # OP_EQUALVERIFY, OP_CHECKSIG
00000000 # Lock Time
Signable Tx
As stated above, a Raw Tx is useless. It's like an idiot-savant's version of JSON.
The signable TX is similar (example forthcoming), but:
sigScript
(and its size) is replaced by the previous transaction's output's lock Script (rather than being 0-length, as in the raw)- The SigHashType (
0x01
) must be appended as a 32-bit LittleEndian - The double-sha256sum is taken and then reversed
Note: this example was added in haste and may not be perfectly correct. TODO make it perfect!
# version (int32)
01 00 00 00
# number of outputs as inputs (varint)
01
# output at index 0
# byte-reversed txid of input's previous output
a2bda7b7e967346fcf189cee2563b0846d7bec06bb6db6119054add1875bd377
# index of input's previous output
00 00 00 00 # prev vout index
# size of signature script (actually previous output lock script)
19
# previous output's lock script (TODO use the real one from the tx)
76a9
14
f93af105187d21ed6adfa5d71bfada7d7324e53c
88ac
# sequence of this input
ffffffff
# number of outputs
01
# output at index 0
# satoshis (reverse byte order)
20 f1 61 0b 00 00 00 00
# varint size of this output's pubkeyhash script
19
# some op codes
76 a9
# decimal 20, the size of the pubkeyhash
14
# the pubkeyhash (no magic byte or checksum)
f93af105187d21ed6adfa5d71bfada7d7324e53c
# more op codes
88 ac
# locktime
00000000
A Signed Tx
The signed transaction will look like this:
0100000001a2bda7b7e967346fcf189cee2563b0846d7bec06bb6db6119054add1875bd377000000006a4730440220528e92bc890b362efcab0ab1af0f9427d501909be59fe22dbdb4c26eac17418102206eb9c83360ad46c9f17be32ea15a08d2765a934e08ce6f2578b3379bbfa03afd0121024451fc7d9e271fab77265bd0292fc274ee231e7ecc076bf6269999c0cbbf9f90ffffffff0120f1610b000000001976a914f93af105187d21ed6adfa5d71bfada7d7324e53c88ac00000000
Which can be broken down like this:
# version (int32)
01 00 00 00
# number of outputs as inputs (varint)
01
# output at index 0
# byte-reversed txid of input's previous output
a2bda7b7e967346fcf189cee2563b0846d7bec06bb6db6119054add1875bd377
# index of input's previous output
00 00 00 00 # prev vout index
# size of signature script (106 decimal)
- 00
+ 6a
+ # size of signature + sighashtype (71 in decimal)
+ 47
+ # ASN.1 Sequence + Size
+ 30 44
+ # ASN.1 Bytes + Len
+ 02 20
+ # Signature R value
+ 528e92bc890b362efcab0ab1af0f9427d501909be59fe22dbdb4c26eac174181
+ # ASN.1 Bytes + Len
+ 02 20
+ # Signature S Value
+ 6eb9c83360ad46c9f17be32ea15a08d2765a934e08ce6f2578b3379bbfa03afd
+ # SigHashType
+ 01
+ # Varint PubKey Len (33)
+ 21
+ # Full Public Key (first byte is quadrant)
+ 02 4451fc7d9e271fab77265bd0292fc274ee231e7ecc076bf6269999c0cbbf9f90
# sequence of this input
ffffffff
# number of outputs
01
# output at index 0
# satoshis (reverse byte order)
20 f1 61 0b 00 00 00 00
# varint size of this output's pubkeyhash script
19
# some op codes
76 a9
# decimal 20, the size of the pubkeyhash
14
# the pubkeyhash (no magic byte or checksum)
f93af105187d21ed6adfa5d71bfada7d7324e53c
# more op codes
88 ac
# locktime
00000000