The phrase "smart contract" makes a program sound like an agreement that has learned to enforce itself. The difficulty is that a program enforces its operations. People arrive with an interpretation of what those operations are supposed to mean. The two can diverge without the machine becoming confused.

Vitalik Buterin's June discussion of contract security puts several different failures beside the DAO: reentrancy, unexpectedly public information, resource limits and naming mistakes. It is a useful list because it resists the idea that one language feature or one careful review will remove every class of problem.

An external call changes who is in control

Consider an intentionally simplified withdrawal routine. It checks a balance, sends funds to a recipient, then clears the balance. A reader may treat the send as the middle line of an uninterrupted sequence. If sending invokes recipient-controlled code, it is also a transfer of control.

The recipient may call back before the original routine reaches its final bookkeeping. The second invocation observes state that the first invocation intended to change later. The programmer has reasoned about a completed operation; the program has exposed an intermediate state.

A contract calls an external recipient, which calls back before the original state update finishes.

A generic reentrancy pattern. The callback reaches state that the first call has not yet updated; this is not the exact source of a particular exploit.

Real implementations involve more state, more entry points and assumptions about failure than this simplified example. Moving one assignment is not a substitute for examining those relationships together.

The useful design question is: what must remain true whenever another party can run code? That question turns attention from individual functions to invariants across the system.

Public execution changes ordinary assumptions

A random seed stored where participants can read it is not a secret because the interface omits a "show seed" button. A game that exposes one player's choice before the other player commits has a protocol problem even if its arithmetic is correct.

These are familiar lessons from adversarial software, made sharper by an environment in which code may directly control value. The machine can faithfully execute an arrangement that a participant has a strong incentive to exploit.

Resource limits belong in the same analysis. A process that requires visiting every participant may work with a small test group and become impossible to complete as the group grows. A valid state can still be a state from which the intended next operation cannot finish.

Define the boundary of the promise

I would want a contract design to state who can call it, what information is observable, which operations invoke outside code, and how it behaves when those operations fail. Tests can then challenge explicit claims rather than simply replaying the expected happy path.

Formal reasoning, better tools and simpler interfaces each help with different parts of that work. None converts an unstated intention into an executable guarantee. Immutability makes the distinction more consequential: preserving a mistake perfectly is still preserving a mistake.