Skip to content

contract creation code#16

Merged
thedavidmeister merged 9 commits intomainfrom
2026-02-07-creation-code
Feb 7, 2026
Merged

contract creation code#16
thedavidmeister merged 9 commits intomainfrom
2026-02-07-creation-code

Conversation

@thedavidmeister
Copy link
Contributor

@thedavidmeister thedavidmeister commented Feb 7, 2026

Motivation

Solution

Checks

By submitting this for review, I'm confirming I've done the following:

  • made this PR as small as possible
  • unit-tested any new functionality
  • linked any relevant issues or PRs
  • included screenshots (if this involves a front-end change)

Summary by CodeRabbit

  • New Features

    • Added a creation-code generator for producing deployable contract bytecode (replaces prior inline deployment helpers).
    • Enforces a maximum data size and returns a clear error when data is too large.
  • Tests

    • Reworked tests to deploy data contracts from generated creation code and verify full-data and sliced-data integrity via fuzzing.

@coderabbitai
Copy link

coderabbitai bot commented Feb 7, 2026

Walkthrough

Replaced container-based in-memory deployment logic with an internal contractCreationCode(bytes) helper that assembles raw creation bytecode from input data; tests updated to deploy that creation code via inline assembly and validate stored data on-chain.

Changes

Cohort / File(s) Summary
Library: creation-code generator
src/lib/LibDataContract.sol
Added contractCreationCode(bytes memory data) and DataTooLarge(uint256); removed newContainer, write, and writeZoltu. Assembly builds creation bytecode and enforces max data length. Review assembly memory math, prefix/length encoding, and error path.
Tests: creation-code deploy + assertions
test/lib/LibDataContract.t.sol
Replaced in-memory container tests with creation-code based flows: added contractCreationCodeVeryLargeData, testContractCreationCodeDataTooLargeRevert, and testRoundCreationCodeFuzz(...). Tests now deploy creationCode via inline create and validate full-data and slice hashes; removed many old write/writeZoltu tests and helpers.
Tooling / Snapshot
.gas-snapshot
Removed metrics for several removed tests; snapshot updated to reflect deleted test cases. No functional code beyond tests/library changes.

Sequence Diagram(s)

sequenceDiagram
    participant Test as Test
    participant Lib as LibDataContract
    participant EVM as EVM (create)
    participant Deployed as DeployedContract

    Test->>Lib: contractCreationCode(data)
    Lib-->>Test: creationCode (bytes)
    Test->>EVM: create(creationCode) via inline assembly
    EVM-->>Deployed: deployed contract at addr
    Test->>Deployed: call read(start, length)
    Deployed-->>Test: return data / slice
    Test->>Test: assert keccak/length/slice equality
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • update deps #14: Modifies the same LibDataContract deployment/code-generation flow (related changes to write/deploy helpers and ZOLTU handling).
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'contract creation code' is vague and generic, using non-descriptive phrasing that doesn't clearly convey the main changes (replacing deployment flow with creation code generation, adding DataTooLarge validation). Consider a more specific title like 'Replace deployment helpers with contractCreationCode function' or 'Add contractCreationCode with data size validation' to better reflect the primary changes.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 2026-02-07-creation-code

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/lib/LibDataContract.sol`:
- Around line 90-102: The prefix computation uses add(mload(data), 1) without
limiting length to 2 bytes, risking silent overflow and inconsistent behavior vs
newContainer; update the prefix calculation to mask the length into 2 bytes the
same way as newContainer (use and(0xFFFF, add(mload(data), 1))) before the shl,
so the computed prefix (built from basePrefix and shifted length) always encodes
a 2-byte length; modify the code around the prefix variable calculation (the
or/shl/add calls) to apply this 2-byte mask.
- Line 107: The mcopy call is using swapped source/destination args causing the
uninitialized creation code buffer to be read and the input data to be
overwritten; update the mcopy invocation so it copies mload(data) bytes from the
input data pointer (dataPointer) into the creation code buffer pointer
(creationCodeDataPointer) by swapping the first two arguments in the mcopy call
(reference symbols: mcopy, dataPointer, creationCodeDataPointer, mload(data)).

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@test/lib/LibDataContract.t.sol`:
- Around line 46-48: After the assembly block that assigns dataContract via
create(...) add an explicit zero-address check (e.g., assert or require) to fail
fast when create returns address(0); reference the local variable dataContract
and ensure this check runs before calling read so a deployment failure is
reported directly instead of being masked by ReadError from read.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
test/lib/LibDataContract.t.sol (1)

5-17: 🛠️ Refactor suggestion | 🟠 Major

Remove unused imports.

console2 is imported but never used. Additionally, DataContractMemoryContainer, WriteError, and ZOLTU_PROXY_ADDRESS are imported but no longer referenced after the write-function removal.

♻️ Proposed fix
-import {Test, console2} from "forge-std/Test.sol";
+import {Test} from "forge-std/Test.sol";
 import {LibMemCpy} from "rain.solmem/lib/LibMemCpy.sol";
 import {LibBytes} from "rain.solmem/lib/LibBytes.sol";
 
 import {
     LibPointer,
     Pointer,
-    DataContractMemoryContainer,
     LibDataContract,
-    ReadError,
-    WriteError,
-    ZOLTU_PROXY_ADDRESS
+    ReadError
 } from "src/lib/LibDataContract.sol";
