Bitcoin Basics

Bitcoin is the first successful implementation of blockchain technology. Understanding Bitcoin deeply provides the foundation for understanding all subsequent blockchains, including Solana.

How Bitcoin Works: A Complete Picture

Let's trace what happens when Alice sends Bitcoin to Bob.

Step 1: Creating the Transaction

Alice wants to send 0.5 BTC to Bob. Her wallet software creates a transaction:

JavaScript
// Conceptual transaction structure
const transaction = {
  version: 2,
  inputs: [
    {
      // Reference to previous transaction output Alice can spend
      previousTxHash: "abc123...",
      outputIndex: 0,
      // Proof Alice owns this output (signature)
      scriptSig: "304402... 02a1b2...", // signature + public key
    },
  ],
  outputs: [
    {
      // Bob receives 0.5 BTC
      value: 50000000, // in satoshis (1 BTC = 100,000,000 satoshis)
      scriptPubKey:
        "OP_DUP OP_HASH160 <bob_pubkey_hash> OP_EQUALVERIFY OP_CHECKSIG",
    },
    {
      // Change back to Alice (0.499 BTC - she's paying 0.001 BTC fee)
      value: 49900000,
      scriptPubKey:
        "OP_DUP OP_HASH160 <alice_pubkey_hash> OP_EQUALVERIFY OP_CHECKSIG",
    },
  ],
  lockTime: 0,
};

Step 2: Broadcasting to the Network

Alice's wallet broadcasts the transaction to connected nodes. Those nodes:

  1. Validate the transaction (signature valid? inputs unspent?)
  2. Propagate to their connected peers
  3. Add to their mempool (pending transaction pool)

Within seconds, the transaction reaches most of the network through gossip protocol.

