VIEW THIS AS

Auto mode follows the Route Engine until you choose a viewpoint.

YOU ARE HERE

ROUTE CHECK

CONNECTED TO

WHAT NEXT

Use the canonical route for this room, or HELP if you are unsure.

Smart-Contract Source Verification: Reconstruct the Build and Explain the Bytecode Match

Three students in school uniforms work through open books at a classroom table, with textbooks and stationery nearby and study notes on the whiteboard behind them.

中文版 · Blockchain learning guide · Previous article

Blockchain learning · Extension BCX008

Three students in school uniforms work through open books at a classroom table, with textbooks and stationery nearby and study notes on the whiteboard behind them.
Study photograph for illustration; it does not establish that the pictured students are studying blockchain.

Readable source code and a deployed contract are different evidence objects. To connect them, a reviewer needs the correct build inputs, the correct output artifact and an explicit comparison with code from an identified chain context. A familiar function name or a successful compiler process is not that connection.

This lesson explains the investigation through a static, auditable dossier. You will distinguish creation code from runtime code, classify metadata-only and unexplained body differences, and apply declared library and immutable substitutions without hiding arbitrary discrepancies.

The byte arrays below are deliberately synthetic comparison objects. They are not real Solidity compiler output, are not claimed to execute as a contract, and were not deployed or submitted to a verification service. Their purpose is to make offsets, scope and conclusions reproducible without a live target, wallet, credential or financial action.

Choose your reading route

In this guide

Sections 1–3 establish the identity and build record. Sections 4–8 work through the byte comparison cases. Sections 9–11 interpret labels and produce a bounded verdict. The exercise supplies numeric answers. For what a block explorer’s badge does and does not establish, see Reading Blockchain Explorer Evidence.

Back to contents · Next section

1. Identify the object being verified

A source-verification claim should identify the network, address, observed block context and runtime bytes being compared. A contract name is not a globally unique identifier. Nor does a code response from an unidentified endpoint establish the authenticity or finality of the chain observation.

Our dossier supplies a correctly identified, non-proxy target T in fictional context N at block B. It supplies a captured comparison object R and a proposed build packet P. Target identity and observation authenticity are assumptions for this exercise; we are investigating the next link, between the packet and the captured object.

If the target were a proxy, a separate question would identify which implementation and execution path are relevant. Matching the proxy’s own code would not by itself match all application implementation code. The stored-state upgrade lesson handles another part of that distinction.

Keep the claimed scope in one sentence: “Does the declared build packet account for the captured runtime object at this identified context, under these named transformations?” That is narrower and more testable than “Is this contract verified and safe?”

Back to contents · Next section

2. Reconstruct inputs before interpreting differences

A real reproduction record needs the exact source bytes and source-unit paths, all imported dependencies, compiler identity and relevant settings. Record the chosen contract within the compilation, optimizer configuration, EVM target, intermediate-representation pipeline setting and metadata options. A repository branch name alone does not freeze those inputs.

The Solidity 0.8.30 compiler interface describes structured inputs and outputs, including separate bytecode artifacts and reference ranges. The optimizer runs setting concerns expected usage when optimizing; it is not a literal count of optimization passes. The same compiler version with different settings is not the same declared build.

Our conceptual packet P names source set S7, source-unit path contracts/Catalogue.sol, compiler artifact C7, optimizer enabled with runs 200, target shanghai and viaIR false. S7 and C7 are dossier labels, not published source hashes or claims that a compiler was actually run here. The full input record is assumed supplied within the fictional investigation.

In real work, unresolved imports, missing source bytes or an ambiguous compiler identity stop a reproducibility claim. A plausible-looking source file cannot substitute for the missing dependency graph. Record what is absent rather than filling it with whichever current package happens to compile.

Back to contents · Next section

3. Select runtime output rather than the deployment input

Creation code executes to establish a contract and return its deployed code. The runtime artifact is the code retained for subsequent calls. Solidity’s contract documentation explains that constructor code is not simply retained as part of that final callable code.

Accordingly, comparing a creation artifact directly against captured runtime bytes is the wrong test. Constructor arguments and deployment-time effects need their own treatment. A mismatch between different artifact types does not show that the submitted source was malicious or that the compiler failed.

For a visibly simple comparison, our dossier includes a synthetic creation-shaped object C with four leading marker bytes, the 90-byte object R, and two trailing argument-marker bytes. Its length is 96. This is an invented packaging illustration, not a model of actual EVM creation-code structure or a rule for stripping six bytes from real deployments.

The correct classroom runtime comparison uses R’s 90 bytes. Choosing C’s 96 bytes produces an artifact-selection error before any metadata or library analysis. In a real build record, the appropriate output field and provenance establish the artifact type; appearance alone does not.

Back to contents · Next section

4. Define a complete synthetic comparison object

All offsets are zero-based byte offsets, not positions in a hexadecimal text string. R contains an 80-byte body, an eight-byte toy CBOR marker, and a two-byte length field. Thus its total length is 90 bytes.

