ERC-5202 Blueprint contract format

Final · Other · created 2022-06-23

Defines a standard bytecode format for storing deployment code (initcode), which creates contracts, on chain as a "blueprint" contract. The identifier at the front prevents direct execution and lets tools recognize it easily.

Why it is needed

If the deployment code (initcode) that creates a contract is stored on chain, a deployer contract can copy that code (EXTCODECOPY) and then call a creation instruction (CREATE, CREATE2) to make a new contract, which reduces the size of the deployer contract. But without a defined format, two problems arise. First, external tools and indexers have difficulty telling which contracts are for ordinary execution and which store deployment code. Finding them by guessing bytecode patterns is problematic for both accuracy and maintenance. Second, if deployment code is stored as raw bytes, anyone can call that contract directly and run the deployment code as if it were ordinary code. This opens room for side effects such as writing to storage or calling external contracts. If the code contains a self-destruct instruction (SELFDESTRUCT), the blueprint itself can be deleted, and a deployer contract that depends on it may stop working.

In depth

Basic preamble structure

A blueprint contract must begin with the preamble 0xFE71<version bits><length encoding bits>. In the third byte, the upper 6 bits are the version and the lower 2 bits are the length encoding. The version starts at 0 (0b000000) and increases by 1. If the length encoding bits are 0b11, that is a reserved value, and the third byte is treated as a continuation byte. This marks the case where a version must be written in several bytes, but the exact encoding of a multibyte version is deferred to a later ERC. A blueprint must also contain at least 1 byte of initcode, and empty initcode is prohibited to prevent a common mistake.

Data section and length encoding

Arbitrary bytes (data or code) may be placed between the version byte and the initcode. In that case the preamble takes the form 0xFE71<version bits><length encoding bits><length bytes><data>. <length encoding bits> is a number from 0 to 2 that indicates how many bytes <length bytes> has, and <length bytes> is the data length written in big-endian. Because EIP-170 limits contract size to 24KB, 2 bytes are enough to write the length. That is why the unused value 0b11 could be reserved as a continuation sequence marker. An indexer can read this length information and skip the data section.

Why it starts with 0xFE71

Calling a blueprint directly with CALL is a misuse, so the preamble starts with the INVALID (0xfe) instruction and ends execution with an exceptional halt instead of a soft stop such as STOP (0x00). To distinguish it from other contracts that start with 0xFE, one more magic byte is added. 0x71 is a value chosen arbitrarily from the last byte of the keccak256 hash of the byte string "blueprint" (keccak256(b"blueprint")[-1]). To save gas and storage, the preamble was designed to be as short as possible.

The initcode length is not recorded

The preamble does not include the length of the initcode itself by default. It would take up space, and the total contract size is easy to get with EXTCODESIZE, so the initcode length can be derived directly by subtracting the preamble and data section lengths. The reference implementation function parse_blueprint_preamble splits bytecode into (version, data section, initcode) following this rule and raises an exception if the format does not match.

The format by example

The simplest blueprint, with no data section and an initcode of a single STOP byte, is 0xFE710000. An example that stores 0xFF seven times as data is 0xFE710107FFFFFFFFFFFFFF00, which splits into 0xFE71|01|07|FFFFFFFFFFFFFF|00. 0x01 is version 0 plus the length bits value 1, and 0x07 is the data length. If the data is 256 bytes, the length bits become 2 and the length is written in 2 bytes (0x0100), as in 0xFE71|02|0100|FF...FF|00.

Relationship to EOF

Adding a section kind for initcode (3) to the EVM Object Format (EOF) could be another way to specify blueprints. However, EOF is not yet in the EVM, and this standard aims to standardize blueprints right now without any EVM change. If section kind 3 is later added to the EOF specification and EOF becomes part of the EVM, this ERC is considered deprecated, because EOF validation provides much stronger guarantees than this ERC. The status of this proposal is set to Final.

Things to watch out for

Original ERC · ← ERCs