From 19f0e0125381d7bb688dedf272f0f1cfdb2a1f8d Mon Sep 17 00:00:00 2001 From: Vladislav Volosnikov Date: Fri, 6 Dec 2024 11:59:23 +0100 Subject: [PATCH] fix(EVM): Make fetchDeployedCode more robust (2) (#1123) --- system-contracts/contracts/EvmEmulator.yul | 114 +++++++++--------- .../EvmEmulatorFunctions.template.yul | 50 ++++---- .../evm-emulator/EvmEmulatorLoop.template.yul | 7 +- 3 files changed, 90 insertions(+), 81 deletions(-) diff --git a/system-contracts/contracts/EvmEmulator.yul b/system-contracts/contracts/EvmEmulator.yul index dabf78485..4da1e794f 100644 --- a/system-contracts/contracts/EvmEmulator.yul +++ b/system-contracts/contracts/EvmEmulator.yul @@ -408,29 +408,35 @@ object "EvmEmulator" { function fetchDeployedCode(addr, dstOffset, srcOffset, len) -> copiedLen { let codeHash := getRawCodeHash(addr) mstore(0, codeHash) - // The first word of returndata is the true length of the bytecode - let codeLen := fetchFromSystemContract(CODE_ORACLE_SYSTEM_CONTRACT(), 32) - - if gt(len, codeLen) { - len := codeLen - } - - let shiftedSrcOffset := add(32, srcOffset) // first 32 bits is length - - let _returndatasize := returndatasize() - if gt(shiftedSrcOffset, _returndatasize) { - shiftedSrcOffset := _returndatasize - } - - if gt(add(len, shiftedSrcOffset), _returndatasize) { - len := sub(_returndatasize, shiftedSrcOffset) - } - - if len { - returndatacopy(dstOffset, shiftedSrcOffset, len) - } + + let success := staticcall(gas(), CODE_ORACLE_SYSTEM_CONTRACT(), 0, 32, 0, 0) + // it fails if we don't have any code deployed at this address + if success { + returndatacopy(0, 0, 32) + // The first word of returndata is the true length of the bytecode + let codeLen := mload(0) - copiedLen := len + if gt(len, codeLen) { + len := codeLen + } + + let shiftedSrcOffset := add(32, srcOffset) // first 32 bytes is length + + let _returndatasize := returndatasize() + if gt(shiftedSrcOffset, _returndatasize) { + shiftedSrcOffset := _returndatasize + } + + if gt(add(len, shiftedSrcOffset), _returndatasize) { + len := sub(_returndatasize, shiftedSrcOffset) + } + + if len { + returndatacopy(dstOffset, shiftedSrcOffset, len) + } + + copiedLen := len + } } // Returns the length of the EVM bytecode. @@ -1759,11 +1765,8 @@ object "EvmEmulator" { } if gt(len, 0) { - let copiedLen - if getRawCodeHash(addr) { - // Gets the code from the addr - copiedLen := fetchDeployedCode(addr, dstOffset, srcOffset, len) - } + // Gets the code from the addr + let copiedLen := fetchDeployedCode(addr, dstOffset, srcOffset, len) if lt(copiedLen, len) { $llvm_AlwaysInline_llvm$_memsetToZero(add(dstOffset, copiedLen), sub(len, copiedLen)) @@ -3517,29 +3520,35 @@ object "EvmEmulator" { function fetchDeployedCode(addr, dstOffset, srcOffset, len) -> copiedLen { let codeHash := getRawCodeHash(addr) mstore(0, codeHash) - // The first word of returndata is the true length of the bytecode - let codeLen := fetchFromSystemContract(CODE_ORACLE_SYSTEM_CONTRACT(), 32) - - if gt(len, codeLen) { - len := codeLen - } - - let shiftedSrcOffset := add(32, srcOffset) // first 32 bits is length - - let _returndatasize := returndatasize() - if gt(shiftedSrcOffset, _returndatasize) { - shiftedSrcOffset := _returndatasize - } - - if gt(add(len, shiftedSrcOffset), _returndatasize) { - len := sub(_returndatasize, shiftedSrcOffset) - } - - if len { - returndatacopy(dstOffset, shiftedSrcOffset, len) - } + + let success := staticcall(gas(), CODE_ORACLE_SYSTEM_CONTRACT(), 0, 32, 0, 0) + // it fails if we don't have any code deployed at this address + if success { + returndatacopy(0, 0, 32) + // The first word of returndata is the true length of the bytecode + let codeLen := mload(0) - copiedLen := len + if gt(len, codeLen) { + len := codeLen + } + + let shiftedSrcOffset := add(32, srcOffset) // first 32 bytes is length + + let _returndatasize := returndatasize() + if gt(shiftedSrcOffset, _returndatasize) { + shiftedSrcOffset := _returndatasize + } + + if gt(add(len, shiftedSrcOffset), _returndatasize) { + len := sub(_returndatasize, shiftedSrcOffset) + } + + if len { + returndatacopy(dstOffset, shiftedSrcOffset, len) + } + + copiedLen := len + } } // Returns the length of the EVM bytecode. @@ -4868,11 +4877,8 @@ object "EvmEmulator" { } if gt(len, 0) { - let copiedLen - if getRawCodeHash(addr) { - // Gets the code from the addr - copiedLen := fetchDeployedCode(addr, dstOffset, srcOffset, len) - } + // Gets the code from the addr + let copiedLen := fetchDeployedCode(addr, dstOffset, srcOffset, len) if lt(copiedLen, len) { $llvm_AlwaysInline_llvm$_memsetToZero(add(dstOffset, copiedLen), sub(len, copiedLen)) diff --git a/system-contracts/evm-emulator/EvmEmulatorFunctions.template.yul b/system-contracts/evm-emulator/EvmEmulatorFunctions.template.yul index adc931e45..011f7b13a 100644 --- a/system-contracts/evm-emulator/EvmEmulatorFunctions.template.yul +++ b/system-contracts/evm-emulator/EvmEmulatorFunctions.template.yul @@ -346,29 +346,35 @@ function isHashOfConstructedEvmContract(rawCodeHash) -> isConstructedEVM { function fetchDeployedCode(addr, dstOffset, srcOffset, len) -> copiedLen { let codeHash := getRawCodeHash(addr) mstore(0, codeHash) - // The first word of returndata is the true length of the bytecode - let codeLen := fetchFromSystemContract(CODE_ORACLE_SYSTEM_CONTRACT(), 32) - - if gt(len, codeLen) { - len := codeLen - } - - let shiftedSrcOffset := add(32, srcOffset) // first 32 bits is length - - let _returndatasize := returndatasize() - if gt(shiftedSrcOffset, _returndatasize) { - shiftedSrcOffset := _returndatasize - } - - if gt(add(len, shiftedSrcOffset), _returndatasize) { - len := sub(_returndatasize, shiftedSrcOffset) - } - - if len { - returndatacopy(dstOffset, shiftedSrcOffset, len) - } + + let success := staticcall(gas(), CODE_ORACLE_SYSTEM_CONTRACT(), 0, 32, 0, 0) + // it fails if we don't have any code deployed at this address + if success { + returndatacopy(0, 0, 32) + // The first word of returndata is the true length of the bytecode + let codeLen := mload(0) - copiedLen := len + if gt(len, codeLen) { + len := codeLen + } + + let shiftedSrcOffset := add(32, srcOffset) // first 32 bytes is length + + let _returndatasize := returndatasize() + if gt(shiftedSrcOffset, _returndatasize) { + shiftedSrcOffset := _returndatasize + } + + if gt(add(len, shiftedSrcOffset), _returndatasize) { + len := sub(_returndatasize, shiftedSrcOffset) + } + + if len { + returndatacopy(dstOffset, shiftedSrcOffset, len) + } + + copiedLen := len + } } // Returns the length of the EVM bytecode. diff --git a/system-contracts/evm-emulator/EvmEmulatorLoop.template.yul b/system-contracts/evm-emulator/EvmEmulatorLoop.template.yul index fde5817f5..c76854588 100644 --- a/system-contracts/evm-emulator/EvmEmulatorLoop.template.yul +++ b/system-contracts/evm-emulator/EvmEmulatorLoop.template.yul @@ -508,11 +508,8 @@ for { } true { } { } if gt(len, 0) { - let copiedLen - if getRawCodeHash(addr) { - // Gets the code from the addr - copiedLen := fetchDeployedCode(addr, dstOffset, srcOffset, len) - } + // Gets the code from the addr + let copiedLen := fetchDeployedCode(addr, dstOffset, srcOffset, len) if lt(copiedLen, len) { $llvm_AlwaysInline_llvm$_memsetToZero(add(dstOffset, copiedLen), sub(len, copiedLen))