src/lib/LibDataContract.sol (1)

7-7: ⚠️ Potential issue | 🟡 Minor

Remove unused WriteError import.

WriteError is imported but never used in this file—there are no write functions that would throw it. The three exported functions are contractCreationCode, read, and readSlice.

Proposed fix
-import {WriteError, ReadError} from "../error/ErrDataContract.sol";
+import {ReadError} from "../error/ErrDataContract.sol";
🤖 Fix all issues with AI agents
In `@test/lib/LibDataContract.t.sol`:
- Around line 46-50: Extract the repeated inline assembly deployment block into
a single internal test helper (e.g., _deployDataContract(bytes memory data)
internal returns (address)) that builds creationCode via
LibDataContract.contractCreationCode(data), performs the assembly create call,
and requires the returned address != address(0); then replace the four
duplicated 5-line assembly blocks in the tests with calls to this helper to
centralize the address(0) check and remove duplication.
- Around line 108-110: Remove the leftover commented-out old write flow in the
test by deleting the three commented lines referencing
LibDataContract.newContainer, LibMemCpy.unsafeCopyBytesTo, and
LibDataContract.write so the test no longer contains dead/commented code; ensure
no other references to this old flow remain in LibDataContract.t.sol and run
tests to confirm nothing else depends on those lines.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@test/lib/LibDataContract.t.sol`:
- Around line 51-67: Fuzz can generate data longer than EIP-170 max deployed
code (24,576 bytes) so create returns address(0) and later reads revert; in the
tests (testRoundCreationCodeFuzz, testRoundSliceError, testSameReads,
testZeroPrefix) guard the create/deploy path by constraining or skipping such
inputs — add an assumption like vm.assume(uint256(data.length) + 1 <= 24576)
before building/creating the contract (or check data.length and skip/assert on
address(0) before calling LibDataContract.read) so you never attempt to deploy
data exceeding the EVM code-size limit when using
LibDataContract.contractCreationCode and assembly create.

Comment on lines +51 to +67
function testRoundCreationCodeFuzz(bytes memory data, bytes memory garbage, uint16 start, uint16 sliceLength)
external
{
bytes32 dataHash = keccak256(data);
vm.assume(uint256(start) + uint256(sliceLength) <= data.length);

bytes memory expectedSlice = new bytes(sliceLength);
LibMemCpy.unsafeCopyBytesTo(data.dataPointer().unsafeAddBytes(start), expectedSlice.dataPointer(), sliceLength);

/// Writing any data to a contract then reading it back without corrupting
/// memory or the data itself.
function testRoundFuzz(bytes memory data, bytes memory garbage) public {
// Put some garbage in unallocated memory.
LibMemCpy.unsafeCopyBytesTo(garbage.dataPointer(), LibPointer.allocatedMemoryPointer(), garbage.length);

(DataContractMemoryContainer container, Pointer pointer) = LibDataContract.newContainer(data.length);

LibMemCpy.unsafeCopyBytesTo(data.dataPointer(), pointer, data.length);

address datacontract = LibDataContract.write(container);

bytes memory round = LibDataContract.read(datacontract);
bytes memory creationCode = LibDataContract.contractCreationCode(data);
address dataContract;
assembly ("memory-safe") {
dataContract := create(0, add(creationCode, 0x20), mload(creationCode))
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fuzz test can fail when data.length exceeds EVM max contract code size (24 576 bytes).

contractCreationCode allows up to 65 534 bytes, but EVM's EIP-170 limits deployed code to 24 576 bytes. When data.length + 1 > 24576, create silently returns address(0) and the subsequent read reverts with ReadError, causing a spurious test failure.

The same concern applies to testRoundSliceError, testSameReads, and testZeroPrefix.

Proposed fix
     function testRoundCreationCodeFuzz(bytes memory data, bytes memory garbage, uint16 start, uint16 sliceLength)
         external
     {
+        vm.assume(data.length <= 24575);
         bytes32 dataHash = keccak256(data);
         vm.assume(uint256(start) + uint256(sliceLength) <= data.length);
🤖 Prompt for AI Agents
In `@test/lib/LibDataContract.t.sol` around lines 51 - 67, Fuzz can generate data
longer than EIP-170 max deployed code (24,576 bytes) so create returns
address(0) and later reads revert; in the tests (testRoundCreationCodeFuzz,
testRoundSliceError, testSameReads, testZeroPrefix) guard the create/deploy path
by constraining or skipping such inputs — add an assumption like
vm.assume(uint256(data.length) + 1 <= 24576) before building/creating the
contract (or check data.length and skip/assert on address(0) before calling
LibDataContract.read) so you never attempt to deploy data exceeding the EVM
code-size limit when using LibDataContract.contractCreationCode and assembly
create.

@thedavidmeister thedavidmeister merged commit 04cd6c0 into main Feb 7, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant