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:
data: Contains the actual transaction details.hash: Stores the Keccak256 hash of the RLP-encoded transaction data (computed lazily).size: Caches the size of the transaction.from: Holds the sender's address, derived from the digital signature.
👉 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:
- Nonce: Ensures transaction order and prevents replay attacks.
- GasPrice & GasLimit: Define cost and computational limits.
- Recipient: Target address; if
nil, it triggers contract creation. - Amount: Value transferred in wei (1 ETH = 10¹⁸ wei).
- Payload (Data): Encoded function calls or initialization code for contracts.
- V, R, S: Components of the ECDSA digital signature used to recover the sender.
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:
to: Recipient addressvalue: Amount in wei
Example via web3.js:
web3.eth.sendTransaction({
from: '0xSender',
to: '0xRecipient',
value: '1000000000000000000' // 1 ETH
});2. Contract Creation Transactions
When deploying a smart contract:
tofield is omitted (nil)datacontains compiled bytecode (including constructor arguments)
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:
to: Contract addressdata: ABI-encoded function selector and parameters
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 bothvalue(sending ETH) anddata(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:
- Only
value: Simple payment - Only
data: Smart contract interaction - Both: Payable function call
- Neither: Gas-consuming noop (rare but 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:
- Convert transaction into a
Messageobject. - Instantiate an EVM instance.
- Deduct initial gas fee (
GasLimit × GasPrice) from sender. - Compute intrinsic gas (base cost + payload cost).
- Execute via EVM (
Create()for contracts,Call()for invocations). - Generate receipt with logs, status, and gas used.
Each transaction produces a Receipt, which includes:
PostState: RLP hash of state after execution.Logs: Events emitted during execution (used by indexers).Bloom: Bloom filter for efficient log querying.
The GasPool tracks available gas per block, ensuring no overflow.
Layer 2: Inside the EVM
Once inside, EVM handles:
- Native transfers via
Context.Transfer() - Contract creation or method execution via interpreter
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:
- Unused gas
- Certain state-clearing operations (e.g., deleting storage)
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:
- Key: Transaction hash prefixed with lookup key.
Value: RLP-encoded
txLookupEntrycontaining:- Block hash
- Block number
- Transaction index within the block
This allows fast retrieval of any transaction by hash—a crucial feature for explorers and light clients.
Calls originate from:
WriteBlockAndState()incore/blockchain.go- Invoked during mining (
miner/worker.go)
👉 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.