Transactions

The following subsections provide a brief overview of important transaction details.

OpCodes

The opcodes used in the pubkey scripts of typical transactions include:

  • Several data-pushing opcodes ranging from 0x00 to 0x4e (values 1–78). These are generally not displayed in examples but must be used to push signatures and public keys onto the stack. Refer to the link below for more details.
  • OP_TRUE/OP_1 (0x51) and OP_2 through OP_16 (0x52–0x60), which push the values 1 to 16 onto the stack.

  • OP_CHECKSIG consumes a signature and full public key, pushing true onto the stack if the transaction data specified by the SIGHASH flag matches the signature, produced using the same ECDSA private key as the public key. If it doesn’t match, it pushes false.

  • OP_DUP duplicates the top stack item and pushes the copy onto the stack.

  • OP_HASH160 consumes the top stack item, computes its RIPEMD160(SHA256()) hash, and then pushes that hash onto the stack.

  • OP_EQUAL consumes the top two items on the stack, compares them, and pushes true if they match, or false if they don’t.

  • OP_VERIFY consumes the top item of the stack. If the value is zero (false), it stops the script with failure.

  • OP_EQUALVERIFY first runs OP_EQUAL and then OP_VERIFY in sequence.

  • OP_CHECKMULTISIG takes the value (n) from the top of the stack, consumes that many subsequent stack levels (public keys), takes the new top value (m), and then consumes that many additional stack levels (signatures), plus one extra value.

The “extra value” consumed is due to an off-by-one error in BitcoinEvo Core’s implementation. This extra value is not used, so signature scripts prefix the secp256k1 signatures list with an OP_0 (0x00).

OP_CHECKMULTISIG compares the first signature against each public key until an ECDSA match is found. For the next public key, it compares the second signature, and this repeats until all signatures are checked or there aren’t enough remaining public keys for a valid match.

Since public keys are not checked again after a failed comparison, signatures must be ordered in the signature script according to the same order as their corresponding public keys in the pubkey or redeem script. For further details, see the “OP_CHECKMULTISIG” warning below.

  • OP_RETURN causes the script to fail when executed.

Signature script modification warning:
Since signature scripts are not signed, anyone can alter them. Therefore, signature scripts should only contain data and data-pushing opcodes that can’t be changed without causing the pubkey script to fail. Including non-data-pushing opcodes in a signature script currently results in a non-standard transaction, and future consensus rules may ban such transactions entirely. (Non-data-pushing opcodes are already prohibited in signature scripts when spending a P2SH pubkey script.)

OP_CHECKMULTISIG warning:
The multisig verification process described earlier requires that the signatures in the signature script be placed in the same sequence as their corresponding public keys in the pubkey or redeem script. For example, the following combined signature and pubkey script would result in the stack and comparisons as shown:

OP_0 <A sig> <B sig> OP_2 <A pubkey> <B pubkey> <C pubkey> OP_3

Sig Stack Pubkey Stack (Actually a single stack)
--------- ------------
B sig C pubkey
A sig B pubkey
OP_0 A pubkey


