Ethereum

Ethereum #

Limitations of Bitcoin #

  • UTXO contains ScriptPK or hash thereof
    • Simple script: indicates conditions when UTXO can be spent
  • However: difficult to maintain state in multi-stage contracts or to enforce global rules on assets
    • e.g. rate limiting: if wallet has 100 UTXOs, and want to enforce transfer of max 2BTC per day out of wallet, this is impossible!

Example: NameCoin #

  • DNS on the blockchain
  • Need operations:
    • Name.new(OwnerAddr, DomainName): intent to register
    • Name.update(DomainName, newVal, newOwner, OwnerSig)
    • Name.lookup(DomainName)
    • note: also need to ensure no front-running on Name.new()
  • UTXO for new, update:
    DUP HASH256 <OwnerAddr> EQVERIFY CHECKSIG VERIFY <NAMECOIN> <DomainName> <IPAddr> <1>
    
    • Limitation: cannot enforce “if I own a domain name, nobody else can register or update to that domain name”
    • Required a fork of Bitcoin to achieve
    • However: gave rise to Ethereum, which natively supports global state

Cryptocurrencies as state transition systems #

  • Bitcoin: each transaction is a function mapping from set of possible world states, set of possible inputs -> set of possible world states
    • Limited functionality in these transactions: the mutation only executes over UTXOs transforming one UTXO to another UTXO
  • Ethereum: much richer state transaction function
    • One transition executes an entire program

Ethereum applications #

  • Ethereum DApps include:
    • New coins: ERC-20 standard interface
    • Decentralized finance: exchanges, lending, stablecoins, derivatives, etc
    • Insurance
    • Decentralized organizations
    • NFTs: managing asset ownership (ERC-721 interface)
  • DApps run on:
    • Base: consensus layer: beacon chain
    • Compute layer: execution chain
    • Create DApp w/Program Code, runs on compute layer mapping states to states with transactions as transitions

The Ethereum system #

Consensus layer: proof-of-stake #

  • One block every 12 seconds; about 150 Tx per block
    • Block proposer receives Tx fees for the block, along with other rewards
  • Beacon chain: Eth2 (post-Sep. 2022) consensus layer
    • Validators, not miners
    • To become a validator: stake (lock up) 32 ETH, or use Lido
    • Validators:
      • Sign blocks to express correctness
      • Occasionally propose blocks (chosen at random)
      • Correct behavior: issued new ETH every epoch (32 blocks)
      • Incorrect behavior: slashed
  • When consensus reached: notify_new_payload(payload) (Engine API) called, sends transactions to compute layer

Compute layer: Ethereum Virtual Machine #

  • World state: set of accounts identified by 32-byte address
  • Types of accounts:
    • Owned accounts: controlled by ECDSA signing pair (pk, sk)
    • Contracts: controlled by code (set at account creation time, does not change)

EVM structure and instructions #

  • Stack machine (like Bitcoin) but with JUMP (so loops allowed)
    • Max stack depth = 1024
    • Program aborts if stack size exceeded; block proposer keeps gas
    • Contract can create or call another contract
    • Opcodes at evm.codes
  • Two types of zero-initialized memory:
    • Persistant storage (on blockchain), to use SLOAD, SSTORE (expensive)
    • Volatile memory (for single Tx): MLOAD, MSTORE (cheap)
    • LOG0(data): write data to log
  • Every instruction costs gas:
    • SSTORE <addr>, <value> (32 byte variables each)
    • zero -> nonzero: 20,000 gas
    • nonzero -> nonzero: 5,000 gas (for a cold slot)
    • nonzero -> zero: 15,000 gas refund (example)
      • Refunds given for reducing size of blockchain state: incentivizes contracts to clean up after themselves
      • However: refund has a maximum, cannot make money by just cleaning up the blockchain
    • CREATE: 32,000 + 200x code size gas
    • CALL gas, addr, value, args: call another contract
    • SELFDESTRUCT addr: kill current contract, 5000 gas

Account data #

  • Address (computed):
    • Owned, H(pk)
    • Contracts: H(CreatorAddr, CreatorNonce)
  • Code:
    • Owned: none
    • Contracts: CodeHash
  • Storage root (state):
    • Owned: none
    • Contracts: StorageRoot
  • Balance (in Wei = 10-18 ETH, note GigaWei often used = 10-9 ETH)
    • Both for humans and contracts
  • Nonce:
    • Both for humans and contracts
    • Nonce = number of Tx sent + number of accounts created: anti-replay mechanism

