HomeCurriculumBlockchain BasicsTransaction Models - UTXO vs Account State
Transaction Models: UTXO vs Account State

Transaction Models - UTXO vs Account State

Bitcoin UTXO model vs Ethereum Account-based state model, nonce management, and gas fees.

DT
Authored by DevThesis Systems Editorial Team
Reviewed for Technical Accuracy & Code Determinism

At the foundation of every distributed ledger is a state transition engine that maintains a consistent record of asset ownership, value transfers, and contract execution. Mathematically, a blockchain can be modeled as a replicated deterministic finite state machine where consensus validates the state transition function:

S_t+1 = APPLY(S_t, TX)

where S_t represents the global state before the transaction block, TX represents a block of validated transactions, and S_t+1 represents the resulting mutated state.

However, blockchain architectures diverge fundamentally in how state is structured, indexed, and mutated. The two primary paradigms are:

  1. The UTXO (Unspent Transaction Output) Model: Pioneered by Bitcoin and adopted by Cardano and Ergo, where state is represented as a distributed graph of discrete, consumable cryptographic coins.
  2. The Account/Balance Model: Pioneered by Ethereum and adopted by Solana, Avalanche, and Cosmos, where state is represented as a global database mapping account addresses to mutable balances and storage tries.

Understanding the deep trade-offs between these models—governing concurrency, transaction parallelization, privacy, smart contract expressiveness, and storage bloat—is essential for blockchain systems architecture.


1. The Bitcoin UTXO Model: The Graph of Discrete Coins#

In the UTXO model, coins do not exist as account balances in a ledger. There is no central table in Bitcoin recording that "Alice has 5 BTC." Instead, value exists solely as discrete, atomic entities called Unspent Transaction Outputs (UTXOs) scattered across a Directed Acyclic Graph (DAG).

text
The UTXO Directed Acyclic Graph (DAG) Structure:

Transaction 1 (TxID: 0xaa..) Transaction 2 (TxID: 0xbb..)
┌──────────────────────────────┐ ┌──────────────────────────────┐
│ Inputs: │ │ Inputs: │
│ PrevTx: 0x99.., vout: 0 │ │ PrevTx: 0xaa.., vout: 1 │◄── Consumes
│ ScriptSig: <SigAlice> │ │ ScriptSig: <SigBob> │ Output #1
├──────────────────────────────┤ ├──────────────────────────────┤
│ Outputs: │ │ Outputs: │
│ [0]: 0.8 BTC -> Carol │ │ [0]: 0.3 BTC -> Dave │
│ [1]: 1.2 BTC -> Bob │───────►│ [1]: 0.89 BTC -> Bob (Chg) │
└──────────────────────────────┘ └──────────────────────────────┘
 Implicit Fee = 1.2 - (0.3 + 0.89) = 0.01 BTC

Anatomy of a UTXO Transaction#

Every Bitcoin transaction consumes one or more existing UTXOs as Inputs and creates one or more new UTXOs as Outputs. Once an output is consumed as an input in a valid transaction, it is permanently marked as spent and can never be spent again.

1. Transaction Inputs (`tx_in`)

Each input references an existing unspent output and provides cryptographic authorization:

  • Previous Output Pointer (`OutPoint`):

- txid: The 32-byte double-SHA-256 hash of the transaction that created the UTXO.

- vout: A 4-byte zero-indexed integer identifying which specific output of that transaction is being spent.

  • Unlocking Script (`ScriptSig` or `Witness`): Contains the cryptographic proof (digital signature and public key) that satisfies the locking conditions established by the UTXO.
  • Sequence Number (`nSequence`): A 4-byte field utilized for relative timelocks (BIP 68) and Replace-by-Fee (RBF, BIP 125) signaling.

2. Transaction Outputs (`tx_out`)

Each output establishes a new discrete coin:

  • Value: An 8-byte unsigned integer denominated in satoshis (1 satoshi = 10^-8 BTC).
  • Locking Script (`ScriptPubKey`): A forth-like script establishing the mathematical conditions (e.g., knowledge of a private key corresponding to a public key hash) that must be fulfilled to spend the satoshis in the future.

3. Implicit Transaction Fees

In the UTXO model, the miner fee is not explicitly specified in a dedicated transaction field. Rather, it is the mathematical difference between the total input satoshis and total output satoshis:

Fee = ∑_i=1^m Value(Input_i) - ∑_j=1^n Value(Output_j)