B sig compared with C pubkey (no match)
B sig compared with B pubkey (match #1)
A sig compared with A pubkey (match #2)

Success: two matches found.

However, reversing the order of the signatures without changing anything else would lead to failure, as illustrated below:

OP_0 <B sig> <A sig> OP_2 <A pubkey> <B pubkey> <C pubkey> OP_3

Sig Stack Pubkey Stack (Actually a single stack)
--------- ------------
A sig C pubkey
B sig B pubkey
OP_0 A pubkey

A sig compared with C pubkey (no match)
A sig compared with B pubkey (no match)


Failure: two signature matches are required, but none were found, with only one pubkey left.

Address Conversion

The hashes used in P2PKH and P2SH outputs are typically encoded as BitcoinEvo addresses. Below is the process for encoding these hashes and decoding the addresses.

First, you need your hash. For P2PKH, this is done by applying RIPEMD-160(SHA256()) to an ECDSA public key, which is derived from your 256-bit ECDSA private key (random data). For P2SH, RIPEMD-160(SHA256()) is applied to a redeem script serialized in the format used for raw transactions (explained in the following section). With the resulting hash:

  1. Add an address version byte before the hash. The version bytes most commonly used by BitcoinEvo are:
    • 0x00 for P2PKH addresses on the main BitcoinEvo network (mainnet)
    • 0x6f for P2PKH addresses on the BitcoinEvo test network (testnet)
    • 0x05 for P2SH addresses on mainnet
    • 0xc4 for P2SH addresses on testnet
  2. Create a copy of the version and hash; hash the copy twice using SHA256: SHA256(SHA256(version . hash))

  3. Take the first four bytes of the double-hashed result. These will act as a checksum to verify that the base hash is transmitted correctly.

  4. Append the checksum to the version and hash, then encode the result as a base58 string: BASE58(version . hash . checksum)

BitcoinEvo’s base58 encoding, known as Base58Check, may differ from other implementations.


code_string = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
x = convert_bytes_to_big_integer(hash_result)

output_string = ""

while(x > 0)
{
(x, remainder) = divide(x, 58)
output_string.append(code_string[remainder])
}

repeat(number_of_leading_zero_bytes_in_hash)
{
output_string.append(code_string[0]);
}

output_string.reverse();


To convert addresses back into hashes, reverse the base58 encoding, extract the checksum, recalculate the checksum, compare it with the extracted checksum, and then remove the version byte.

Raw Transaction Format

BitcoinEvo transactions are transmitted between peers in a serialized byte format, referred to as raw format. This form of the transaction is double-hashed using SHA256(SHA256()) to create the transaction ID (TXID), which is eventually included in the merkle root of the block that contains the transaction. This format is part of the consensus rules.

BitcoinEvo Core, along with many other tools, prints and accepts raw transactions encoded in hexadecimal.

All BitcoinEvo Core transactions use the version 1 format, as outlined below. (Note: Transactions in the blockchain can use a higher version number to allow for soft forks, though they are treated as version 1 transactions by current software.)

A raw transaction follows this top-level format:

A transaction can contain multiple inputs and outputs, so the txIn and txOut structures may be repeated within a single transaction. CompactSize unsigned integers are a type of variable-length integer used in this context.

TxIn: A Transaction Input (Non-Coinbase)

Each non-coinbase input spends a specific output from a prior transaction. (Coinbase inputs are discussed separately after the examples below.)

Outpoint: The Specific Part Of A Specific Output

Since a transaction can include multiple outputs, the outpoint structure is used to specify both a TXID and an output index number to reference a particular output.



Bytes Name Data Type Description
32 hash char[32] The TXID of the transaction containing the output to be spent. The TXID is presented in internal byte order.
4 index uint32_t The index number of the output within the transaction to be spent. The first output index is 0x00000000.

TxOut: A Transaction Output

Each output spends a certain number of satoshis and requires specific conditions (via a pubkey script) to be met in order to be spent by a future transaction.



Bytes Name Data Type Description
8 value int64_t The number of satoshis being spent. It can be zero; however, the total value of all outputs must not exceed the total satoshis spent to the referenced outpoints in the inputs. (Exception: coinbase transactions spend the block subsidy and any transaction fees.)
1+ pk_script bytes compactSize uint The length of the pubkey script in bytes. The maximum allowable size is 10,000 bytes.
Varies pk_script char[] This defines the conditions that must be fulfilled to spend the output.


Example


The example raw transaction below is the one created in the Simple Raw Transaction section of the Developer Examples. It spends a prior pay-to-pubkey output by sending funds to a new pay-to-pubkey-hash (P2PKH) output.


01000000 ................................... Version

01 ......................................... Number of inputs
|
| 7b1eabe0209b1fe794124575ef807057
| c77ada2138ae4fa8d6c4de0398a14f3f ......... Outpoint TXID
| 00000000 ................................. Outpoint index number
|
| 49 ....................................... Bytes in signature script: 73
| | 48 ..................................... Push 72 bytes as data
| | | 30450221008949f0cb400094ad2b5eb3
| | | 99d59d01c14d73d8fe6e96df1a7150de
| | | b388ab8935022079656090d7f6bac4c9
| | | a94e0aad311a4268e082a725f8aeae05
| | | 73fb12ff866a5f01 ..................... secp256k1 signature
|
| ffffffff ................................. Sequence number: UINT32_MAX

01 ......................................... Number of outputs
| f0ca052a01000000 ......................... Satoshis (49.99990000 BTCE)
|
| 19 ....................................... Bytes in pubkey script: 25
| | 76 ..................................... OP_DUP
| | a9 ..................................... OP_HASH160
| | 14 ..................................... Push 20 bytes as data
| | | cbc20a7664f2f69e5355aa427045bc15
| | | e7c6c772 ............................. Public key hash
| | 88 ..................................... OP_EQUALVERIFY
| | ac ..................................... OP_CHECKSIG

00000000 ................................... Locktime: 0 (a block height)

Coinbase Input: The Input for the First Transaction in a Block

The first transaction in a block, known as the coinbase transaction, must include one input, referred to as the coinbase input. This input currently follows the format outlined below.

Although the coinbase script can consist of arbitrary data, including any signature-checking operations such as “OP_CHECKSIG” within the script will count those operations as sigops (signature operations), contributing to the block’s sigop limit. To avoid this, the data can be prefixed with the correct push operation.

Here is an example of a coinbase transaction:

01000000 .............................. Version

01 .................................... Number of inputs
| 00000000000000000000000000000000
| 00000000000000000000000000000000 ... Previous outpoint TXID
| ffffffff ............................ Previous outpoint index
|
| 29 .................................. Bytes in coinbase script
| |
| | 03 ................................ Number of bytes in height
| | | 4e0105 .......................... Block height: 328014
| |
| | 062f503253482f0472d35454085fffed
| | f2400000f90f54696d65202620486561
| | 6c74682021 ........................ Arbitrary data
| 00000000 ............................ Sequence

01 .................................... Number of outputs
| 2c37449500000000 .................... Satoshis (25.04275756 BTCE)
| 1976a914a09be8040cbf399926aeb1f4
| 70c37d1341f3b46588ac ................ Pay-to-PubKey-Hash (P2PKH) script
| 00000000 ............................ Locktime

CompactSize Unsigned Integers

The raw transaction format, along with several peer-to-peer network messages, uses a type of variable-length integer to indicate the byte count of a subsequent data item.

In BitcoinEvo Core, and this document, these variable-length integers are referred to as compactSize. Other documents may refer to them as var_int or varInt, but this can lead to confusion with other types of variable-length integer encodings — such as the CVarInt class used in BitcoinEvo Core for serializing data to disk. Since compactSize integers are used in transaction formats, their structure is part of the consensus rules.

For values ranging from 0 to 252, compactSize integers appear as standard unsigned integers. For larger values, a prefix byte indicates the length, but the number itself still follows regular unsigned integer formatting in little-endian order.



Value Range Bytes Used Format
0 to 252 1 uint8_t
253 to 0xffff 3 0xfd followed by the number as uint16_t
0x10000 to 0xffffffff 5 0xfe followed by the number as uint32_t
0x100000000 to 0xffffffffffffffff 9 0xff followed by the number as uint64_t


For example, the number 515 would be encoded as 0xfd0302.