Solidity Programming Language and Ethereum Virtual Machine Architecture
Overview and Core Characteristics of Solidity
Execution Environment: Smart contracts written in Solidity run on the Ethereum Virtual Machine (EVM).
Language Inspirations: Solidity design is heavily inspired by C++, Python, and JavaScript.
Type System: Solidity is a statically typed programming language.
Supported Features:
Inheritance across contracts.
Complex User-Defined Types (UDTs).
Primary Smart Contract Applications:
Voting systems.
Multi-signature (multi-sig) wallets.
Blind auctions.
Crowdfunding platforms.
Solidity Contract Examples and Code Mechanics
SimpleStorage Contract Implementation:
License identifier:
// SPDX-License-Identifier: GPL-3.0Compiler version pragma:
pragma solidity >=0.4.16 <0.9.0;Contract Definition:
solidity contract SimpleStorage { uint storedData; function set(uint x) public { storedData = x; } function get() public view returns (uint) { return storedData; } } Deployment Characteristics: A deployed contract executes at a specific address on the EVM.
State Variables:
storedDatais an unsigned integer state variable that is 256 bits long.Functions:
set(uint x): Public setter function modifyingstoredData.get(): Public getter function markedviewreturning auintvalue.
Coin / Cryptocurrency Contract Implementation:
Contract Definition and Logic: ```solidity error InsufficientBalance(uint requested, uint available);
contract Coin { address public minter; mapping(address => uint) public balances;
event Sent(address from, address to, uint amount); constructor() { minter = msg.sender; } function mint(address receiver, uint amount) public { require(msg.sender == minter); balances[receiver] += amount; } function send(address receiver, uint amount) public { require(amount <= balances[msg.sender], InsufficientBalance(amount, balances[msg.sender])); balances[msg.sender] -= amount; balances[receiver] += amount; emit Sent(msg.sender, receiver, amount); }} ```
Error Declarations: Custom errors (such as
InsufficientBalance) provide precise structural information to function callers regarding operational failure reasons.State Variables and Visibility:
minter: Address variable markedpublic, making it accessible from other contracts.balances: Public mapping from anaddressto auintbalance.Events:
event Sentallows off-chain clients to monitor and react to specific state changes.Constructor: Executes exactly once when the contract is initially created on the EVM, setting
minter = msg.sender.Coin Minting:
minttransfers newly created coins to a target address; restricted to execution by the contract creator (minter).Coin Transfers:
sendtransfers existing coins from the function caller (msg.sender) to a target address, enforcing balance limits viarequireand emitting aSentevent upon success.
Data Types, Control Flow, and Client Interaction
Address Data Type:
Represented as a 160-bit value.
Arithmetic operations are explicitly prohibited on address types.
Primary Uses:
Storing a contract address.
Storing a hash of an Externally Owned Account (EOA) public key.
Mapping Data Type:
Functions similarly to a virtual hash table without key collisions.
All possible key hashes are virtually created and mapped to an initial default value of zero.
Key-value iteration is impossible directly; contract logic must maintain separate tracking lists if key iteration is needed.
Events and Client-Side Listeners:
Events must be explicitly declared before being emitted.
Outside clients listen to emitted events via off-chain libraries such as
web3.jsorviem.TypeScript Listener Pattern:
typescript Coin.Sent().watch({}, '', function(error, result) { if (!error) { console.log("Coin transfer: " + result.args.amount + " coins were sent from " + result.args.from + " to " + result.args.to + "."); console.log("Balances now: " + "Sender: " + Coin.balances.call(result.args.from) + "Receiver: " + Coin.balances.call(result.args.to)); } })
Condition Verification and Exceptions:
requirestatements impose pre-execution conditions on function logic (analogous tocassertin C++).Failing a
requirecondition causes transaction execution to revert, throwing an exception where the sender loses spent gas.requirewith custom error payloads sends detailed context back to clients.Unchecked integer arithmetic overflow also triggers automatic transaction reverts.
Global Environmental Variables:
Key global namespace variables include
msg,tx, andblock.msg.sender: Specifies theaddressthat directly invoked the currently executing contract function.
EVM Architecture, Accounts, and Transaction Flow
EVM Account Types:
Externally Owned Accounts (EOAs): Controlled by private key pairs.
Contract Accounts: Controlled by smart contract bytecode.
Account Structure: Both account types contain:
Storage (a key-value map from 256-bit words to 256-bit words).
Balance denominated in Wei, where .
Transaction Execution Flow:
Transactions originate from a sender and target a recipient address (target address can be empty).
Transactions include a binary data payload and Ether value.
Specified Target: If the target is a specified contract, the binary payload is executed as calldata.
Empty Target (Contract Creation):
Triggers creation of a new contract.
The EVM computes the new contract address using the sender's address and the sender's transaction count (nonce).
Assumes the transaction payload is initial EVM bytecode and executes it.
Stores the output resulting from bytecode execution as contract runtime code at the newly computed address.
Safety Constraint: External calls into a contract must not occur until its constructor completes execution.
EVM Gas Economics
Gas Payment Responsibility:
tx.originmust pay sufficient gas upfront for transaction creation.Gas Depletion Rules: Gas is consumed sequentially during execution according to pre-determined opcode cost rules.
Out-of-Gas Exceptions:
If remaining gas drops below zero (becomes negative), an out-of-gas exception is thrown.
Execution is terminated immediately.
All state changes caused by the transaction revert.
The transaction sender (
tx.origin) forfeits all spent gas.
Gas Price and Upfront Capital:
tx.originspecifiesgas_priceand pays upfront to the EVM full node executor.Unused excess gas is refunded to
tx.originupon successful transaction completion.Setting a
gas_pricevalue below market thresholds risks rejection or non-inclusion by network miners.
EVM Data Storage Regions
Storage Region (
storage):Key-value store mapping 256-bit words to 256-bit words.
Non-enumerated data structure.
Operation costs: Extremely costly to read, and significantly more expensive to create or update.
Guideline: Minimize storage usage exclusively to essential runtime state variables.
Isolation: A contract cannot access the storage area of another account.
Transient Storage Region:
Automatically resets to default zero values at the end of every transaction.
Values persist only across inner function calls originating from the primary transaction call.
Subsequent transactions cannot access transient storage data from prior transactions.
Gas cost is substantially lower than standard
storageoperations.
Memory Region:
Linear and byte-addressable workspace.
Supports reads up to 256 bits and writes of 8 bits or 256 bits.
Instantiation: Every external message call receives a freshly cleared memory instance.
Expansion Mechanics: Memory expands by a 256-bit word whenever an unallocated memory word is accessed (for read or write).
Expansion Cost: Gas cost grows quadratically relative to total memory length utilized.
Stack Region:
Execution workspace where the EVM performs all computational processing.
Stack Capacity: Maximum stack limit of 1024 elements.
Word Size: Each stack element is 256 bits wide.
Permissible Operations:
Copying any element from the top 16 positions to the top of the stack.
Swapping any element in the top 16 positions with the top element.
Standard operations pop one, two, or more elements and push computation results back onto the stack.
Stack values can be moved directly to memory or storage.
EVM Calldata, Returndata, and Code Memory Regions
Calldata Region:
Read-only payload data supplied within a smart contract transaction.
Formats: Constructor bytecode during deployment, or function parameter values during external method calls.
Encoding: First stored in ABI-encoded format, subsequently decoded into target function variables.
Decoding Behavior:
Parameters defined with the
memorykeyword are eagerly decoded upon entering the function.Parameters defined with the
calldatakeyword are lazily decoded at the specific location of their first use.Value types and storage pointers are loaded directly onto the stack.
Returndata Region:
Transient location holding ABI-encoded return values produced by contract function calls.
Code Region:
Dedicated region where EVM instruction opcodes of a smart contract are permanently stored.
Opcodes are sequentially read, interpreted, and executed by the EVM.
Stores
immutableandconstantstate values.References to
immutablevariables are replaced directly with literal values at runtime.Constant expressions are inlined directly at all reference points during compilation.
EVM Instruction Set:
Designed to ensure strict determinism to prevent execution inconsistencies that lead to consensus failures across nodes.
Operates on 256-bit words, byte arrays, or memory slices.
Supports arithmetic, bitwise, logical, relational, conditional jump, and unconditional jump operators.
Enables reading execution block properties, including block number and block timestamp.
Message Calls, Interoperability, and Execution Contexts
Message Call Mechanics:
Mechanism allowing contracts to call methods in other contracts or transfer Ether to EOAs.
Characteristics: Possesses source, target, data payload, Ether value, gas allocation, and return data.
Hierarchy: Top-level transaction creates the initial message call, which can spawn nested inner message calls.
Gas Forwarding: Contracts forward a portion of remaining gas to inner calls, capped at a maximum of of current available gas while retaining the remainder.
Inner Execution Context:
Receives a freshly cleared memory instance.
Accesses payload via the calldata area.
Writes output into caller-preallocated memory as returndata.
Message calls execute fully synchronously.
Depth Limits: Capped at a maximum theoretical depth of 1024. Due to the gas forwarding limit, practical execution depth limits out at slightly less than 1000. Iterative loops are strongly preferred over recursive calls for iterations surpassing 1000.
Inner Call Exception Handling:
Failures (such as running out of gas) place an error code onto the stack.
Calling contracts must check error results and raise explicit exceptions to cause errors to bubble up the call stack.
Delegate Calls and Libraries:
Target address code is executed within the context (address, storage, and balance) of the calling contract.
Context Persistence:
msg.senderandmsg.valueremain unchanged during execution.Functionality: Enables contracts to dynamically load code from external addresses at runtime while operating on the host contract's state.
Primary Use Case: Formulates the foundational mechanism for Solidity libraries.
Event Logging, Contract Lifecycle, and Pre-compiles
Log Mechanics:
Log structures implement Solidity events, indexed partially via bloom filters mapped up to the block level.
Contract Access: Smart contracts generate log records but are strictly prohibited from reading log data post-creation.
External Access: Searchable cryptographically by light nodes and external client software off-chain.
Contract Instantiation (
CREATE):Smart contracts can create child contracts during runtime.
EVM processes creation payload and writes the resulting output as code, returning the newly generated contract address to the parent contract's stack.
Contract Deactivation and Self-Destruct:
selfdestructOperation: Historical method for removing contract code and storage state from the active EVM state.Ether Handling: Remaining Ether balance at the self-destructed address is forcefully transferred to a specified target address.
Historical Records: Bytecode remains permanently recorded in historical blockchain blocks.
Risks: Sending Ether to a self-destructed contract results in permanent loss of funds.
Deprecation Notice:
selfdestructis officially deprecated as of Solidity 0.8.18 and must not be used in newly developed smart contracts.Modern Deactivation Pattern: Smart contracts should be disabled by altering internal state flags to cause all functions to revert. Reverting returns incoming Ether immediately and renders the contract unusable.
Pre-compiled Contracts:
Native specialized EVM contracts residing at fixed address ranges
0x01through0x0a(with address range0x0001through0xffffreserved).Implemented directly within the EVM execution environment with predefined gas cost algorithms.