By consensus rules, if ∑ Output > ∑ Input, the transaction is invalid. If ∑ Input > ∑ Output, the unallocated surplus is implicitly collected by the miner who mines the block into their coinbase transaction.

4. The Change Output Paradigm

Because a UTXO is an atomic, indivisible coin, it cannot be partially spent. If a user holds a single UTXO worth 2.0 BTC and wishes to pay a merchant 0.5 BTC, the transaction must consume the entire 2.0 BTC coin and generate two new outputs:

  1. Destination Output: 0.5 BTC locked to the merchant's address.
  2. Change Output: 1.4995 BTC locked to a newly generated address owned by the sender.

The remaining 0.0005 BTC is the miner fee.


2. Bitcoin Script: The Stack-Based Verification Engine#

Bitcoin evaluates transaction validity using Bitcoin Script, a stack-based, Forth-like, non-Turing complete programming language. Script operates without loops, recursion, or complex jumps, providing a strict upper bound on execution time and eliminating the Halting Problem and denial-of-service infinite loop attacks.

text
Stack Execution Flow (Last-In, First-Out):

Initial State: [ ScriptSig ] followed by [ ScriptPubKey ]
 <Signature> <PublicKey> OP_DUP OP_HASH160 <PKHash> OP_EQUALVERIFY OP_CHECKSIG

Step 1: Push Sig and PubKey onto Stack:
 Stack: [ <Sig>, <PubKey> ]
Step 2: OP_DUP duplicates top item:
 Stack: [ <Sig>, <PubKey>, <PubKey> ]
Step 3: OP_HASH160 hashes top item (RIPEMD160(SHA256(PubKey))):
 Stack: [ <Sig>, <PubKey>, <ComputedHash> ]
Step 4: Push expected <TargetPKHash> from ScriptPubKey:
 Stack: [ <Sig>, <PubKey>, <ComputedHash>, <TargetPKHash> ]
Step 5: OP_EQUALVERIFY compares top two hashes:
 If Equal -> Pops both. If Not Equal -> FAILS IMMEDIATELY!
 Stack: [ <Sig>, <PubKey> ]
Step 6: OP_CHECKSIG validates ECDSA signature against public key:
 Pushes TRUE (0x01) if valid, FALSE (0x00) if invalid.
Final State: Stack holds [ 0x01 ] -> TRANSACTION VALID!

Standard Bitcoin Script Templates#

1. Pay-to-Public-Key-Hash (P2PKH)

The historical standard for Bitcoin addresses (starting with '1'):

  • ScriptPubKey: OP_DUP OP_HASH160 <TargetPKHash> OP_EQUALVERIFY OP_CHECKSIG
  • ScriptSig: <Signature> <PublicKey>

2. Pay-to-Script-Hash (P2SH, BIP 16)

P2SH (addresses starting with '3') shifts the computational complexity and fee burden of advanced locking logic (such as m-of-n multi-signature escrows) from the sender to the spender:

  • The sender locks funds to the 20-byte hash of an arbitrary redemption script:

ScriptPubKey: OP_HASH160 <RedeemScriptHash> OP_EQUAL

  • The spender reveals the full serialized redeem script and its satisfying signatures in ScriptSig:

ScriptSig: <Sig1> <Sig2> ... <SerializedRedeemScript>

3. Segregated Witness (SegWit, BIP 141)

SegWit solves Transaction Malleability (where third-party nodes could alter cryptographic signatures without invalidating them, mutating the txid) by decoupling the signature data from the base transaction tree:

  • Signature data is relocated from ScriptSig to a separate Witness field.
  • Introduces Block Weight Units (WU) instead of raw byte sizes:

Weight = BaseSize × 3 + TotalSize

Witness bytes receive a 75\% discount, effectively expanding block capacity to 2-4 MB while preserving backwards compatibility.

4. Taproot & Schnorr Signatures (BIP 340 / 341 / 342)

Activated in November 2021, Taproot introduces:

  • Schnorr Signatures (BIP 340): Linear signature aggregation (S = ∑ s_i), allowing multi-signature wallets to appear on-chain as a single, standard public key, drastically boosting privacy and slashing fee overhead.
  • Merkelized Alternative Script Trees (MAST): Complex spending conditions are committed into a Merkle tree. Spenders reveal only the specific execution path executed, keeping all unused fallback conditions private.

3. The Ethereum Account-Based State Model#

