Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions src/tests/evm_precompiles.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@ inline bool isBlake2bPrecompile(const evmc::address &Addr,
return Addr.bytes[sizeof(Addr.bytes) - 1] == 0x09;
}

inline bool isIdentityPrecompile(const evmc::address &Addr) noexcept {
for (size_t I = 0; I + 1 < sizeof(Addr.bytes); ++I) {
if (Addr.bytes[I] != 0) {
return false;
}
}
return Addr.bytes[sizeof(Addr.bytes) - 1] == 0x04;
}

inline intx::uint256 loadUint256Padded(const uint8_t *Data, size_t Size,
size_t Offset) noexcept {
uint8_t Buffer[32] = {0};
Expand Down Expand Up @@ -221,6 +230,38 @@ inline void blake2bCompress(uint64_t H[8], const uint64_t M[16], uint64_t T0,
}
}

inline evmc::Result executeIdentity(const evmc_message &Msg,
std::vector<uint8_t> &ReturnData) {
constexpr uint64_t BaseGas = 15;
constexpr uint64_t GasPerWord = 3;
const uint64_t MsgGas = Msg.gas < 0 ? 0 : static_cast<uint64_t>(Msg.gas);
const uint64_t InputSize = static_cast<uint64_t>(Msg.input_size);
const uint64_t Words = (InputSize + 31) / 32;
const uint64_t GasCost = BaseGas + GasPerWord * Words;

if (GasCost > MsgGas) {
ReturnData.clear();
return evmc::Result(EVMC_OUT_OF_GAS, 0, 0, nullptr, 0);
}

if (InputSize != 0 && Msg.input_data == nullptr) {
ReturnData.clear();
return evmc::Result(EVMC_OUT_OF_GAS, 0, 0, nullptr, 0);
}

if (InputSize == 0) {
ReturnData.clear();
} else {
const auto *Input = static_cast<const uint8_t *>(Msg.input_data);
ReturnData.assign(Input, Input + InputSize);
}

const int64_t GasLeft = static_cast<int64_t>(MsgGas - GasCost);
return evmc::Result(EVMC_SUCCESS, GasLeft, 0,
ReturnData.empty() ? nullptr : ReturnData.data(),
ReturnData.size());
}

inline evmc::Result executeModExp(const evmc_message &Msg,
evmc_revision Revision,
std::vector<uint8_t> &ReturnData) {
Expand Down
3 changes: 2 additions & 1 deletion src/tests/evm_state_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,8 @@ ExecutionResult executeStateTest(const StateTestFixture &Fixture,
: PT.Message->recipient;
const bool IsPrecompile =
precompile::isModExpPrecompile(PrecompileAddr) ||
precompile::isBlake2bPrecompile(PrecompileAddr, Revision);
precompile::isBlake2bPrecompile(PrecompileAddr, Revision) ||
precompile::isIdentityPrecompile(PrecompileAddr);

// Find the target account (contract to call) if present.
const ParsedAccount *TargetAccount = nullptr;
Expand Down
6 changes: 5 additions & 1 deletion src/tests/evm_test_host.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ class ZenMockedEVMHost : public evmc::MockedHost {
: Config.Message.recipient;
const bool IsPrecompile =
precompile::isModExpPrecompile(PrecompileAddr) ||
precompile::isBlake2bPrecompile(PrecompileAddr, ActiveRevision);
precompile::isBlake2bPrecompile(PrecompileAddr, ActiveRevision) ||
precompile::isIdentityPrecompile(PrecompileAddr);
if (!Config.Bytecode && Config.BytecodeSize != 0) {
Result.ErrorMessage = "Bytecode buffer is null";
return Result;
Expand Down Expand Up @@ -472,6 +473,9 @@ class ZenMockedEVMHost : public evmc::MockedHost {
if (precompile::isModExpPrecompile(PrecompileAddr)) {
return precompile::executeModExp(Msg, Revision, ReturnData);
}
if (precompile::isIdentityPrecompile(PrecompileAddr)) {
return precompile::executeIdentity(Msg, ReturnData);
}

// For CALLCODE and DELEGATECALL, code comes from code_address, not
// recipient
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Tests that fill coverage gaps when porting over from `ethereum/tests`."""
Loading