Account state: persistent storage #

  • Every contract has associated storage array S[] w/capacity 2256-1, where each cell holds 32 bytes, init to 0
  • Account storage root: Merkle Patricia Tree, keys are hash of S[]
    • Due to cannot compute full Merkle tree hash: 2256 leaves

State transitions: Tx and messages #

  • Transactions: signed data by initiator, fields:
    • To: 32-byte address of target (0 means create new account)
    • From, [Signature]: initiator address and signature on Tx (if owned)
    • Value: # Wei being sent with Tx
    • Tx fees (EIP 1559): gasLimit, maxFee, maxPriorityFee
    • if To = 0: create new contract code = (init, body)
    • if To != 0: data = (function, args)
    • Nonce: must match current nonce of sender (to prevent Tx replay)
  • Transaction types:
    • owned -> owned: transfer ETH between users
    • owned -> contract: call contract w/ETH and data
    • contract -> owned: contract sends funds to user
    • contract -> contract: one program calls another (and sends funds)
      • Enables composability of contracts
      • One transaction from user can lead to many Tx processed

An Ethereum Block #

  • Validators collect Txs from users => proposer creates a block of n Tx
    • To produce block, do:
      • for i = 1,…,n: execute state change of Txi sequentially (can change state of >n accounts)
      • record updated world state in block
    • Other validators revalidate all Tx to verify block
      • sign block if valid; if enough sigs, finalizes epoch
  • Block headers:
    • Consensus data: proposer ID, parent hash, votes, etc
    • Address of gas beneficiary (Tx fee recipient)
    • World state root: updated world state
      • Merkle Patricia Tree hash of all accounts in system
    • Tx root: Merkle hash of all Tx processed in block
    • Tx receipt root: Merkle hash of all log messages generated in block
    • Gas used: used to adjust gas price (target 15M gas per block)
  • Total blockchain size, ETH world, Oct. 2022: 12TB

Gas calculation #

  • Why charge Tx fees (gas)?
    • Gas prevents submitting Tx that runs for many steps
    • During high load: block proposes Tx from mempool that maximize its income
      • Gas prices spike during congestion
  • Old EVM (prior to Aug. 2021):
    • Every Tx contains a gasPrice “bid” (gas -> Wei conversion bid)
    • Producer chooses Tx w/highest gasPrice (max sum(gasPrice * gasLimit))
      • Not an efficient auction mechanism
      • Changed Aug. 2021 to second-choice auction type design
  • EIP1559 EVM gas calculation:
    • Every block has a baseFee: minimum gasPrice for Tx in the block
    • baseFee computed from total gas in earlier blocks
      • Earlier blocks at gas limit (30M gas) - lots of congestion: base fees goes up 12.5% to discourage participation
      • Earlier blocks empty - no congestion: base fee decreases by 12.5% to encourage participation
      • If earlier blocks at “target size” (15M gas): base fee does not change
    • Transaction specifies three parameters:
      • gasLimit: max total gas allowed for Tx
      • maxFee: maximum allowed gas price
      • maxPriorityFee: additional “tip” to be paid to block proposer
    • Computed gasPrice bid in Wei: gasPrice <- min(maxFee, baseFee + maxPrioirityFee)
      • Max gas: gasLimit * gasPrice
      • Algorithm:
        1. if gasPrice < baseFee: abort
        2. if gasLimit * gasPrice > msg.sender.balance: abort
        3. deduct gasLimit * gasPrice from msg.sender.balance
        4. set Gas <- gasLimit
        5. execute Tx: deduct gas from Gas for each instruction
          • if at end Gas < 0: abort, mark Tx invalid (proposer keeps gasLimit * gasPrice)
        6. Refund Gas * gasPrice to msg.sender.balance (leftover change)
        7. gasUsed <- gasLimit - Gas
          • Burn gasUsed * baseFee (destroys ether, deflation)
          • Send gasUsed * (gasPrice - baseFee) to block producer (tip)
    • Why burn ETH?
      • Goals of EIP1559:
        • Incentivize users to bid true utility for posting Tx
        • Incentivize block proposer to not create fake Tx
        • Disincentivize off-chain agreements
      • Without burn (i.e., baseFee given to block producer):
        • In periods of low Tx, volume proposer would try to increase volume by offering to refund baseFee off-chain to users