In contrast to Bitcoin's discrete coin graph, Ethereum models the blockchain as a global, centralized ledger of bank accounts. The global world state is an authenticated mapping from 160-bit (20-byte) hexadecimal addresses to 4-element account state tuples:

σ: Address → (nonce, balance, storageRoot, codeHash)

text
Ethereum Global World State Architecture:

Global State Root (Keccak-256 Hash in Block Header)
 │
 ▼
[ Merkle Patricia State Trie ]
 ├── 0xAlice... ──► [ Nonce: 14, Balance: 4.5 ETH, Storage: Empty, Code: Empty ] (EOA)
 ├── 0xBob... ──► [ Nonce: 2, Balance: 0.8 ETH, Storage: Empty, Code: Empty ] (EOA)
 └── 0xUniswapV3.. ──► [ Nonce: 0, Balance: 1250 ETH, Storage: RootHash, Code: Hash ] (Contract)
 │
 ┌────────────────────────────┘
 ▼
 [ Storage Trie for Contract ]
 (Holds all state variables: mappings, uints)

The Two Account Classifications#

1. Externally Owned Accounts (EOAs)

Accounts controlled by private individuals via cryptographic private keys (ECDSA secp256k1):

  • nonce: Scalar integer counter representing the exact number of transactions broadcast from this address.
  • balance: Account balance denominated in Wei (1 ETH = 10^18 Wei).
  • storageRoot: An empty Keccak-256 hash (0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421), as EOAs contain no internal persistent storage.
  • codeHash: An empty hash (Keccak256("")), as EOAs contain no executable bytecode.

2. Contract Accounts (Smart Contracts)

Autonomous entities deployed to the state lattice, governed entirely by compiled EVM bytecode:

  • nonce: The number of child contracts created by this contract.
  • balance: Ether held by the contract.
  • storageRoot: The 256-bit root hash of a dedicated Merkle Patricia Trie that maps 2^256 storage slots to 2^256 32-byte values.
  • codeHash: The immutable Keccak-256 hash of the contract's EVM runtime bytecode.

The Account Nonce & Replay Protection#

Because an account balance is simply a number stored in a database, a naive transaction "Alice pays Bob 5 ETH" contains no intrinsic link to previous transactions. Without protection, an adversary (or Bob) could intercept the signed transaction and re-broadcast it to the network a thousand times, draining Alice's entire balance.

Ethereum resolves this by enforcing an Account Nonce:

  1. Every transaction signed by an EOA must contain a nonce value exactly equal to the account's current state nonce:

TX.nonce = σ[sender].nonce

  1. Upon successful transaction validation, the account's nonce increments atomically:

σ[sender].nonce ← σ[sender].nonce + 1

  1. If a transaction arrives with a nonce lower than the account's state nonce, it is rejected as a Replay Attack. If a transaction arrives with a nonce higher than current state, it stalls in the node's memory pool until all intervening nonces are mined.

4. Architectural Trade-Off Matrix: UTXO vs. Account State#

DimensionUTXO Model (Bitcoin, Cardano)Account Model (Ethereum, Solana)
State RepresentationGraph of unspent coin outputsGlobal key-value state database
Concurrency & ParallelismEmbarrassingly Parallel: Non-overlapping UTXOs can be verified simultaneously across all CPU coresSequential / Complex: Transactions targeting the same account must be serialized to prevent state race conditions
Smart Contract ExpressivenessDifficult shared state; requires extended UTXO (eUTXO) or state channelsTuring-Complete Shared State: Native shared mutable state (crucial for AMMs, lending protocols, DAOs)
Replay Attack DefenseNatural (Outputs can only be consumed once; second attempt is rejected as double-spend)Requires monotonic per-account nonces
Transaction Space & FeesLarger transactions (must specify multiple inputs and outputs); fees scale with byte sizeCompact transactions (sender, recipient, value, data); fees scale with computational gas
Privacy & PseudonymitySuperior: Users generate unique one-time addresses for change outputsInferior: Public balances and transactions are permanently consolidated into a single address identity
State Bloat & PruningNodes only need to store the active UTXO set (~5-10 GB); spent historical outputs can be prunedSevere State Bloat: Full node must store contract storage slots and balances perpetually

5. Industrial Production Implementation: UTXO vs Account State Engines#

