Skip to content

Commit

Permalink
Add validation rules and tests for initcode list emptiness
Browse files Browse the repository at this point in the history
  • Loading branch information
pdobacz authored and gumb0 committed Apr 5, 2024
1 parent 580e2a7 commit fd27842
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 3 deletions.
6 changes: 6 additions & 0 deletions test/state/errors.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ enum ErrorCode : int
GAS_LIMIT_REACHED,
SENDER_NOT_EOA,
INIT_CODE_SIZE_LIMIT_EXCEEDED,
INIT_CODE_EMPTY,
INIT_CODE_COUNT_LIMIT_EXCEEDED,
INIT_CODE_COUNT_ZERO,
CREATE_BLOB_TX,
EMPTY_BLOB_HASHES_LIST,
INVALID_BLOB_HASH_VERSION,
Expand Down Expand Up @@ -67,8 +69,12 @@ inline const std::error_category& evmone_category() noexcept
return "sender not an eoa:";
case INIT_CODE_SIZE_LIMIT_EXCEEDED:
return "max initcode size exceeded";
case INIT_CODE_EMPTY:
return "initcode empty";
case INIT_CODE_COUNT_LIMIT_EXCEEDED:
return "max initcode count exceeded";
case INIT_CODE_COUNT_ZERO:
return "initcode list empty";

Check warning on line 77 in test/state/errors.hpp

View check run for this annotation

Codecov / codecov/patch

test/state/errors.hpp#L72-L77

Added lines #L72 - L77 were not covered by tests
case CREATE_BLOB_TX:
return "blob transaction must not be a create transaction";
case EMPTY_BLOB_HASHES_LIST:
Expand Down
5 changes: 5 additions & 0 deletions test/state/state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,9 +269,14 @@ std::variant<int64_t, std::error_code> validate_transaction(const Account& sende
return make_error_code(TX_TYPE_NOT_SUPPORTED);
if (tx.initcodes.size() > max_initcode_count)
return make_error_code(INIT_CODE_COUNT_LIMIT_EXCEEDED);
if (tx.initcodes.empty())
return make_error_code(INIT_CODE_COUNT_ZERO);
if (std::any_of(tx.initcodes.begin(), tx.initcodes.end(),
[](const bytes& v) { return v.size() > max_initcode_size; }))
return make_error_code(INIT_CODE_SIZE_LIMIT_EXCEEDED);
if (std::any_of(
tx.initcodes.begin(), tx.initcodes.end(), [](const bytes& v) { return v.empty(); }))
return make_error_code(INIT_CODE_EMPTY);
break;

default:;
Expand Down
57 changes: 54 additions & 3 deletions test/unittests/state_transition_eof_create_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1221,6 +1221,45 @@ TEST_F(state_transition, txcreate_initcontainer_max_size)
expect.post[create_address].nonce = 1;
}

TEST_F(state_transition, txcreate_initcontainer_empty)
{
rev = EVMC_PRAGUE;

const bytecode empty_init_container{};

const auto deploy_container = eof_bytecode(bytecode(OP_INVALID));

const auto init_code = returncontract(0, 0, 0);
const bytes init_container = eof_bytecode(init_code, 2).container(deploy_container);

tx.type = Transaction::Type::initcodes;
tx.initcodes.push_back(init_container);
tx.initcodes.push_back(empty_init_container);

const auto factory_code = txcreate().initcode(keccak256(init_container)) + ret_top();
const auto factory_container = eof_bytecode(factory_code, 5);

tx.to = To;
pre.insert(*tx.to, {.nonce = 1, .code = factory_container});

expect.tx_error = INIT_CODE_EMPTY;
}

TEST_F(state_transition, txcreate_no_initcontainer)
{
rev = EVMC_PRAGUE;

tx.type = Transaction::Type::initcodes;

const auto factory_code = txcreate().initcode(keccak256(bytecode())) + ret_top();
const auto factory_container = eof_bytecode(factory_code, 5);

tx.to = To;
pre.insert(*tx.to, {.nonce = 1, .code = factory_container});

expect.tx_error = INIT_CODE_COUNT_ZERO;
}

TEST_F(state_transition, txcreate_initcontainer_too_large)
{
rev = EVMC_PRAGUE;
Expand Down Expand Up @@ -1735,7 +1774,13 @@ TEST_F(state_transition, txcreate_invalid_deploycode)
TEST_F(state_transition, txcreate_missing_initcontainer)
{
rev = EVMC_PRAGUE;
const auto deploy_container = eof_bytecode(bytecode(OP_INVALID));

const auto init_code = returncontract(0, 0, 0);
const bytes init_container = eof_bytecode(init_code, 2).container(deploy_container);

tx.type = Transaction::Type::initcodes;
tx.initcodes.push_back(init_container);

const auto factory_code = txcreate().initcode(keccak256(bytecode())).input(0, 0).salt(Salt) +
OP_DUP1 + push(1) + OP_SSTORE + ret_top();
Expand All @@ -1744,7 +1789,7 @@ TEST_F(state_transition, txcreate_missing_initcontainer)
tx.to = To;
pre.insert(*tx.to, {.nonce = 1, .code = factory_container});

expect.gas_used = 55236;
expect.gas_used = 55748;

expect.post[tx.sender].nonce = pre.get(tx.sender).nonce + 1;
expect.post[*tx.to].nonce = pre.get(*tx.to).nonce; // CREATE caller's nonce must not be bumped
Expand All @@ -1754,11 +1799,17 @@ TEST_F(state_transition, txcreate_missing_initcontainer)
TEST_F(state_transition, txcreate_light_failure_stack)
{
rev = EVMC_PRAGUE;
const auto deploy_container = eof_bytecode(bytecode(OP_INVALID));

const auto init_code = returncontract(0, 0, 0);
const bytes init_container = eof_bytecode(init_code, 2).container(deploy_container);

tx.type = Transaction::Type::initcodes;
tx.initcodes.push_back(init_container);

const auto factory_code =
push(0x123) + txcreate().value(1).initcode(0x43_bytes32).input(2, 3).salt(Salt) + push(1) +
OP_SSTORE + // store result from TXCREATE
push(0x123) + txcreate().value(1).initcode(keccak256(bytecode())).input(2, 3).salt(Salt) +
push(1) + OP_SSTORE + // store result from TXCREATE
push(2) +
OP_SSTORE + // store the preceding push value, nothing else should remain on stack
ret(0);
Expand Down

0 comments on commit fd27842

Please sign in to comment.