Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

evmzero: Add check for range in blockHash op #461

Merged
merged 2 commits into from
May 27, 2024
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
21 changes: 20 additions & 1 deletion cpp/vm/evmzero/interpreter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -864,8 +864,27 @@ struct Impl<OpCode::BLOCKHASH> {
constexpr static OpInfo kInfo = UnaryOp(20);

static OpResult Run(uint256_t* top, Context& ctx) noexcept {
if (top[0] > std::numeric_limits<int64_t>::max()) {
top[0] = 0;
return {};
}

int64_t number = static_cast<int64_t>(top[0]);
facuMH marked this conversation as resolved.
Show resolved Hide resolved
top[0] = ToUint256(ctx.host->get_block_hash(number));
int64_t upper, lower;
upper = int64_t(ctx.host->get_tx_context().block_number);
// BLOCKHASH description states that it gets the hash of a block not older
// than 256 in comparison with the current block. and in case the current
// block number is less than 256, then the lower boundary is 0.
if (upper < 257) {
lower = 0;
} else {
lower = upper - 256;
}
facuMH marked this conversation as resolved.
Show resolved Hide resolved
if (number >= lower && number < upper) {
top[0] = ToUint256(ctx.host->get_block_hash(number));
} else {
top[0] = 0;
}
return {};
}
};
Expand Down
81 changes: 78 additions & 3 deletions cpp/vm/evmzero/interpreter_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2834,9 +2834,13 @@ TEST(InterpreterTest, EXTCODEHASH_StackError) {

///////////////////////////////////////////////////////////
// BLOCKHASH
TEST(InterpreterTest, BLOCKHASH) {
TEST(InterpreterTest, BLOCKHASH_inRange) {
const uint64_t block_number = 1000;
MockHost host;
EXPECT_CALL(host, get_block_hash(21)) //
EXPECT_CALL(host, get_tx_context()) //
.Times(1)
.WillOnce(Return(evmc_tx_context{.block_number = block_number}));
EXPECT_CALL(host, get_block_hash(block_number - 1)) //
.Times(1)
.WillOnce(Return(evmc::bytes32(0x0a0b0c0d)));

Expand All @@ -2845,12 +2849,83 @@ TEST(InterpreterTest, BLOCKHASH) {
.state_after = RunState::kDone,
.gas_before = 40,
.gas_after = 20,
.stack_before = {21},
.stack_before = {block_number - 1},
.stack_after = {0x0a0b0c0d},
.host = &host,
});
}

TEST(InterpreterTest, BLOCKHASH_firstInRange) {
const uint64_t block_number = 1000;
MockHost host;
EXPECT_CALL(host, get_tx_context()) //
.Times(1)
.WillOnce(Return(evmc_tx_context{.block_number = block_number}));
EXPECT_CALL(host, get_block_hash(block_number - 256)) //
.Times(1)
.WillOnce(Return(evmc::bytes32(0x0a0b0c0d)));

RunInterpreterTest({
.code = {op::BLOCKHASH},
.state_after = RunState::kDone,
.gas_before = 40,
.gas_after = 20,
.stack_before = {block_number - 256},
.stack_after = {0x0a0b0c0d},
.host = &host,
});
}

TEST(InterpreterTest, BLOCKHASH_outOfRange) {
const uint64_t block_number = 1000;
MockHost host;
EXPECT_CALL(host, get_tx_context()) //
.Times(1)
.WillOnce(Return(evmc_tx_context{.block_number = block_number}));

RunInterpreterTest({
.code = {op::BLOCKHASH},
.state_after = RunState::kDone,
.gas_before = 40,
.gas_after = 20,
.stack_before = {block_number - 257},
.stack_after = {0},
.host = &host,
});
}

TEST(InterpreterTest, BLOCKHASH_sameAsCurrent) {
const uint64_t block_number = 1000;
MockHost host;
EXPECT_CALL(host, get_tx_context()) //
.Times(1)
.WillOnce(Return(evmc_tx_context{.block_number = block_number}));

RunInterpreterTest({
.code = {op::BLOCKHASH},
.state_after = RunState::kDone,
.gas_before = 40,
.gas_after = 20,
.stack_before = {block_number},
.stack_after = {0},
.host = &host,
});
}

TEST(InterpreterTest, BLOCKHASH_overflow) {
MockHost host;

RunInterpreterTest({
.code = {op::BLOCKHASH},
.state_after = RunState::kDone,
.gas_before = 40,
.gas_after = 20,
.stack_before = {uint256_t{0x0000000000000001, 0x0000000000000384}},
.stack_after = {0},
.host = &host,
});
}

facuMH marked this conversation as resolved.
Show resolved Hide resolved
TEST(InterpreterTest, BLOCKHASH_OutOfGas) {
RunInterpreterTest({
.code = {op::BLOCKHASH},
Expand Down
23 changes: 23 additions & 0 deletions regression_inputs/blockhash_#461.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"Status": "running",
"Revision": "Istanbul",
"ReadOnly": true,
"Pc": 8,
"Gas": 20,
"GasRefund": -227234023154315042,
"Code": "66750be9068df1f6408bbef5686da975769e56d9c234c26308561e54671ef3bf29a5c7dfa0be5587f58ba5cdae3ecb7423edccae610551c586da8a405f51a3a946ad926b095fd2626dc2bfb119899d3838b041a1ee2f52a00d71302f93562cc2",
"Stack": [
"4ae34574e9825110 de832ae81b410c8b dba36e64a329105c 32bb930fbfeafc82",
"0000000000000000 0000000000000000 0000000000000000 0000000000000004"
],
"BlockContext": {
"BaseFee": "ddb99751cdafe03b db1282bd243a8724 f8020d59eb04c225 74f9aaa2fbcd2aa8",
"BlockNumber": 0,
"ChainID": "1af9d83701ad0e63 4de99a69a7ccb803 4a5005c9bf10e0a7 af17726db99a2e08",
"CoinBase": "0xd774bd9070705b43cc0e869b651027f2e1d5a4a0",
"GasLimit": 452038407889421009,
"GasPrice": "7769b4568916bcdc 95f45a0b8e86a9cc 84a2c7aac56289ae 0929506dcb3ed222",
"Difficulty": "4712f1af585ea1d8 7f6e4125fbe56924 21ae13d6e2d673e2 f57beecfb640f15b",
"TimeStamp": 4864479995436506094
}
}
Loading