The following complete Python script implements both transaction models from scratch:

  1. A UTXO Transaction Engine that validates OutPoints, checks double-spending, verifies balance conservation, and tracks unspent transaction outputs.
  2. An Account State Ledger that enforces strict nonce sequencing, deducts gas and transfers, updates account tuples, and handles reverts on insufficient funds.
python
import hashlib
from typing import Dict, List, Tuple, Set

# ==========================================================
# 1. UTXO TRANSACTION ENGINE IMPLEMENTATION
# ==========================================================

class UTXOEngine:
 """Simulates a Bitcoin-style UTXO State Machine."""
 def __init__(self) -> None:
 # Maps OutPoint (txid, vout) -> (recipient, satoshis)
 self.utxo_set: Dict[Tuple[str, int], Tuple[str, int]] = {}

 def add_coinbase(self, txid: str, vout: int, recipient: str, satoshis: int) -> None:
 """Mints an initial unspent transaction output (coinbase)."""
 self.utxo_set[(txid, vout)] = (recipient, satoshis)

 def process_transaction(
 self,
 txid: str,
 inputs: List[Tuple[str, int]], # List of (prev_txid, vout)
 outputs: List[Tuple[str, int]] # List of (recipient, satoshis)
 ) -> Tuple[bool, str, int]:
 """
 Validates and applies a UTXO transaction.
 Returns: (success_bool, status_message, miner_fee)
 """
 # 1. Check for duplicate inputs within the same transaction
 if len(inputs) != len(set(inputs)):
 return False, "REJECTED: Duplicate inputs in transaction.", 0

 # 2. Verify all inputs exist in the UTXO set (prevent double-spending)
 total_input_sats = 0
 for outpoint in inputs:
 if outpoint not in self.utxo_set:
 return False, f"REJECTED: OutPoint {outpoint} is spent or invalid.", 0
 recipient, sats = self.utxo_set[outpoint]
 total_input_sats += sats

 # 3. Verify total output value does not exceed input value
 total_output_sats = sum(sats for _, sats in outputs)
 if total_output_sats > total_input_sats:
 return False, "REJECTED: Output value exceeds input value.", 0

 miner_fee = total_input_sats - total_output_sats

 # 4. Atomic State Mutation: Remove spent inputs
 for outpoint in inputs:
 del self.utxo_set[outpoint]

 # 5. Add newly created UTXOs
 for vout_idx, (recipient, sats) in enumerate(outputs):
 self.utxo_set[(txid, vout_idx)] = (recipient, sats)

 return True, "SUCCESS: Transaction applied.", miner_fee


# ==========================================================
# 2. ACCOUNT STATE LEDGER IMPLEMENTATION
# ==========================================================

class AccountLedger:
 """Simulates an Ethereum-style Account State Machine."""
 def __init__(self) -> None:
 # Maps address -> {'nonce': int, 'balance_wei': int}
 self.state: Dict[str, Dict[str, int]] = {}

 def create_account(self, address: str, initial_balance_wei: int) -> None:
 self.state[address] = {"nonce": 0, "balance_wei": initial_balance_wei}

 def process_transaction(
 self,
 sender: str,
 recipient: str,
 value_wei: int,
 nonce: int,
 gas_fee_wei: int
 ) -> Tuple[bool, str]:
 """
 Validates and applies an account-based state transfer.
 """
 if sender not in self.state:
 return False, "REJECTED: Sender account does not exist."

 sender_account = self.state[sender]

 # 1. Nonce Check (Replay Protection)
 if nonce != sender_account["nonce"]:
 return False, f"REJECTED: Nonce mismatch! Expected {sender_account['nonce']}, got {nonce}."

 # 2. Balance Check (Value + Gas Fee)
 total_debit = value_wei + gas_fee_wei
 if sender_account["balance_wei"] < total_debit:
 return False, "REJECTED: Insufficient balance for value + gas."

 # 3. Ensure recipient account exists
 if recipient not in self.state:
 self.state[recipient] = {"nonce": 0, "balance_wei": 0}

 # 4. Atomic State Mutation
 sender_account["balance_wei"] -= total_debit
 sender_account["nonce"] += 1
 self.state[recipient]["balance_wei"] += value_wei

 return True, "SUCCESS: State transition complete."


# ==========================================================
# DEMONSTRATION & VERIFICATION
# ==========================================================

