@@ -85,11 +85,13 @@ library LibMigrationRegistry {
8585
8686 /// Reverts unless the pinned registry address holds the pinned code.
8787 ///
88- /// Both entry points check, and they check the same way, because both are
89- /// worse than useless against unknown code: a read would branch a test on
90- /// whatever that code returned, and a write would record a migration
88+ /// All three entry points check, and they check the same way, because each
89+ /// is worse than useless against unknown code: `applied` would branch a
90+ /// test on whatever timestamp that code returned, `head` would hand back a
91+ /// value that is not a head, and `applyMigration` would record a migration
9192 /// somewhere nothing will ever read it. The check is one function so the
92- /// two cannot drift into checking different things.
93+ /// three cannot drift into checking different things, and an entry point
94+ /// added later has one place to call rather than a rule to remember.
9395 function checkCodeHash () internal view {
9496 bytes32 actualCodeHash = LibMigrationRegistryDeploy.MIGRATION_REGISTRY_DEPLOYED_ADDRESS.codehash;
9597 if (actualCodeHash != LibMigrationRegistryDeploy.MIGRATION_REGISTRY_DEPLOYED_CODEHASH) {
@@ -103,11 +105,13 @@ library LibMigrationRegistry {
103105 ///
104106 /// Verifies the registry's code hash before reading, so a chain where the
105107 /// registry is absent, or where something else occupies its address, is a
106- /// loud revert rather than a call into unknown code. That distinction is
107- /// the whole point here: "no registry on this chain" and "this migration
108- /// has not been applied" are different facts, and silently collapsing the
109- /// first into the second would send a caller down its pre-migration branch
110- /// on every chain the registry was never deployed to.
108+ /// NAMED revert rather than a call into unknown code. An absent registry
109+ /// reverts either way — solc reverts a high-level call whose returndata is
110+ /// too short to decode — but anonymously, saying nothing about which of the
111+ /// two it was. What the check actually forbids is the case that does NOT
112+ /// revert: code at the address that is not this registry, an EIP-7702
113+ /// delegation included, is free to answer zero to every migration and send
114+ /// every caller down its pre-migration branch.
111115 ///
112116 /// The registry itself refuses the zero writer, and refuses the two ids a
113117 /// migration can never be, so those arrive as reverts from it rather than
@@ -129,10 +133,11 @@ library LibMigrationRegistry {
129133 /// if it has never applied one.
130134 ///
131135 /// Verifies the registry's code hash first for the same reason `applied`
132- /// does, and more sharply: a call into an empty account returns nothing,
133- /// which decodes as zero, and zero is the one value a head can never hold —
134- /// so an unverified read would hand back a head that is not a head at all,
135- /// on exactly the chains where nothing has been deployed.
136+ /// does, and more sharply: occupying code is free to answer any head it
137+ /// likes, including the zero no head can ever hold, so an unverified read
138+ /// can hand back something that is not a head at all. An empty address is
139+ /// not that case — there is no returndata for a `bytes32` to decode from,
140+ /// so it reverts unguarded — and the check is what gives it a name.
136141 /// @param writer The namespace to read. Never the zero address.
137142 /// @return The head of `writer`'s namespace. Never zero.
138143 function head (address writer ) internal view returns (bytes32 ) {
@@ -151,10 +156,12 @@ library LibMigrationRegistry {
151156 /// one account interleave into one chain.
152157 ///
153158 /// Verifies the registry's code hash before writing, so a migration is
154- /// never "applied" into an empty address or into unknown code. A record
155- /// that went nowhere is worse than no record at all: the migration would
156- /// have run, and every reader would go on asserting the pre-migration
157- /// state.
159+ /// never "applied" into unknown code. A write into an EMPTY address fails
160+ /// unguarded — solc checks the callee exists when no return data is
161+ /// expected — so what this stops is the write that SUCCEEDS into something
162+ /// that is not the registry: a record that went nowhere is worse than no
163+ /// record at all, because the migration ran and every reader goes on
164+ /// asserting the pre-migration state.
158165 ///
159166 /// The registry refuses the zero id, refuses a migration this caller has
160167 /// already applied, and refuses one applied onto anything but the
0 commit comments