Ethereum Transaction Structure, Execution, and Storage Explained

·

Ethereum is more than just a cryptocurrency—it’s a decentralized computing platform powered by smart contracts and secured through blockchain technology. At the heart of this ecosystem lies the transaction: the fundamental unit that drives value transfer, contract deployment, and on-chain interactions. Understanding how Ethereum transactions are structured, executed, and stored is essential for developers, validators, and blockchain enthusiasts alike.

This comprehensive guide dives into the core mechanics of Ethereum transactions—from their internal data structure to execution flow and persistent storage—offering technical clarity with practical insights.


Transaction Structure in Ethereum

At its foundation, every Ethereum transaction follows a strict format defined in the Go-Ethereum (Geth) source code under core/types/transaction.go. The primary struct is:

type Transaction struct {
    data txdata
    hash atomic.Value
    size atomic.Value
    from atomic.Value
}

Each field serves a specific purpose:

👉 Learn how real-world blockchain applications use transaction structures today.

Inside txdata: The Core Fields

The txdata struct encapsulates all critical transaction parameters:

type txdata struct {
    AccountNonce uint64      `json:"nonce"`
    Price        *big.Int    `json:"gasPrice"`
    GasLimit     uint64      `json:"gas"`
    Recipient    *common.Address `json:"to"`
    Amount       *big.Int    `json:"value"`
    Payload      []byte      `json:"input"`
    V, R, S      *big.Int    `json:"v", "r", "s"`
    Hash         *common.Hash `json:"hash,omitempty"`
}

Here’s what each field means:

Notably, the sender address is not explicitly stored—it's cryptographically derived from the signature using elliptic curve recovery (secp256k1), ensuring authenticity without bloating data.


Types of Ethereum Transactions

While Ethereum uses one unified transaction structure, they can be functionally categorized into three types based on intent.

1. Transfer Transactions

These involve simple Ether transfers between externally owned accounts (EOAs). Minimal fields are required:

Example via web3.js:

web3.eth.sendTransaction({
    from: '0xSender',
    to: '0xRecipient',
    value: '1000000000000000000' // 1 ETH
});

2. Contract Creation Transactions

When deploying a smart contract:

Upon execution, EVM creates a new contract account with a deterministic address (derived from sender and nonce).

3. Contract Execution (Invocation) Transactions

To interact with an existing smart contract:

For example, calling transfer(address,uint256) requires encoding the method ID and arguments using Ethereum’s Contract ABI specification. Tools like Web3.js or ethers.js automate this process.

💡 A single transaction can include both value (sending ETH) and data (invoking logic), enabling powerful patterns like payable function calls.

Creating a Transaction: Required Inputs

When submitting a transaction via JSON-RPC (e.g., using MetaMask or Infura), nodes expect structured input defined in internal/ethapi/api.go:

type SendTxArgs struct {
    From   common.Address
    To     *common.Address
    Gas    *hexutil.Uint64
    GasPrice *hexutil.Big
    Value  *hexutil.Big
    Nonce  *hexutil.Uint64
    Data   *hexutil.Bytes
    Input  *hexutil.Bytes
}

All combinations of value and data are valid:

📌 Maximum data size per transaction: 44 KB


How Transactions Are Executed

Ethereum processes transactions in two layers: outside and inside the EVM.

Layer 1: Outside the EVM

Execution begins in core/state_processor.go via Process()—a loop that applies each transaction in a block using ApplyTransaction().

Key steps:

  1. Convert transaction into a Message object.
  2. Instantiate an EVM instance.
  3. Deduct initial gas fee (GasLimit × GasPrice) from sender.
  4. Compute intrinsic gas (base cost + payload cost).
  5. Execute via EVM (Create() for contracts, Call() for invocations).
  6. Generate receipt with logs, status, and gas used.

Each transaction produces a Receipt, which includes:

The GasPool tracks available gas per block, ensuring no overflow.

Layer 2: Inside the EVM

Once inside, EVM handles:

Smart contract code (Payload) is executed instruction-by-instruction. State changes are not immediate—they’re cached in StateDB and only committed upon successful block validation.

Refunds are issued for:

Miners receive rewards based on consumed gas × gas price.


Where Are Transactions Stored?

After execution, transactions must be persistently stored for auditability and synchronization.

Storage Mechanism

Defined in core/database_util.go, the function WriteTXLookupEntries handles indexing:

This allows fast retrieval of any transaction by hash—a crucial feature for explorers and light clients.

Calls originate from:

👉 See how leading platforms securely manage transaction storage and retrieval.


Frequently Asked Questions (FAQ)

Q: How is the sender address recovered without being stored?

The sender's address is derived from the digital signature (V, R, S) using elliptic curve cryptography (secp256k1). The public key is recovered from the signature and hashed to produce the Ethereum address.

Q: What happens if a transaction runs out of gas?

It fails mid-execution. All state changes are reverted, but the sender still pays for gas consumed. This prevents spam and ensures network fairness.

Q: Can a transaction have zero gas price?

Yes, in EIP-1559 blocks, priority fees can be zero if miners accept base fee-only transactions. However, zero-gas-price transactions are typically ignored unless processed privately.

Q: Why do we need receipts and logs?

Receipts confirm execution outcomes. Logs enable off-chain services (like Etherscan) to track events (e.g., token transfers) efficiently using bloom filters.

Q: Is there a limit on transaction data size?

Yes—each transaction can carry up to 44 KB of data. Larger payloads increase gas costs significantly due to non-zero byte fees.

Q: How are contract addresses determined?

For newly created contracts, the address is computed as:

keccak256(rlp.encode(sender_address, nonce))[12:]

This ensures uniqueness and predictability.


Final Thoughts

Understanding Ethereum’s transaction lifecycle—from structure to execution and storage—reveals the elegance behind its design. Every transaction is a carefully validated operation backed by cryptography, economic incentives, and deterministic computation.

Whether you're building dApps, auditing contracts, or exploring consensus mechanisms, mastering these fundamentals empowers deeper engagement with the decentralized web.

👉 Start exploring Ethereum development tools and APIs now.