if __name__ == "__main__":
 print("=== 1. Testing UTXO Engine ===")
 utxo = UTXOEngine()
 # Genesis UTXO: Alice has 500,000 satoshis (0.005 BTC)
 utxo.add_coinbase("tx_gen_01", 0, "Alice", 500_000)

 # Alice pays Bob 300,000 satoshis, sends 190,000 back as change, 10,000 fee
 tx1_inputs = [("tx_gen_01", 0)]
 tx1_outputs = [("Bob", 300_000), ("Alice_Change", 190_000)]
 ok, msg, fee = utxo.process_transaction("tx_01", tx1_inputs, tx1_outputs)
 print(f"Tx 1 Status: {msg} (Miner Fee: {fee} sats)")
 assert ok and fee == 10_000

 # Double-spending attempt: Alice tries to reuse tx_gen_01
 ok2, msg2, _ = utxo.process_transaction("tx_fraud", tx1_inputs, tx1_outputs)
 print(f"Double-Spend Attempt: {msg2}")
 assert not ok2

 print("=== 2. Testing Account Ledger ===")
 eth = AccountLedger()
 eth.create_account("0xAlice", 10_000_000_000) # 10 Gwei
 eth.create_account("0xBob", 0)

 # Valid transaction from Alice to Bob
 ok_eth, msg_eth = eth.process_transaction(
 sender="0xAlice", recipient="0xBob", value_wei=6_000_000_000, nonce=0, gas_fee_wei=21_000
 )
 print(f"ETH Tx 1 Status: {msg_eth}")
 assert ok_eth

 # Replay attack attempt: Repeating identical transaction with nonce 0
 ok_replay, msg_replay = eth.process_transaction(
 sender="0xAlice", recipient="0xBob", value_wei=6_000_000_000, nonce=0, gas_fee_wei=21_000
 )
 print(f"ETH Replay Attack Attempt: {msg_replay}")
 assert not ok_replay

6. Common Anti-Patterns & Engineering Pitfalls#

1. Address Reuse in UTXO Systems#

The Anti-Pattern: Reusing the same public address across multiple incoming payments.

Why it Breaks: Reusing addresses permanently degrades privacy by enabling blockchain analytics heuristics (Common Input Ownership clustering) to map out a user's entire transaction graph. Furthermore, once an address spends funds, its raw public key is exposed on-chain, eliminating the hash-commitment security layer provided by OP_HASH160.

Correct Practice: Utilize Hierarchical Deterministic (HD) wallets (BIP 32/44) that generate a pristine, unique public address for every incoming transaction and change output.

2. High-Concurrency Nonce Collisions in Ethereum Backends#

The Anti-Pattern: Spawning parallel worker threads that sign and broadcast Ethereum transactions from a single shared EOA without nonce coordination.

Why it Breaks: If Thread A and Thread B both read the account nonce as 42, they will broadcast competing transactions with nonce=42. Only one transaction can be mined; the other is rejected with nonce too low or stalls the queue with replacement transaction underpriced.

Correct Practice: Implement a centralized in-memory Redis-based atomic nonce counter, or partition operational workloads across distinct, segregated worker EOAs.

3. Dust Attacks on UTXO Wallets#

The Anti-Pattern: Blindly consolidating unknown micro-UTXOs received from anonymous senders.

Why it Breaks: An adversary broadcasts microscopic UTXO outputs ("dust", e.g., 546 satoshis) to thousands of addresses. When a user's wallet automatically selects this dust UTXO as an input alongside their primary savings UTXOs, the wallet signs all inputs together, cryptographically linking the user's previously disjoint addresses in public blockchain analysis tools.


7. Checkpoint Practice Problems#

Problem 1: Bitcoin P2PKH Script Stack Simulation#

A transaction output contains a standard Pay-to-Public-Key-Hash (P2PKH) locking script:

text
OP_DUP OP_HASH160 <TargetPKHash> OP_EQUALVERIFY OP_CHECKSIG

where <TargetPKHash> is the 20-byte string 0x7a8b9c....

The spending input supplies the unlocking script:

text
<SigAlice> <PubKeyAlice>

where HASH160(PubKeyAlice) = RIPEMD160(SHA256(PubKeyAlice)) = 0x7a8b9c..., and the signature SigAlice is mathematically valid.

Required:

  1. Write out the concatenated execution stream evaluated by the script engine.
  2. Step through each instruction sequentially, showing the exact contents of the stack after each operation:

- Initial state

- Pushing unlocking arguments

- OP_DUP

- OP_HASH160

- Pushing <TargetPKHash>