Text
     [Alice's Node]
          │
    ┌─────┼─────┐
    ▼     ▼     ▼
  [Node] [Node] [Node]
    │     │     │
  ┌─┴─┐ ┌─┴─┐ ┌─┴─┐
  ▼   ▼ ▼   ▼ ▼   ▼
 ... ... ... ... ... ...

Exponential propagation reaches
~10,000 nodes in seconds

Step 3: Mining a Block

Miners collect transactions from their mempool and attempt to create a valid block.

Python
# Mining process (simplified)
def mine_block(mempool, previous_block_hash, coinbase_address):
    # Select transactions (usually by fee rate)
    transactions = select_transactions(mempool, max_size=1_000_000)

    # Create coinbase transaction (mining reward)
    coinbase_tx = create_coinbase(
        reward=6.25,  # BTC (as of 2024)
        fees=sum(tx.fee for tx in transactions),
        address=coinbase_address
    )

    # Build block header
    header = {
        'version': 0x20000000,
        'prev_hash': previous_block_hash,
        'merkle_root': compute_merkle_root([coinbase_tx] + transactions),
        'timestamp': int(time.time()),
        'bits': current_difficulty_target,
        'nonce': 0
    }

    # Find valid nonce (the actual "mining")
    target = bits_to_target(header['bits'])
    while True:
        header_bytes = serialize_header(header)
        block_hash = sha256(sha256(header_bytes))

        if int(block_hash, 16) < target:
            return create_block(header, [coinbase_tx] + transactions)

        header['nonce'] += 1
        if header['nonce'] >= 2**32:
            # Exhausted nonce space, change something else
            header['timestamp'] = int(time.time())
            header['nonce'] = 0

The difficulty target requires the block hash to have a certain number of leading zeros:

Text
Target:  00000000000000000007a4...
Valid:   00000000000000000004f2...(less than target)
Invalid: 00000000000000000012c8...(greater than target)

Step 4: Block Propagation

When a miner finds a valid block:

  1. They broadcast it to the network
  2. Nodes validate:
    • Block hash meets difficulty target
    • All transactions are valid
    • Coinbase reward is correct
    • Previous block hash references valid chain tip
  3. Nodes update their chain and mempool
  4. Other miners abandon current work and start on new block

Step 5: Confirmation

Alice's transaction is now "1 confirmation" deep. Each additional block adds more security:

Text
Block 700,000 (Alice's tx)
      │
Block 700,001  ← 2 confirmations
      │
Block 700,002  ← 3 confirmations
      │
Block 700,003  ← 4 confirmations
      │
Block 700,004  ← 5 confirmations
      │
Block 700,005  ← 6 confirmations (generally considered "final")

Why 6 confirmations? To reverse a transaction, an attacker would need to re-mine all subsequent blocks faster than the honest network. With each confirmation, this becomes exponentially harder.

The UTXO Model

Bitcoin uses Unspent Transaction Outputs (UTXOs) to track balances.

Mental Model: Digital Cash Envelopes

Think of UTXOs as sealed envelopes of cash:

Text
Alice receives 1.0 BTC:
┌─────────────────────────────┐
│  UTXO #1                    │Value: 1.0 BTC             │
│  Owner: Can be spent by     │
│         Alice's signature   │
└─────────────────────────────┘

Alice wants to pay Bob 0.3 BTC:

She "opens" her envelope and creates new ones:

┌─────────────────────────────┐
│  UTXO #2                    │
│  Value: 0.3 BTC             │
│  Owner: Bob                 │
└─────────────────────────────┘

┌─────────────────────────────┐
│  UTXO #3 (change)           │
│  Value: 0.699 BTC           │
│  Owner: Alice               │
└─────────────────────────────┘

(0.001 BTC goes to miners as fee)

UTXO vs Account Model

Bitcoin's UTXO model differs from Ethereum's account model:

UTXO (Bitcoin)Account (Ethereum)
Track individual "coins"Track balances
Stateless verificationStateful
Parallel processing easierSequential processing
Privacy via new addressesAddress reuse common
Change outputsNo change needed

Solana uses an account model, but understanding UTXO helps you appreciate the design trade-offs.

UTXO Code Example

TypeScript
// Representing UTXOs in TypeScript
interface UTXO {
  txHash: string;
  outputIndex: number;
  value: number; // in satoshis
  scriptPubKey: string;
}

interface Transaction {
  inputs: TransactionInput[];
  outputs: TransactionOutput[];
}

interface TransactionInput {
  utxo: UTXO;
  scriptSig: string; // Signature proving ownership
}

interface TransactionOutput {
  value: number;
  scriptPubKey: string; // Locking script
}

// Calculate wallet balance
function getBalance(utxos: UTXO[]): number {
  return utxos.reduce((sum, utxo) => sum + utxo.value, 0);
}

// Coin selection: Choose which UTXOs to spend
function selectCoins(utxos: UTXO[], targetAmount: number): UTXO[] {
  // Simple strategy: largest first
  const sorted = [...utxos].sort((a, b) => b.value - a.value);
  const selected: UTXO[] = [];
  let total = 0;

  for (const utxo of sorted) {
    if (total >= targetAmount) break;
    selected.push(utxo);
    total += utxo.value;
  }

  if (total < targetAmount) {
    throw new Error("Insufficient funds");
  }

  return selected;
}

Bitcoin Script

Bitcoin transactions use a stack-based scripting language called Script.

How Script Works

Script is intentionally limited:

  • No loops (prevents infinite execution)
  • No state (each script execution is independent)
  • Stack-based execution
Text
Standard Pay-to-Public-Key-Hash (P2PKH) script:

ScriptPubKey (locking script):
  OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG

ScriptSig (unlocking script):
  <signature> <publicKey>

Execution (scripts concatenated):
  <sig> <pubKey> OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG

Step-by-step:
1. Push <sig> onto stack:           Stack: [sig]
2. Push <pubKey> onto stack:        Stack: [sig, pubKey]
3. OP_DUP (duplicate top):          Stack: [sig, pubKey, pubKey]
4. OP_HASH160 (hash top):           Stack: [sig, pubKey, hash(pubKey)]
5. Push <pubKeyHash>:               Stack: [sig, pubKey, hash(pubKey), pubKeyHash]
6. OP_EQUALVERIFY:                  Stack: [sig, pubKey] (if hashes match)
7. OP_CHECKSIG:                     Stack: [true] (if signature valid)

Result: Transaction is valid!

Script Limitations

Bitcoin Script intentionally can't do everything:

Text
What Script CAN'T do:
✗ Loops (while, for)
✗ Complex state
✗ External data access
✗ Most arithmetic (limited to 32-bit)

What Script CAN do:
✓ Signature verification
✓ Time locks
✓ Multi-signature requirements
✓ Hash puzzles

This simplicity is a feature—it makes Bitcoin highly secure and predictable. Ethereum (and Solana) opted for more expressive smart contracts with different trade-offs.

Mining Economics

Block Rewards and Halving

Bitcoin's monetary policy is fixed in code:

Python
def get_block_reward(block_height: int) -> float:
    """
    Block reward halves every 210,000 blocks (~4 years)
    """
    halvings = block_height // 210_000
    if halvings >= 64:
        return 0  # Reward becomes negligible after ~2140

    initial_reward = 50  # BTC
    return initial_reward / (2 ** halvings)

# Examples:
# Block 0:       50 BTC (2009)
# Block 210,000: 25 BTC (2012)
# Block 420,000: 12.5 BTC (2016)
# Block 630,000: 6.25 BTC (2020)
# Block 840,000: 3.125 BTC (2024)

Total supply: 21,000,000 BTC (asymptotically approached)

Transaction Fees

As block rewards decrease, transaction fees become more important:

Text
Fee = (Input Values) - (Output Values)

Example:
Inputs:  1.0 BTC
Outputs: 0.3 BTC (to recipient) + 0.699 BTC (change)
Fee:     1.0 - 0.3 - 0.699 = 0.001 BTC

Miners prioritize transactions by fee rate (satoshis per virtual byte):

JavaScript
function calculateFeeRate(transaction) {
  const fee = sumInputs(transaction) - sumOutputs(transaction);
  const vsize = calculateVirtualSize(transaction); // ~200-500 bytes typical
  return fee / vsize; // sat/vB
}

// Higher fee rate = faster confirmation
// Current typical rates: 10-100 sat/vB

Security Guarantees

51% Attack

If an attacker controls >50% of hash power:

Text
Honest chain:  ABCDEAttacker:                 D' → E'F'  (attacker's chain)

If attacker's chain becomes longer, the network switches to it.
This could reverse transactions in blocks D and E.

Why it's hard:

  • Bitcoin's hash rate is ~500 EH/s (500 quintillion hashes/second)
  • Requires specialized hardware worth billions
  • Attack would crash BTC price, devaluing attacker's investment

Selfish Mining

A miner with significant hash power might:

  1. Mine blocks secretly
  2. Wait for the honest network to find a block
  3. Release their longer chain, orphaning honest blocks

This can provide >proportional rewards but requires ~25-33% hash power to be profitable.

Common Misconceptions

"Bitcoin transactions are anonymous"

Reality: Bitcoin is pseudonymous, not anonymous. All transactions are public and traceable. Sophisticated chain analysis can often link addresses to identities.

"Bitcoin is slow"

Reality: Bitcoin prioritizes security and decentralization. 7 TPS is a design choice, not a limitation. Layer 2 solutions (Lightning Network) enable millions of TPS for smaller transactions.

"Bitcoin wastes energy"

Reality: Complex topic. Bitcoin's energy use secures a global monetary network. The relevant comparison is to traditional financial system energy use, not to zero energy use.

Key Takeaways

  1. Transactions spend UTXOs and create new ones
  2. Mining is competitive search for valid block hashes
  3. Consensus emerges from economic incentives + longest chain rule
  4. Security increases with each confirmation
  5. Script is intentionally limited for security

Deep Dive: Transaction Validation

A node validates every transaction by checking:

Rust
// Conceptual validation (not real Bitcoin code)
fn validate_transaction(tx: &Transaction, utxo_set: &UtxoSet) -> Result<(), Error> {
    // 1. Check inputs exist and are unspent
    for input in &tx.inputs {
        let utxo = utxo_set.get(&input.outpoint)
            .ok_or(Error::MissingInput)?;

        // 2. Verify signature against UTXO's locking script
        if !verify_script(&input.script_sig, &utxo.script_pubkey, tx)? {
            return Err(Error::InvalidSignature);
        }
    }

    // 3. Check value conservation (inputs >= outputs)
    let input_value: u64 = tx.inputs.iter()
        .map(|i| utxo_set.get(&i.outpoint).unwrap().value)
        .sum();
    let output_value: u64 = tx.outputs.iter()
        .map(|o| o.value)
        .sum();

    if output_value > input_value {
        return Err(Error::InsufficientInputs);
    }

    // Fee = input_value - output_value (goes to miner)

    // 4. Check transaction size limits
    if tx.serialized_size() > MAX_TX_SIZE {
        return Err(Error::TooLarge);
    }

    Ok(())
}

Try It Yourself

  1. Explore a transaction: Go to mempool.space, find a recent transaction, and identify the inputs, outputs, and fee.

  2. Calculate confirmations: If a block is mined roughly every 10 minutes, how many confirmations would a transaction have after 1 hour?

  3. UTXO math: Alice has UTXOs worth 0.5, 0.3, and 0.1 BTC. She wants to send 0.6 BTC. Which UTXOs should she use, and how much change will she receive (assuming 0.0001 BTC fee)?


Next: Ethereum Basics - How Ethereum expanded the blockchain paradigm with smart contracts.