Start the body with byte value 0x10 in all 80 positions. Replace positions 8 through 27 with twenty bytes of value 0x22. Replace positions 32 through 63 with the 32-byte big-endian representation of integer 7: thirty-one zero bytes followed by 0x07. Replace position 70 with 0x77. All other body bytes remain 0x10.

The marker bytes at positions 80 through 87 are a1 61 74 44 01 02 03 04. For this toy, they encode a one-entry CBOR map whose key is t and whose value is the four-byte sequence 01 02 03 04. This marker is not an IPFS hash, a Solidity metadata file or evidence of a real source fingerprint.

The final two bytes, positions 88 and 89, are 00 08, declaring marker length eight. The arithmetic for its start is 90 minus 2 minus 8, which equals 80. Every byte is specified so that a reader can independently reconstruct and compare the arrays.

Real Solidity metadata has its own schema and build settings. The pinned metadata documentation describes a trailing length and CBOR parsing, and warns against assuming a fixed starting prefix. Appending CBOR metadata can also be disabled. Our toy illustrates boundary arithmetic; it is not a universal parser for arbitrary contract code.

Back to contents · Next section

5. Packet A: explain substitutions and then compare everything

The proposed template has the same body and marker as R except that positions 8–27 and 32–63 are zero-filled placeholders. The packet separately declares the first span as a library-reference range and the second as an immutable-reference range.

The supplied transformation record names exactly two operations: place twenty 0x22 bytes in the library span, and place the 32-byte encoding of 7 in the immutable span. It attributes both values to supplied deployment evidence in the fictional dossier. There are no other permitted substitutions, omitted ranges or inferred values.

After those operations, all 90 bytes equal R. The declared ranges cover 20+32=52 distinct bytes, leaving 38 outside them. Those 38 include the remaining body and the complete marker and length field. They must also match; recording legitimate transformations does not authorize ignoring the rest.

The conclusion is a full comparison match for this supplied synthetic object after the two declared materializations. It is not a report that Sourcify verified a deployed contract, and it does not establish an actual source-to-compiler relationship because our packet and output are teaching fixtures.

In a real investigation, reference ranges come from the relevant compiler output and the verifier’s documented procedure. Their values and provenance must remain visible. “Ignore every differing byte” would reverse the purpose of verification.

Back to contents · Next section

6. Packet B: only the marker differs

Take the already materialized object from Packet A and change byte 87 from 0x04 to 0x05. Leave all 80 body bytes and the final length field unchanged. The object still has length 90, and the marker still occupies positions 80–87.

The complete byte arrays do not match. Their bodies match exactly, while the supplied marker value differs. A report should preserve both findings rather than collapse them into either “everything identical” or “no useful correspondence.”

For actual Solidity builds, source paths, comments or whitespace can affect metadata even when the relevant generated body comparison is unchanged. That is a reason to investigate metadata differences, not permission to assume that every mismatch near the end is harmless. The actual boundary, parsed structure and build record have to support the classification.

Our Packet B marker is only a toy marker. We therefore call its outcome “body match with marker discrepancy,” not an actual service-issued Match status. A real verifier may use its documented matching rules and evidence to classify a genuine build; our arithmetic alone cannot award that label.

Back to contents · Next section

7. Packets C and D: unexplained body change and changed settings

Packet C starts from the materialized matching object but changes body byte 70 from 0x77 to 0x78. That position is outside both declared substitution ranges and outside the marker. The full comparison fails, and removing the marker does not fix it.

The correct finding is an unexplained body discrepancy under the supplied comparison rules. Do not enlarge an immutable range to cover position 70 after seeing the mismatch. Do not infer the exact behavioural effect of that byte in our non-executable fixture. A discrepancy warrants explanation without inventing an exploit or a proof of harmlessness.

Packet D separately claims the same source-set label S7 but changes optimizer runs from 200 to 1000. Its supplied output has byte 70 equal to 0x79 and a different marker. This is explicitly a hypothetical outcome provided by the dossier, not an assertion that changing that setting in an actual compiler always changes precisely this byte.

D does not reproduce P’s declared build inputs and does not match R under the allowed transformations. Retain the changed-setting explanation as a hypothesis to test with the correct reproducible build. The mere fact that settings differ does not tell you the complete cause of every output difference.

An EVM-target change would likewise require its own declared input and output evidence. There is no rule that every setting change must alter every contract’s body. Reproduction means testing the specified inputs, not relying on an intuition that two configurations probably behave similarly.

Back to contents · Next section

8. Packet E: a missing immutable value is unresolved evidence

Start again with the unmaterialized template. The library range and its twenty 0x22 bytes are documented, but the dossier lacks the evidence establishing the immutable value. The captured R happens to contain the encoding of 7 in that range.

A reviewer can record those observed bytes and identify the unresolved reference. However, copying 7 from the target into the proposed artifact and then announcing that the deployment input was independently confirmed would be circular. An observed matching value and an independently reconstructed value are different evidentiary claims.

Under this lesson’s stricter reconstruction criterion, Packet E remains incomplete until the required value provenance is supplied or the claim is explicitly narrowed. A service may document a matching procedure that excludes or transforms immutables; that should be reported as its actual scope rather than silently promoted into a stronger reconstruction claim.