- OP_EQUALVERIFY

- OP_CHECKSIG

  1. State the final condition required for the transaction input to be deemed cryptographically valid.

Step-by-Step Solution:

Step 1: Concatenated Instruction Stream

The execution engine concatenates ScriptSig and ScriptPubKey:

Stream = ⟨ SigAlice ⟩ ⟨ PubKeyAlice ⟩ OP\_DUP OP\_HASH160 ⟨ TargetPKHash ⟩ OP\_EQUALVERIFY OP\_CHECKSIG

Step 2: Step-by-Step Stack Evaluation

  • State 0 (Initial): Stack is empty:

Stack = [\ ]

  • State 1 (Push `<SigAlice>`):

Stack = [ ⟨ SigAlice ⟩ ]

  • State 2 (Push `<PubKeyAlice>`):

Stack = [ ⟨ SigAlice ⟩, ⟨ PubKeyAlice ⟩ ]

  • State 3 (`OP_DUP`):

Duplicates the top stack element:

Stack = [ ⟨ SigAlice ⟩, ⟨ PubKeyAlice ⟩, ⟨ PubKeyAlice ⟩ ]

  • State 4 (`OP_HASH160`):

Pops top element, computes RIPEMD160(SHA256(⟨ PubKeyAlice ⟩)), and pushes the result:

Stack = [ ⟨ SigAlice ⟩, ⟨ PubKeyAlice ⟩, 0x7a8b9c... ]

  • State 5 (Push `<TargetPKHash>`):

Pushes constant 0x7a8b9c... onto the stack:

Stack = [ ⟨ SigAlice ⟩, ⟨ PubKeyAlice ⟩, 0x7a8b9c..., 0x7a8b9c... ]

  • State 6 (`OP_EQUALVERIFY`):

Pops top two elements and checks equality:

0x7a8b9c... == 0x7a8b9c... is True.

Both elements are popped. (If false, execution halts immediately with failure).

Stack = [ ⟨ SigAlice ⟩, ⟨ PubKeyAlice ⟩ ]

  • State 7 (`OP_CHECKSIG`):

Pops public key and signature. Evaluates ECDSA verification equation:

Verify(MessageHash, ⟨ SigAlice ⟩, ⟨ PubKeyAlice ⟩) → True

Pushes boolean success code 0x01 onto the stack:

Stack = [ 0x01 ]

Step 3: Final Validity Condition

The script execution terminates with no errors, and the top item on the stack is a non-zero element (0x01 / True). Thus, the input is cryptographically valid.


Problem 2: Multi-Input UTXO Fee and Change Satoshis Computation#

A Bitcoin wallet contains three unspent transaction outputs:

  • UTXO_1: 45,000,000 satoshis (0.45 BTC)
  • UTXO_2: 20,000,000 satoshis (0.20 BTC)
  • UTXO_3: 85,000,000 satoshis (0.85 BTC)

The user wants to send exactly 110,000,000 satoshis (1.10 BTC) to an external merchant.

The mempool congestion requires a fee rate of R = 28 satoshis/vByte.

The transaction structure consists of:

  • A standard SegWit transaction (Native SegWit, P2WPKH).
  • 2 inputs: each input has a virtual size of 68 vBytes.
  • 2 outputs: destination output (31 vBytes) and change output (31 vBytes).
  • Overhead header and version: 10.5 vBytes.

Required:

  1. Select the minimal subset of UTXOs that provides sufficient funds to cover the payment and fee.
  2. Compute the exact total virtual size (vSize) of the constructed transaction.
  3. Calculate the required miner fee in satoshis.
  4. Calculate the exact change amount returned to the user's change address in satoshis and in BTC.

Step-by-Step Solution:

Step 1: UTXO Coin Selection

Target payment = 110,000,000 satoshis.

  • Combining UTXO_1 (45 M) and UTXO_2 (20 M) yields 65 M < 110 M (Insufficient).
  • Combining UTXO_2 (20 M) and UTXO_3 (85 M) yields 105 M < 110 M (Insufficient).
  • Combining UTXO_1 (45 M) and UTXO_3 (85 M) yields:

Total Input = 45,000,000 + 85,000,000 = 130,000,000 satoshis ≥ 110 M

The wallet selects UTXO_1 and UTXO_3 (2 inputs).

Step 2: Compute Transaction Virtual Size (vSize)

vSize = Overhead + (2 × InputSize) + (2 × OutputSize)

