Ethereum Source Code Analysis: Blocks, Transactions, Contracts, and the Virtual Machine

·

Ethereum stands as one of the most influential blockchain platforms, not only enabling decentralized digital currency but also serving as a foundation for smart contracts and decentralized applications (dApps). For developers and enthusiasts seeking deeper technical understanding, diving into the Ethereum source code—specifically the Go implementation (go-ethereum)—offers invaluable insights into its architecture and protocol design.

This article explores core components of Ethereum’s system, including blocks, transactions, contracts, and the Ethereum Virtual Machine (EVM), focusing on how these elements interact to form a secure, scalable, and programmable blockchain environment. All references are based on the open-source go-ethereum project hosted on GitHub.


Core Concepts in Ethereum

SHA-3 Hashing and RLP Encoding

At the heart of Ethereum’s data integrity and identification system lies cryptography and data serialization. Two fundamental technologies power these functions: SHA-3 hashing and Recursive Length Prefix (RLP) encoding.

SHA-3: Secure Hash Algorithm

Ethereum uses SHA-3 (Keccak-256) as its primary cryptographic hash function. Unlike SHA-1 or SHA-2, SHA-3 employs a different internal structure called the sponge construction, offering robust resistance against known cryptographic attacks. Every block header, transaction, and state is identified by a unique 32-byte (256-bit) hash derived using SHA-3.

The irreversible nature of hashing ensures that no original data can be reconstructed from its hash—making it ideal for verifying data integrity without exposing sensitive content.

RLP: Recursive Length Prefix Encoding

While SHA-3 provides data fingerprinting, RLP encoding enables efficient storage and transmission of complex, nested data structures. RLP serializes arbitrary byte arrays—including nested lists—into flat binary sequences. This makes it perfect for encoding Ethereum objects like transactions, blocks, and account states before they are hashed or stored.

👉 Discover how blockchain developers use secure hashing and encoding techniques in real-world applications.

Importantly, RLP is reversible, allowing encoded data to be accurately decoded back into its original structure. In practice, Ethereum computes an object's hash by applying SHA-3 to its RLP-encoded form—commonly referred to as RLP hash.

This combination ensures that:


Key Data Types: Hashes and Addresses

Ethereum defines several custom types to standardize critical identifiers across the network:

// common/types.go
const (
    HashLength  = 32      // 256 bits
    AddressLength = 20    // 160 bits
)
type Hash    [HashLength]byte
type Address [AddressLength]byte

Additionally, Ethereum leverages Go’s big.Int type to handle large integers such as balances, gas limits, and prices—ensuring precision even with extremely high values.


Understanding Gas and Ether

Two essential economic units govern operations within Ethereum:

Gas: The Unit of Computation

Every action on Ethereum—transferring funds, deploying a contract, or executing logic—consumes computational resources. To prevent abuse and ensure fair usage, Ethereum introduces Gas, a unit measuring resource consumption.

Each operation has a predefined gas cost:

Transactions specify:

This mechanism protects the network from infinite loops and denial-of-service attacks by capping execution costs.

Ether: The Native Cryptocurrency

Ether (ETH) is Ethereum’s native currency. It serves as the medium through which users pay for gas. When a transaction executes, the total fee is calculated as:

Transaction Fee = GasUsed × GasPrice

This fee compensates miners (or validators in proof-of-stake) for securing the network.

👉 Learn how gas optimization impacts transaction efficiency and cost savings.

Thus, Ether becomes a functional currency, enabling economic incentives while maintaining system stability.


Blocks: The Foundation of Blockchain

A blockchain is essentially a linked list of blocks. Each Block contains:

// core/types/block.go
type Block struct {
    header       *Header
    transactions Transactions // []*Transaction
    ...
}

The Header stores metadata such as:

Blocks are immutable once added. The first block—the Genesis Block—is hardcoded and has no parent.

Each block contains a list of transactions (transactions []*Transaction). These represent actions initiated by users or smart contracts.


Transaction Structure

A transaction encapsulates a user-initiated action:

// core/types/transaction.go
type txdata struct {
    AccountNonce uint64
    Price        *big.Int
    GasLimit     *big.Int
    Recipient    *common.Address
    Amount       *big.Int
    Payload      []byte
    V, R, S      *big.Int // Signature values
}

Key fields include:

Notably, the sender address is not explicitly stored—it's derived from the signature during validation.


How Transactions Are Executed

Transaction execution occurs in two layers: outside and inside the EVM.

Layer 1: Outside the EVM

Execution begins in StateProcessor.Process(), which iterates over all transactions in a block:

func (p *StateProcessor) Process(block *Block, statedb *StateDB, cfg vm.Config) {
    for _, tx := range block.Transactions() {
        receipt, _, err := ApplyTransaction(...)
        receipts = append(receipts, receipt)
    }
}

