Understanding Ethereum Accounts and State: A Deep Dive into Go-Ethereum

·

Overview

Ethereum is often described as a transaction-based state machine, fundamentally different from Bitcoin's UTXO model. This system comprises multiple accounts, similar to bank accounts, where the state reflects an account's value at any given moment. In Ethereum, the state is represented by a fundamental data structure called a StateObject. When a StateObject's value changes, we refer to it as a state transition. Account data updates, deletions, or creations triggered by transaction executions cause these state transitions, moving the StateObject from one state to another.

In practical terms, the StateObject instance in Ethereum is an Account. The state specifically refers to the data contained within an account at a particular time.

Accounts are the basic entities participating in on-chain transactions, serving as both initiators and receivers. Ethereum currently supports two primary account types: Externally Owned Accounts (EOAs) and Contract Accounts.

Externally Owned Accounts (EOAs)

Externally Owned Accounts are controlled directly by users via private keys. These accounts are responsible for signing and initiating transactions, ensuring users maintain control over their account data through cryptographic security.

Contract Accounts

Contract Accounts, often called smart contracts, are created by EOAs through transactions. These accounts store immutable, Turing-complete code segments and persistent data variables. Typically written in Solidity, this code provides API interface functions accessible by constructing transactions or via node RPC services. This framework forms the foundation of the current DApp ecosystem.

Contract functions enable computations, queries, and modifications of persistent data. Contrary to popular belief, the phrase "data recorded on the blockchain is immutable" is not entirely accurate. While a smart contract's code logic is indeed unchangeable once deployed, its persistent data variables can be modified (Create, Update, Read, Delete) by calling the contract's functions, following the defined logic.

Contract functions are categorized into two types: read-only and write functions. Querying data without modification requires only a call to a read-only function, achievable via direct RPC calls to a node. However, modifying data necessitates constructing a transaction to invoke a write function. Each transaction can call one write function in one contract. Complex on-chain logic requires modularizing write functions to incorporate more operations.

StateObject, Account, and Contract Structures

Core Components

In the Go-Ethereum source code, both account types are defined by the stateObject数据结构, located in core/state/state_object.go. This structure is internal to the state package, indicated by its lowercase naming convention in Go.

The key components of a stateObject include:

The StateAccount Structure

The data field in a stateObject is a types.StateAccount struct, defined in core/types/state_account.go. It contains the essential consensus-related account data:

Account Security and Generation

Who Controls Your Account?

The common assertion that "only you control your cryptocurrency assets on the blockchain" is largely accurate. Native tokens like Ether cannot be transferred without a transaction signed by the account's private key. This security relies on the strength of Ethereum's cryptographic algorithms, making it computationally infeasible to derive the private key within a reasonable time frame.

However, this guarantee has nuances. First, it depends on the continued resistance of cryptographic tools (like ECDSA) to attacks, a concern addressed by research into quantum-resistant cryptography. Second, many assets like ERC-20 tokens or NFTs (ERC-721) are not native tokens but data entries within smart contracts. The security of these assets depends entirely on the contract's code security. Vulnerable contracts can be exploited to drain tokens, even if the user's private key remains secure. 👉 Explore secure development strategies

Generating an EOA

Creating an EOA involves a local generation process and an on-chain registration. Wallet tools like MetaMask handle local creation, while on-chain registration is managed by the StateDB module.

Locally, the NewAccount function in accounts/keystore/keystore.go initiates creation. A passphrase encrypts the local keystore file but isn't involved in cryptographic key generation. The core process involves:

  1. Private Key Generation: Using ecdsa.GenerateKey, a cryptographically secure random 32-byte (256-bit) private key is generated.
  2. Public Key Derivation: The private key is used to compute its corresponding public key on the secp256k1 elliptic curve.
  3. Address Calculation: The Ethereum address is derived by taking the last 20 bytes of the Keccak256 hash of the public key.

Signatures and Verification

Digital signatures prove ownership and authorize transactions. The process uses ECDSA with the secp256k1 curve:

Deep Dive into Contract Storage

Storage Layer Structure

A key difference between EOAs and Contracts is the storage layer. Contracts maintain an independent storage space for persistent variables, built from sequential slots. Each slot holds 256 bits (32 bytes) of data. The storage layer is indexed like a massive array, with addresses from 0x00...00 to 0xFF...FF, allowing for a theoretical maximum of 2²⁵⁶ slots.

An MPT (Merkle Patricia Trie) indexes these slots. The root hash of this storage trie is stored in the Root field of the account's StateAccount. Changes to storage affect this root, eventually propagating to the world state root. Storage is accessed and modified by the EVM using dedicated opcodes SLOAD and SSTORE.

Storage Examples and Layout

Solidity variables are stored based on type and declaration order.

Frequently Asked Questions

What is the fundamental difference between Bitcoin's UTXO model and Ethereum's Account/State model?

Bitcoin tracks unspent transaction outputs (UTXOs), which are chunks of currency. Ethereum uses an account-based model where balances are stored directly in account states, similar to bank accounts. This simplifies transaction design and enables smart contract state persistence.

How is my Ethereum account's security guaranteed?

Security is based on cryptographic principles. Your private key, which you control, is required to sign transactions. Without it, spending funds is computationally impossible due to the strength of the Elliptic Curve Digital Signature Algorithm (ECDSA) used. However, assets stored in smart contracts depend on the contract's code security, not just your private key.

What is the difference between an EOA and a contract account?

An EOA is controlled by a private key and has no associated code. It can send transactions. A contract account has associated code (smart contract) and is controlled by its logic. It cannot initiate transactions itself but can execute code in response to transactions sent to it.

How are variables stored inside a smart contract?

Persistent variables are stored in the contract's storage—a key-value store where each key and value is 32 bytes. Fixed-size variables are stored sequentially based on declaration order. Smaller types may be packed into a single slot. Complex types like mappings and arrays use more complex, hashed storage layouts to avoid collisions.

Why might using a uint256 be more gas-efficient than a uint8?

The EVM operates on 32-byte words. If a uint8 is stored alone, it still occupies a full 32-byte slot. If multiple small variables are packed, reading or writing one requires reading and writing the entire 32-byte slot, which can cost more gas than operating on a naturally aligned 32-byte value.

Can a deployed smart contract's code be changed?

No. The bytecode of a deployed contract is immutable and its hash (CodeHash) is fixed. This ensures verifiability and trustlessness. However, the data stored by the contract can be changed by calling its functions, following the immutable rules defined in the code. Patterns like proxy contracts can create upgradeability illusions by delegating calls to changeable logic contracts.