vSize = 10.5 + 2(68) + 2(31) = 10.5 + 136.0 + 62.0 = 208.5 vBytes

Rounding up to the nearest integer byte ceiling:

vSize = 209 vBytes

Step 3: Calculate Required Miner Fee

Fee = ⌈ vSize × R ⌉ = 209 vBytes × 28 sat/vByte = 5,852 satoshis

Step 4: Compute Change Satoshis

Recall the conservation of satoshis equation:

Change = Total Input - Destination Payment - Fee

Change = 130,000,000 - 110,000,000 - 5,852 = 20,000,000 - 5,852 = 19,994,148 satoshis

In Bitcoin:

Change in BTC = (19,994,148 / 10^8) = 0.19994148 BTC

Fee in BTC = (5,852 / 10^8) = 0.00005852 BTC

Conservation check:

1.10000000 + 0.19994148 + 0.00005852 = 1.30000000 BTC (Exact balance preserved).


Problem 3: Ethereum Nonce Queueing & Mempool Stalling Dynamics#

An automated decentralized arbitrage bot broadcasts four transactions from an Ethereum Externally Owned Account (EOA) whose on-chain state currently has:

Current State Nonce = 45, Balance = 2.0 ETH

Due to network routing anomalies and fluctuating gas prices, the four transactions are received by miner mempools in the following scrambled order:

  • Transaction A: Nonce = 45, Value = 0.4 ETH, Gas Fee = 0.01 ETH
  • Transaction B: Nonce = 47, Value = 0.5 ETH, Gas Fee = 0.01 ETH
  • Transaction C: Nonce = 48, Value = 0.6 ETH, Gas Fee = 0.01 ETH
  • Transaction D: Nonce = 46, Value = 0.3 ETH, Gas Fee = 0.01 ETH

Required:

  1. Explain how an Ethereum node's transaction pool handles Transaction B and Transaction C when they arrive before Transaction D.
  2. State the exact chronological execution order in which the transactions must be executed on the EVM state.
  3. Compute the step-by-step account balance and state nonce after each transaction executes.
  4. If Transaction D had specified a Value of 1.5 ETH (instead of 0.3 ETH), explain what would occur to Transaction D, Transaction B, and Transaction C.

Step-by-Step Solution:

Step 1: Mempool Queueing Behavior

  • When Transaction B (nonce=47) arrives, current state nonce is 45. Because 47 > 45, a nonce gap exists (missing nonces 45 and 46). Transaction B cannot be mined and is placed in the future / queued transaction bucket.
  • When Transaction C (nonce=48) arrives, it is also queued behind Transaction B.
  • Neither transaction can execute or mutate state until all previous nonces are mined sequentially.

Step 2: Canonical Execution Order

Transactions must be mined strictly in increasing order of their nonces:

Execution Order: Transaction A (45) → Transaction D (46) → Transaction B (47) → Transaction C (48)

Step 3: Step-by-Step State Transitions

  • Initial State:

- Balance: 2.00 ETH, Nonce: 45

  • Execute Transaction A (nonce=45):

- Total deduction = 0.40 + 0.01 = 0.41 ETH

- Remaining balance = 2.00 - 0.41 = 1.59 ETH

- New state nonce: 46

  • Execute Transaction D (nonce=46):

- Total deduction = 0.30 + 0.01 = 0.31 ETH

- Remaining balance = 1.59 - 0.31 = 1.28 ETH

- New state nonce: 47

  • Execute Transaction B (nonce=47):

- Total deduction = 0.50 + 0.01 = 0.51 ETH

- Remaining balance = 1.28 - 0.51 = 0.77 ETH

- New state nonce: 48

  • Execute Transaction C (nonce=48):

- Total deduction = 0.60 + 0.01 = 0.61 ETH

- Remaining balance = 0.77 - 0.61 = 0.16 ETH

- New state nonce: 49

Step 4: Insufficient Balance Revert Scenario

If Transaction D had value 1.5 ETH:

  • Total required for D = 1.50 + 0.01 = 1.51 ETH.
  • Available balance before D = 1.59 ETH.

1.59 ≥ 1.51, so Transaction D executes! Balance becomes 1.59 - 1.51 = 0.08 ETH, Nonce becomes 47.

  • Next, Transaction B (nonce=47) attempts to execute:

Required = 0.50 + 0.01 = 0.51 ETH.

