Why smart-contract platforms use a stack-based VM
A stack-based virtual machine keeps its working data on a simple last-in-first-out stack instead of named registers. This makes the instruction set tiny and uniform: almost every opcode just pops its operands off the top of the stack and pushes its result back on. That simplicity is exactly what a decentralized network needs. Thousands of independent nodes must execute the same bytecode and land on the identical final state, byte for byte, with no ambiguity about which register held what. A stack machine has no hidden register file to disagree about, no compiler-specific calling convention, and no undefined behavior — the stack's contents at any instruction are fully determined by the sequence of opcodes executed so far. This determinism is what lets every node independently re-run a transaction and verify the result rather than trusting a single party's output.
How opcodes push and pop values step by step
Execution proceeds one opcode at a time from a program counter that advances after each instruction. PUSH opcodes place a literal constant on top of the stack. Arithmetic opcodes like ADD or MUL pop exactly two values off the top, compute a result, and push that single result back — net effect: the stack shrinks by one item. Consider PUSH 3, PUSH 5, ADD: after the two pushes the stack holds [3, 5] with 5 on top; ADD pops both, computes 3 + 5, and pushes 8, leaving the stack as [8]. DUP and SWAP opcodes rearrange existing stack items without touching storage at all. Because each opcode's effect on the stack is fixed and context-free, a node can verify correctness just by simulating the same sequence — there is no branch prediction or speculative execution to reconcile between machines.
Storage versus the stack: persistent state
The stack is transient — it exists only for the duration of one execution and is discarded the moment the call finishes. Contract storage is the opposite: a persistent key-value map that survives between transactions and is part of the blockchain's permanent state, replicated identically on every node. Reading storage (SLOAD) pushes the value at a given key onto the stack; writing storage (SSTORE) pops a key and a value off the stack and commits that value into the persistent slot. A token transfer, for example, computes a sender's new balance on the stack, then SSTOREs it into that account's storage slot, and does the same for the recipient — two small stack computations followed by two permanent writes. Because storage writes are deterministic functions of the input transaction, every node ends up with an identical updated state.
Why gas and step limits bound every execution
A general-purpose stack machine could in principle loop forever, which is unacceptable when every node in a network must finish executing every transaction. To guarantee execution always halts, each opcode is assigned a fixed computational cost, and the caller supplies a maximum budget upfront. The virtual machine decrements that budget after every instruction and immediately stops execution if it hits zero, reverting any partial state changes. This turns an otherwise undecidable halting problem into a bounded one: no program can run longer than its prepaid budget allows. It also keeps the cost of validating a transaction roughly comparable across nodes with different hardware, since the metered unit is instruction count and complexity, not wall-clock time.
Frequently asked questions
What does 'stack-based' actually mean for a virtual machine?
It means the VM's primary working memory is a last-in-first-out stack rather than a set of named registers. Most instructions take their operands implicitly from the top of the stack and push their result back onto it, rather than specifying source and destination registers explicitly. This keeps the instruction encoding compact and the interpreter simple: the VM only needs to track a single pointer to the top of the stack, plus the program counter. Stack machines are easier to implement correctly and easier to verify across many independent implementations, which matters when a network of nodes must all execute identical bytecode and agree on the outcome without any coordination beyond the shared instruction sequence itself.
Why does execution need to be deterministic across every node?
A decentralized network has no single authority whose computation is simply trusted — instead, every participating node independently re-executes each transaction's bytecode and checks that it arrives at the same resulting state. If execution depended on floating-point rounding, thread scheduling, wall-clock time, or any other machine-specific factor, different nodes could compute different results from identical input, breaking consensus. A stack-based VM avoids this by using only exact integer arithmetic on a well-defined stack, with a fixed opcode set whose behavior is specified precisely enough that any correct implementation, on any hardware, produces byte-identical output for the same bytecode and inputs.
How is contract storage different from the execution stack?
The stack is temporary scratch space that exists only while one call is executing; it is created empty at the start of a call and discarded entirely when the call returns. Storage is a persistent key-value map attached permanently to a contract account, and it survives across separate transactions and calls — it is part of the durable chain state every node maintains. Opcodes move data between the two: SLOAD copies a value from a storage key onto the stack for use in computation, and SSTORE takes a value that has been computed on the stack and commits it into a storage key, making the change permanent and visible to future executions.
Try it live
Everything above runs in your browser — open Stack Machine: How Smart Contracts Execute and change the parameters while it is running. Nothing is installed, nothing is uploaded, the whole model lives in one tab.
▶ Open Stack Machine: How Smart Contracts Execute simulation