For each transaction:

  1. A Message object is created via tx.AsMessage(), which recovers the sender using ECDSA.
  2. The ApplyTransaction() function processes the message.
  3. A Receipt is generated post-execution.

What Is a Receipt?

A receipt records:

These receipts help light clients verify events without downloading full state data.


Gas Mechanics During Execution

The transaction lifecycle involves precise gas accounting:

  1. Buy Gas: Deduct GasLimit × GasPrice from sender.
  2. Intrinsic Gas Cost: Calculate base cost based on payload size and recipient.
  3. Execute in EVM: Run logic; consume gas dynamically.
  4. Refund Unused Gas: Return remaining gas to sender.
  5. Apply Refunds: Add bonus gas (for storage cleanup) to refund pool.
  6. Reward Miner: Pay miner (GasUsed + Refund) × GasPrice.

This system incentivizes efficient code while rewarding validators fairly.


Digital Signatures: Securing Transactions

Every transaction must be cryptographically signed using ECDSA (Elliptic Curve Digital Signature Algorithm) over the secp256k1 curve.

The signature ([R, S, V]) allows recovery of the sender’s public key—and thus their address—without revealing private keys.

Go-ethereum uses a Signer interface:

type Signer interface {
    Sender(tx *Transaction) (Address, error)
    Hash(tx *Transaction) Hash
}

This abstraction supports future signature schemes (e.g., EIP-155 replay protection).


Inside the Ethereum Virtual Machine (EVM)

The EVM executes transaction logic in isolation. It operates on:

Context and State Management

The EVM receives context from:

Transfers are implemented as:

func Transfer(db StateDB, sender, recipient Address, amount *big.Int) {
    db.SubBalance(sender, amount)
    db.AddBalance(recipient, amount)
}

Changes are not immediately committed—they’re cached in StateDB until the entire block is finalized.


Contract Creation and Execution

Contracts are executable objects within the EVM:

type Contract struct {
    CallerAddress Address
    self          ContractRef
    Code          []byte
    Input         []byte
    Gas           uint64
}

Two main execution paths:

When a contract is created:

  1. A new address is generated (based on sender + nonce).
  2. Initialization code runs and returns runtime bytecode.
  3. Runtime code is saved under the new address in StateDB.

Precompiled Contracts

Certain cryptographic operations are implemented natively for performance:

type PrecompiledContract interface {
    RequiredGas(input []byte) uint64
    Run(input []byte) ([]byte, error)
}

Examples include:

These bypass interpreter overhead, reducing gas costs significantly.


Interpreter: Running Smart Contract Code

Non-precompiled contracts are executed by the Interpreter, which processes opcodes sequentially:

func (in *Interpreter) Run(contract *Contract, input []byte) {
    pc := uint64(0)
    for pc < len(contract.Code) {
        op := contract.Code[pc]
        operation := jumpTable[op]
        operation.execute(&pc, in, contract)
    }
}

Over 140 opcodes support:

Special opcodes like LOG1 emit events stored in transaction receipts—enabling dApps to monitor activity off-chain.


Summary: Ethereum’s Architectural Strengths

Ethereum’s design combines security, flexibility, and economic incentives:

ConceptRole
GasPrevents spam; measures computational effort
BlocksImmutable containers of ordered transactions
TransactionsSigned messages triggering state changes
EVMSandboxed runtime for deterministic execution
ContractsSelf-executing logic with persistent storage

By integrating cryptographic primitives (SHA-3, ECDSA), efficient encoding (RLP), and a robust virtual machine model, Ethereum enables a trustless platform for innovation.


Frequently Asked Questions (FAQ)

Q: Why does Ethereum use SHA-3 instead of SHA-2?
A: Although SHA-2 remains secure, SHA-3 offers structural diversity through sponge construction, providing long-term resilience against potential cryptanalytic advances.

Q: How is the sender address recovered if it’s not stored in the transaction?
A: Using ECDSA’s mathematical properties, the public key—and thus the address—is derived from the signature (R, S, V) during validation.

Q: What happens if a transaction runs out of gas?
A: Execution halts immediately. State changes are reverted, but the gas fee is still charged to prevent network abuse.

Q: Can smart contracts modify their own code after deployment?
A: No. Contract bytecode is immutable. However, upgrade patterns (like proxy contracts) allow logic replacement via delegation.

Q: Why use RLP instead of JSON or Protocol Buffers?
A: RLP is simpler, deterministic, and supports nested structures without schemas—ideal for consensus-critical systems where consistency is paramount.

Q: How do logs improve blockchain usability?
A: Logs enable efficient indexing of events (e.g., token transfers). Applications can listen for specific topics without parsing every transaction.

👉 Explore how developers leverage EVM capabilities to build next-generation dApps.