Available = 0.08 ETH.

Because 0.08 < 0.51, Transaction B fails immediately due to insufficient funds.

  • Transaction B is dropped, leaving the nonce at 47.
  • Consequently, Transaction C (nonce=48) can never execute, remaining indefinitely stalled in the mempool until the user deposits more ETH and broadcasts a valid transaction with nonce 47.

Problem 4: Concurrency & Parallel Verification Scalability Comparison#

A high-throughput layer-1 blockchain node running on a 64-core server processes a proposed block containing N = 10,000 transactions.

  • Under the UTXO Model:

- Every transaction consumes exactly 2 inputs and generates 2 outputs.

- Verification involves checking that the 2 input OutPoints exist in the UTXO set and validating 2 ECDSA cryptographic signatures.

- No two transactions in the block share identical input OutPoints.

  • Under the Account Model:

- Transactions interact with a popular automated market maker (AMM) liquidity pool account.

- Exactly 4,000 of the 10,000 transactions target the same AMM contract address to execute swaps.

Required:

  1. Explain whether the 10,000 UTXO transactions can be verified in parallel across all 64 CPU cores. State the theoretical parallel speedup factor under Amdahl's Law (assuming signature verification accounts for 95\% of CPU time).
  2. Explain why the 4,000 AMM transactions in the Account model cannot be verified simultaneously in parallel without optimistic software transactional memory (STM / Block-STM).
  3. Conclude what structural architectural advantages the UTXO model provides for payment scalability versus what the Account model provides for complex composable decentralized finance (DeFi).

Step-by-Step Solution:

Step 1: Parallel Verification in the UTXO Model

Because no two transactions in the block spend the same OutPoint, the input sets are completely disjoint:

Inputs(TX_i) ∩ Inputs(TX_j) = ∅ ∀ i ≠ j

There are zero data dependencies or shared mutable memory locations between transactions.

The dominant computational bottleneck—cryptographic ECDSA/Schnorr signature verification—is completely embarrassingly parallel.

Under Amdahl's Law with parallel fraction P = 0.95 and N = 64 cores:

Speedup = (1 / (1 - P) + (P / N)) = (1 / (1 - 0.95) + (0.95 / 64)) = (1 / 0.05 + 0.01484) = (1 / 0.06484) ≈ 15.42 ×

Verification scales linearly across available cores, allowing nodes to validate tens of thousands of signatures per second.

Step 2: Serialization Bottleneck in the Account Model

In the Account model, all 4,000 AMM transactions modify the same contract storage slots (the token reserve balances x and y under the constant product formula x · y = k).

  • Transaction 2 depends on the exact output price resulting from Transaction 1.
  • Transaction 3 depends on the state after Transaction 2.

Attempting to execute them simultaneously in parallel creates a Write-After-Write (WAW) and Read-After-Write (RAW) data race:

σ_t+1[AMM] = f(σ_t[AMM], TX_1)

σ_t+2[AMM] = f(σ_t+1[AMM], TX_2)

Without Block-STM (optimistic parallel execution with conflict abortion, as in Aptos/Sui), these 4,000 transactions must be serialized strictly onto a single CPU thread, eliminating parallel speedup.

Step 3: Strategic Architectural Conclusion

  • The UTXO Model is structurally optimized for pure payment processing, scalability, and privacy: transactions are localized, parallelizable, and decoupled, making it ideal for base-layer digital sound money (Bitcoin).
  • The Account Model is structurally optimized for programmable composability and shared global state: allowing arbitrary smart contracts to interact within a single atomic transaction (e.g., flash loans, multi-protocol liquidations, unified liquidity pools), making it the foundation of decentralized finance despite sequential processing bottlenecks.

Key Architectural Takeaways

  • Mastering Transaction Models - UTXO vs Account State is critical for Blockchain Basics production systems.
  • Strict invariant verification guarantees runtime stability and predictability.
  • Always follow industry-standard telemetry, logging, and security practices.

Hands-on Code Playground Available

Execute, edit, and experiment with code for this topic in the live sandbox.

Practice Check • Quick Quiz

Test Your Understanding

In Blockchain Basics, what is the main purpose of Transaction Models - UTXO vs Account State?

A
To guarantee deterministic performance and correctness for transaction models: utxo vs account state.
B
To bypass all system security checks during execution.
C
To increase memory allocation overhead unnecessarily.
D
To force non-blocking single-threaded execution globally.