|
13 | 13 | // You should have received a copy of the GNU General Public License |
14 | 14 | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
15 | 15 |
|
| 16 | +#include <category/core/byte_string.hpp> |
16 | 17 | #include <category/core/int.hpp> |
17 | 18 | #include <category/execution/ethereum/block_hash_buffer.hpp> |
18 | 19 | #include <category/execution/ethereum/chain/ethereum_mainnet.hpp> |
|
40 | 41 | #include <optional> |
41 | 42 |
|
42 | 43 | using namespace monad; |
| 44 | +using namespace monad::literals; |
43 | 45 | using namespace monad::test; |
44 | 46 |
|
45 | 47 | namespace |
@@ -255,3 +257,93 @@ TYPED_TEST(TraitsTest, execute_reverted_insufficient_balance) |
255 | 257 |
|
256 | 258 | EXPECT_EQ(call_frames[0], expected); |
257 | 259 | } |
| 260 | + |
| 261 | +TYPED_TEST(TraitsTest, create_call_trace) |
| 262 | +{ |
| 263 | + InMemoryMachine machine; |
| 264 | + mpt::Db db{machine}; |
| 265 | + TrieDb tdb{db}; |
| 266 | + vm::VM vm; |
| 267 | + |
| 268 | + // Try to deploy a contract with reverting initcode |
| 269 | + auto const code = 0x60fe6000526001601f6000f0_bytes; |
| 270 | + auto const icode = vm::make_shared_intercode(code); |
| 271 | + auto const code_hash = to_bytes(keccak256(code)); |
| 272 | + |
| 273 | + commit_sequential( |
| 274 | + tdb, |
| 275 | + StateDeltas{ |
| 276 | + {ADDR_A, |
| 277 | + StateDelta{ |
| 278 | + .account = |
| 279 | + {std::nullopt, |
| 280 | + Account{ |
| 281 | + .balance = std::numeric_limits<uint256_t>::max()}}}}, |
| 282 | + {ADDR_B, |
| 283 | + StateDelta{ |
| 284 | + .account = |
| 285 | + {std::nullopt, |
| 286 | + Account{.balance = 0, .code_hash = code_hash}}}}}, |
| 287 | + Code{ |
| 288 | + {code_hash, icode}, |
| 289 | + }, |
| 290 | + BlockHeader{}); |
| 291 | + |
| 292 | + BlockState bs{tdb, vm}; |
| 293 | + Incarnation const incarnation{0, 0}; |
| 294 | + State s{bs, incarnation}; |
| 295 | + |
| 296 | + Transaction const tx{ |
| 297 | + .max_fee_per_gas = 1, |
| 298 | + .gas_limit = 1'000'000, |
| 299 | + .value = 0, |
| 300 | + .to = ADDR_B, |
| 301 | + }; |
| 302 | + |
| 303 | + auto const &sender = ADDR_A; |
| 304 | + auto const &beneficiary = ADDR_A; |
| 305 | + |
| 306 | + evmc_tx_context const tx_context{}; |
| 307 | + BlockHashBufferFinalized buffer{}; |
| 308 | + std::vector<CallFrame> call_frames; |
| 309 | + CallTracer call_tracer{tx, call_frames}; |
| 310 | + EvmcHost<typename TestFixture::Trait> host{ |
| 311 | + call_tracer, tx_context, buffer, s}; |
| 312 | + |
| 313 | + auto const result = |
| 314 | + ExecuteTransactionNoValidation<typename TestFixture::Trait>( |
| 315 | + EthereumMainnet{}, |
| 316 | + tx, |
| 317 | + sender, |
| 318 | + authorities_empty, |
| 319 | + BlockHeader{.beneficiary = beneficiary}, |
| 320 | + 0)(s, host); |
| 321 | + EXPECT_TRUE(result.status_code == EVMC_SUCCESS); |
| 322 | + ASSERT_TRUE(call_frames.size() == 2); |
| 323 | + |
| 324 | + // We don't care about the specific revision-dependent gas used in each call |
| 325 | + // frame, only that the outer frame succeeds while the inner one fails to |
| 326 | + // create and has a `std::nullopt` to address. |
| 327 | + |
| 328 | + EXPECT_EQ(call_frames[0].type, CallType::CALL); |
| 329 | + EXPECT_EQ(call_frames[0].flags, 0u); |
| 330 | + EXPECT_EQ(call_frames[0].from, sender); |
| 331 | + EXPECT_EQ(call_frames[0].to, ADDR_B); |
| 332 | + EXPECT_EQ(call_frames[0].value, 0u); |
| 333 | + EXPECT_EQ(call_frames[0].input, byte_string{}); |
| 334 | + EXPECT_EQ(call_frames[0].output, byte_string{}); |
| 335 | + EXPECT_EQ(call_frames[0].status, EVMC_SUCCESS); |
| 336 | + EXPECT_EQ(call_frames[0].depth, 0u); |
| 337 | + EXPECT_EQ(call_frames[0].logs, std::vector<CallFrame::Log>{}); |
| 338 | + |
| 339 | + EXPECT_EQ(call_frames[1].type, CallType::CREATE); |
| 340 | + EXPECT_EQ(call_frames[1].flags, 0u); |
| 341 | + EXPECT_EQ(call_frames[1].from, ADDR_B); |
| 342 | + EXPECT_EQ(call_frames[1].to, std::nullopt); |
| 343 | + EXPECT_EQ(call_frames[1].value, 0u); |
| 344 | + EXPECT_EQ(call_frames[1].input, 0xFE_bytes); |
| 345 | + EXPECT_EQ(call_frames[1].output, byte_string{}); |
| 346 | + EXPECT_EQ(call_frames[1].status, EVMC_FAILURE); |
| 347 | + EXPECT_EQ(call_frames[1].depth, 1u); |
| 348 | + EXPECT_EQ(call_frames[1].logs, std::vector<CallFrame::Log>{}); |
| 349 | +} |
0 commit comments