Skip to content

Commit

Permalink
Change versioned hash format
Browse files Browse the repository at this point in the history
  • Loading branch information
0xVolosnikov committed Dec 13, 2024
1 parent daf7022 commit 9f23a69
Show file tree
Hide file tree
Showing 7 changed files with 26 additions and 146 deletions.
16 changes: 8 additions & 8 deletions system-contracts/contracts/ContractDeployer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,7 @@ contract ContractDeployer is IContractDeployer, SystemContractBase {
SystemContractHelper.setValueForNextFarCall(uint128(value));
}

bytes memory paddedBytecode = EfficientCall.mimicCall({
bytes memory bytecode = EfficientCall.mimicCall({
_gas: gasleft(), // note: native gas, not EVM gas
_address: _newAddress,
_data: _input,
Expand All @@ -593,22 +593,22 @@ contract ContractDeployer is IContractDeployer, SystemContractBase {

// Returned data bytes have structure: bytecode.constructorReturnEvmGas
assembly {
let dataLen := mload(paddedBytecode)
constructorReturnEvmGas := mload(add(paddedBytecode, dataLen))
mstore(paddedBytecode, sub(dataLen, 0x20)) // shrink paddedBytecode
let dataLen := mload(bytecode)
constructorReturnEvmGas := mload(add(bytecode, dataLen))
mstore(bytecode, sub(dataLen, 0x20))
}

bytes32 versionedCodeHash = KNOWN_CODE_STORAGE_CONTRACT.publishEVMBytecode(paddedBytecode);
bytes32 versionedCodeHash = KNOWN_CODE_STORAGE_CONTRACT.publishEVMBytecode(bytecode);
ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT.storeAccountConstructedCodeHash(_newAddress, versionedCodeHash);

bytes32 evmBytecodeHash;
assembly {
let bytecodeLen := mload(add(paddedBytecode, 0x20))
evmBytecodeHash := keccak256(add(paddedBytecode, 0x40), bytecodeLen)
let bytecodeLen := mload(bytecode)
evmBytecodeHash := keccak256(add(bytecode, 0x20), bytecodeLen)
}

_setEvmCodeHash(_newAddress, evmBytecodeHash);

emit ContractDeployed(_sender, versionedCodeHash, _newAddress);
}

Expand Down
75 changes: 2 additions & 73 deletions system-contracts/contracts/EvmEmulator.yul
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,6 @@ object "EvmEmulator" {
copyActivePtrData(BYTECODE_OFFSET(), 0, size)
}

function padBytecode(offset, len) -> blobOffset, blobLen {
blobOffset := sub(offset, 32)
let trueLastByte := add(offset, len)

mstore(blobOffset, len)
// clearing out additional bytes
mstore(trueLastByte, 0)
mstore(add(trueLastByte, 32), 0)

blobLen := add(len, 32)

if iszero(eq(mod(blobLen, 32), 0)) {
blobLen := add(blobLen, sub(32, mod(blobLen, 32)))
}

// Now it is divisible by 32, but we must make sure that the number of 32 byte words is odd
if iszero(eq(mod(blobLen, 64), 32)) {
blobLen := add(blobLen, 32)
}
}

function validateBytecodeAndChargeGas(offset, deployedCodeLen, gasToReturn) -> returnGas {
if deployedCodeLen {
// EIP-3860
Expand Down Expand Up @@ -444,28 +423,6 @@ object "EvmEmulator" {
}
}

// Returns the length of the EVM bytecode.
function fetchDeployedEvmCodeLen(addr) -> codeLen {
let codeHash := getRawCodeHash(addr)
mstore(0, codeHash)

let success := staticcall(gas(), CODE_ORACLE_SYSTEM_CONTRACT(), 0, 32, 0, 0)

switch iszero(success)
case 1 {
// The code oracle call can only fail in the case where the contract
// we are querying is the current one executing and it has not yet been
// deployed, i.e., if someone calls codesize (or extcodesize(address()))
// inside the constructor. In that case, code length is zero.
codeLen := 0
}
default {
// The first word is the true length of the bytecode
returndatacopy(0, 0, 32)
codeLen := mload(0)
}
}

function getMax(a, b) -> max {
max := b
if gt(a, b) {
Expand Down Expand Up @@ -1810,9 +1767,7 @@ object "EvmEmulator" {
evmGasLeft := chargeGas(evmGasLeft, 2500)
}

switch isEvmContract(addr)
case 0 { stackHead := extcodesize(addr) }
default { stackHead := fetchDeployedEvmCodeLen(addr) }
stackHead := extcodesize(addr)

ip := add(ip, 1)
}
Expand Down Expand Up @@ -3176,8 +3131,6 @@ object "EvmEmulator" {

gasToReturn := validateBytecodeAndChargeGas(offset, len, gasToReturn)

offset, len := padBytecode(offset, len)

mstore(add(offset, len), gasToReturn)

verbatim_2i_0o("return_deployed", offset, add(len, 32))
Expand Down Expand Up @@ -3584,28 +3537,6 @@ object "EvmEmulator" {
}
}

// Returns the length of the EVM bytecode.
function fetchDeployedEvmCodeLen(addr) -> codeLen {
let codeHash := getRawCodeHash(addr)
mstore(0, codeHash)

let success := staticcall(gas(), CODE_ORACLE_SYSTEM_CONTRACT(), 0, 32, 0, 0)

switch iszero(success)
case 1 {
// The code oracle call can only fail in the case where the contract
// we are querying is the current one executing and it has not yet been
// deployed, i.e., if someone calls codesize (or extcodesize(address()))
// inside the constructor. In that case, code length is zero.
codeLen := 0
}
default {
// The first word is the true length of the bytecode
returndatacopy(0, 0, 32)
codeLen := mload(0)
}
}

function getMax(a, b) -> max {
max := b
if gt(a, b) {
Expand Down Expand Up @@ -4950,9 +4881,7 @@ object "EvmEmulator" {
evmGasLeft := chargeGas(evmGasLeft, 2500)
}

switch isEvmContract(addr)
case 0 { stackHead := extcodesize(addr) }
default { stackHead := fetchDeployedEvmCodeLen(addr) }
stackHead := extcodesize(addr)

ip := add(ip, 1)
}
Expand Down
13 changes: 0 additions & 13 deletions system-contracts/contracts/libraries/Utils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -141,25 +141,12 @@ library Utils {
/// @param _bytecode The EVM bytecode to hash.
/// @return hashedEVMBytecode The 32-byte hash of the EVM bytecode.
/// Note: The function reverts the execution if the bytecode has non expected format:
/// - Bytecode bytes length is not a multiple of 32
/// - Bytecode bytes length is greater than 2^16 - 1 bytes
/// - Bytecode words length is not odd
function hashEVMBytecode(bytes calldata _bytecode) internal view returns (bytes32 hashedEVMBytecode) {
// Note that the length of the bytecode must be provided in 32-byte words.
if (_bytecode.length % 32 != 0) {
revert MalformedBytecode(BytecodeError.Length);
}

if (_bytecode.length > MAX_EVM_BYTECODE_LENGTH) {
revert MalformedBytecode(BytecodeError.EvmBytecodeLength);
}

uint256 lengthInWords = _bytecode.length / 32;
// bytecode length in words must be odd
if (lengthInWords % 2 == 0) {
revert MalformedBytecode(BytecodeError.WordsMustBeOdd);
}

hashedEVMBytecode =
EfficientCall.sha(_bytecode) &
0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
Expand Down
19 changes: 15 additions & 4 deletions system-contracts/contracts/precompiles/CodeOracle.yul
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,19 @@ object "CodeOracle" {
return(0, lenInBytes)
}

function paddedBytecodeLen(len) -> blobLen {
blobLen := len

if iszero(eq(mod(blobLen, 32), 0)) {
blobLen := add(blobLen, sub(32, mod(blobLen, 32)))
}

// Now it is divisible by 32, but we must make sure that the number of 32 byte words is odd
if iszero(eq(mod(blobLen, 64), 32)) {
blobLen := add(blobLen, 32)
}
}

////////////////////////////////////////////////////////////////
// FALLBACK
////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -147,12 +160,10 @@ object "CodeOracle" {
decommit(versionedCodeHash, lengthInWords)
}
case 2 {
// We do not double check whether the length is 32 mod 64, since it assumed that only valid bytecodes
// can pass the `isCodeHashKnown` check.
let lengthInBytes := and(shr(224, versionedCodeHash), 0xffff)
let paddedLengthInBytes := paddedBytecodeLen(lengthInBytes)

// It is assumed that the `lengthInBytes` is divisible by 32.
decommit(versionedCodeHash, div(lengthInBytes, 32))
decommit(versionedCodeHash, div(paddedLengthInBytes, 32))
}
default {
// Unsupported
Expand Down
23 changes: 0 additions & 23 deletions system-contracts/evm-emulator/EvmEmulator.template.yul
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,6 @@ object "EvmEmulator" {
copyActivePtrData(BYTECODE_OFFSET(), 0, size)
}

function padBytecode(offset, len) -> blobOffset, blobLen {
blobOffset := sub(offset, 32)
let trueLastByte := add(offset, len)

mstore(blobOffset, len)
// clearing out additional bytes
mstore(trueLastByte, 0)
mstore(add(trueLastByte, 32), 0)

blobLen := add(len, 32)

if iszero(eq(mod(blobLen, 32), 0)) {
blobLen := add(blobLen, sub(32, mod(blobLen, 32)))
}

// Now it is divisible by 32, but we must make sure that the number of 32 byte words is odd
if iszero(eq(mod(blobLen, 64), 32)) {
blobLen := add(blobLen, 32)
}
}

function validateBytecodeAndChargeGas(offset, deployedCodeLen, gasToReturn) -> returnGas {
if deployedCodeLen {
// EIP-3860
Expand Down Expand Up @@ -98,8 +77,6 @@ object "EvmEmulator" {

gasToReturn := validateBytecodeAndChargeGas(offset, len, gasToReturn)

offset, len := padBytecode(offset, len)

mstore(add(offset, len), gasToReturn)

verbatim_2i_0o("return_deployed", offset, add(len, 32))
Expand Down
22 changes: 0 additions & 22 deletions system-contracts/evm-emulator/EvmEmulatorFunctions.template.yul
Original file line number Diff line number Diff line change
Expand Up @@ -382,28 +382,6 @@ function fetchDeployedCode(addr, dstOffset, srcOffset, len) -> copiedLen {
}
}

// Returns the length of the EVM bytecode.
function fetchDeployedEvmCodeLen(addr) -> codeLen {
let codeHash := getRawCodeHash(addr)
mstore(0, codeHash)

let success := staticcall(gas(), CODE_ORACLE_SYSTEM_CONTRACT(), 0, 32, 0, 0)

switch iszero(success)
case 1 {
// The code oracle call can only fail in the case where the contract
// we are querying is the current one executing and it has not yet been
// deployed, i.e., if someone calls codesize (or extcodesize(address()))
// inside the constructor. In that case, code length is zero.
codeLen := 0
}
default {
// The first word is the true length of the bytecode
returndatacopy(0, 0, 32)
codeLen := mload(0)
}
}

function getMax(a, b) -> max {
max := b
if gt(a, b) {
Expand Down
4 changes: 1 addition & 3 deletions system-contracts/evm-emulator/EvmEmulatorLoop.template.yul
Original file line number Diff line number Diff line change
Expand Up @@ -468,9 +468,7 @@ for { } true { } {
evmGasLeft := chargeGas(evmGasLeft, 2500)
}

switch isEvmContract(addr)
case 0 { stackHead := extcodesize(addr) }
default { stackHead := fetchDeployedEvmCodeLen(addr) }
stackHead := extcodesize(addr)

ip := add(ip, 1)
}
Expand Down

0 comments on commit 9f23a69

Please sign in to comment.