This is not a finding that the contract is necessarily wrong. It is a finding that the packet does not support everything the proposed verdict says. “Unresolved” is useful when the missing evidence is specific and the next required check is identifiable.

Back to contents · Next section

9. Interpret Exact Match and Match with their scope

Sourcify’s current documentation uses Exact Match and Match, replacing the older perfect and partial terminology. It distinguishes matching metadata fingerprints from a match that allows a metadata-hash difference, and expressly accounts for library and immutable differences.

Consequently, an Exact Match label should be read with its documented transformation scope, not paraphrased as unconditional identity of every raw pre-deployment and post-deployment byte. A Match should not automatically be described as an arbitrary fragment match or a failed verification.

For a genuine report, retain the verifier’s version or checked documentation date, artifact identity, source and settings record, metadata result and library/immutable treatment. The current definitions were checked on 12 October 2026; the pinned Solidity references describe version 0.8.30 rather than an unspecified latest release.

None of these labels alone proves that a named person authored the source, that its logic is safe, that a library is trustworthy, or that initialization and current storage satisfy the intended application policy. Those are additional evidence tasks, not defects in a carefully scoped code-correspondence result.

Back to contents · Next section

10. Check the build result and preserve the investigation record

For a real reproduction, inspect compiler diagnostics and the requested artifacts. Solidity’s Standard JSON interface reports compilation errors in its output, so a successful process exit alone is not enough. A missing runtime object cannot be replaced with a convenient creation object to keep the workflow moving.

Preserve the exact input set, compiler identity, settings, output artifact, observed target context and every transformation. Record lengths and differing offsets before assigning a cause. If source retrieval or compilation failed, say so. Our lesson has performed only local array checks and makes no actual compilation claim.

A practical review record has four distinct outcomes available: complete correspondence under a named scope; a supported narrower correspondence such as the marker-only case; an unexplained discrepancy; and insufficient evidence. These outcomes direct different next steps and should not all be reduced to a green or red badge.

For applying audit findings after a code identity is established, use Reading a Blockchain Audit Packet. That lesson asks whether an assessment covers the relevant implementation and assumptions. Here we inspect the correspondence link that such an assessment often takes as supplied.

Back to contents · Next section

11. A model verdict for the dossier

“Packet A accounts for the complete 90-byte synthetic target after the two specified, evidence-backed substitutions. Packet B preserves its 80-byte body but changes the toy marker, so complete identity is false. Packet C has an unexplained body mismatch at offset 70. Packet D changes a declared compiler setting and supplies a nonmatching body; it is not a reproduction of P.”

“Packet E lacks the stipulated immutable-value evidence and cannot support the stronger reconstruction claim. The 96-byte creation-shaped object is the wrong artifact for a direct runtime comparison. None of these classroom outcomes is an actual compilation, deployment, verification-service result or security audit.”

This verdict keeps useful findings while making their limits explicit. It does not hide mismatch evidence, assign motives to an author or confuse byte correspondence with acceptable application behaviour.

Back to contents · Next section

Exercise with answers

  1. Where does the eight-byte marker begin in a 90-byte object with a two-byte trailing length? At offset 80, because 90−2−8=80.
  2. How many bytes lie in the two declared substitution spans? 52: twenty library-reference bytes and thirty-two immutable-reference bytes, without overlap.
  3. How many bytes remain outside those spans? 38. They still require comparison.
  4. Does changing byte 87 preserve complete identity? No. It preserves the supplied 80-byte body but changes the marker.
  5. Can a marker-only exclusion explain a difference at offset 70? No. Offset 70 is in the body and outside the declared reference ranges.
  6. Does a 96-byte creation-shaped object directly match the 90-byte runtime object? No; it is also the wrong artifact type for this test.
  7. Can a compiler process exit establish that its JSON output contains no errors? No. Inspect the diagnostics and required artifacts.
  8. Does reproducing bytes establish correct current registry state? No. Storage, initialization, authority and behaviour need their own evidence.

For an additional boundary check, suppose the final two bytes declare a marker length of 100 while the entire object is 90 bytes. The computed start would be negative. Reject that proposed parse instead of removing 102 bytes or guessing a marker prefix. A well-formed boundary is a prerequisite to classifying metadata-only differences.

Back to contents · Next section

Frequently asked questions

Can the same source text produce different comparison results?

Yes, build inputs include more than visible text. Settings, compiler identity, dependencies, paths and deployment substitutions require an explicit record. The actual output comparison determines the finding.

May a reviewer simply delete the end of every runtime artifact?

No. Establish whether metadata is appended, parse its documented boundary and state the resulting comparison scope. Arbitrary truncation can hide a discrepancy.

Are libraries and immutables excuses to ignore differences?

No. They require identified ranges and documented treatment. A legitimate transformation is bounded and reproducible; an unexplained differing byte remains unexplained.

Is this an installation or deployment tutorial?

No. It is a static evidence-reading and array-comparison exercise. No compiler installation, account, upload, deployed target or transaction is needed.

Back to contents · Next section

Sources and further reading

A defensible source-verification result explains which artifact matched, under which inputs and transformations, and which important questions remain outside that result.

Back to contents