Section VII: Ethereum Framework
June 3, 2026
In the last lesson we traced how transactions flow through the network. Now we look at what those transactions actually execute.
A smart contract is a program and its state at an address on the blockchain.
Its functions run automatically when a transaction or call reaches that contract.
Different from ‘legal contracts’: execution is automatic and deterministic, not interpretive.
We will briefly survey non-Ethereum smart contract models to situate the landscape.
| Feature | Bitcoin Script | Solidity (Ethereum) |
|---|---|---|
| Purpose | Defines conditions to spend a specific UTXO. | Defines programs that manage state and logic. |
| Language Type | Stack-based, declarative, non–Turing complete. | High-level, imperative, Turing complete. |
| State Model | Stateless: no memory of prior executions. | Stateful: contracts maintain persistent storage between calls. |
| Execution Context | Runs only when spending an output. | Invoked via transactions or calls; read/write storage, call contracts. |
| Control Flow | No loops or recursion; limited branching. | Full control flow (loops, branching, function calls, libraries). |
| Resource Control | Bounded by design. | Bounded by gas metering; execution stops when gas runs out. |
| Security Model | Simplicity and determinism reduce attack surface. | Expressiveness increases flexibility and vulnerability (reentrancy, etc.). |
msg.sender, msg.value, available gas, calldata (function inputs), block context, etc.
msg.sender is the immediate caller, not necessarily the original user. This matters for access control.Deployment happens in a short sequence:
initcode).The contract address is derived deterministically from the deployment rule in use.
Source-code verification on explorers is separate from deployment.
msg.sender and msg.value are per-frame; gas forwarding is explicit.
msg.sender, not the original user. This is critical for access control.Call frame: the EVM’s execution context for a single call. Each frame has its own msg.sender, msg.value, gas budget, memory, and return data. A revert undoes state changes within that frame only.
Each section in a Solidity file explains its behavior:
pragma solidity ... sets compiler expectations, so readers know which language rules and safety checks apply.contract Name { ... } identifies the unit of code and state that will be deployed at one address.Solidity groups types into value types and reference types. Value types are copied when assigned or passed around, so they do not use a data-location label like storage, memory, or calldata.
| Type | Represents | Uses |
|---|---|---|
uint / int |
Signed and unsigned integers for arithmetic | Balances, counters, timestamps, and range checks |
bool |
true / false values |
Flags, checks, and branching logic |
address / address payable |
Account identifiers; payable can receive ETH |
Ownership, recipients, and access-control decisions |
enum |
A limited set of named states | Helps constrain contract state to valid options |
Literal suffixes like 1 ether and time units are syntax conveniences, not a separate datatype family.
Reference types types refer to larger data structures–their behavior depends on where the data lives: storage, memory, or calldata.
| Type | Represents | Uses |
|---|---|---|
| Arrays | Ordered collections of values, fixed-size or dynamic | Lists of items, histories, and batched data |
bytes / string |
Dynamic byte arrays and text data | Raw data/metadata |
struct |
A custom grouped record with multiple fields | Models richer state such as users, proposals, or assets |
mapping(Key => Value) |
Key-value lookup table | Balances, permissions, and registries |
Reference types often need an explicit data location, and copying them can change both gas cost and behavior.
These are function-level modifiers. They tell readers who can call a function, whether it may read or change state, and whether it may receive ETH.
public: callable from inside the contract and from outsideexternal: callable from outside the contractinternal: callable only inside the contract or derived contractsprivate: callable only inside the same contractview: may read state, but not write itpure: does not read or write contract statepayable means the function can receive ETH with the call.
nonpayable is the contrasting default: attached ETH causes the call to revert.external functions can read it without making a copystored is a storage variable; x exists only for the duration of the call.pragma solidity ^0.8.26;
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, "not minter");
balances[receiver] += amount;
}minter and balances live in storage.mint restricts access to minter via require. error InsufficientBalance(uint requested, uint available);
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);
}
}require check stops the transfer unless the sender has enough balance.indexed) create searchable topics; non-indexed fields go into the data blob.Topic: a 32-byte indexed field in a log entry. Topic 0 is the keccak-256 hash of the event signature (e.g., Transfer(address,address,uint256)); topics 1–3 hold indexed parameter values. Clients filter logs by topic without scanning the full data blob.
keccak256("name(types)")[:4]receive handles plain ETH transfers; fallback handles unknown selectors or bad calldata.withdraw() before zeroing balance.The fix is disciplined ordering:
require)A reentrant call now sees zero balance and fails the check. The attack loop from the previous slide is broken.
Some contracts add a second protection: a reentry lock. That pattern blocks the same function from being entered again before the first call finishes.
CEI pattern:
ReentrancyGuard (mutex):
withdraw() before balance changed.delegatecall executes the logic contract’s code in the proxy’s storage context.
Without proxy (immutable)
With proxy (upgradeable)
A smart contract is code + persistent state that executes deterministically on every node.
Ethereum’s EVM provides the execution environment: accounts, gas metering, runtime bytecode, and a shared state trie.
Solidity source is compiled into bytecode for deployment; after creation, the contract account stores runtime bytecode on-chain.
External calls transfer control to untrusted code; the Checks-Effects-Interactions pattern and reentrancy guards are the primary defenses.
Contracts cannot reach outside the chain; oracles and VRFs bridge that gap, each with their own trust assumptions.
Immutability is the default; proxy patterns trade it for upgradeability at the cost of added governance complexity.
Next lesson: we apply these concepts to digital assets, tokenization, and NFTs (ERC-20, ERC-721, ERC-1155).

Smart Contracts: From Concept to Ethereum — Army Cyber Institute — June 3, 2026