@@ -428,6 +428,8 @@ AvmError Execution::execute_enqueued_call(AvmTraceBuilder& trace_builder,
428428 // These hints help us to set up first call ctx
429429 uint32_t clk = trace_builder.get_clk ();
430430 auto context_id = static_cast <uint8_t >(clk);
431+ uint32_t l2_gas_allocated_to_enqueued_call = trace_builder.get_l2_gas_left ();
432+ uint32_t da_gas_allocated_to_enqueued_call = trace_builder.get_da_gas_left ();
431433 trace_builder.current_ext_call_ctx = AvmTraceBuilder::ExtCallCtx{
432434 .context_id = context_id,
433435 .parent_id = 0 ,
@@ -436,10 +438,13 @@ AvmError Execution::execute_enqueued_call(AvmTraceBuilder& trace_builder,
436438 .nested_returndata = {},
437439 .last_pc = 0 ,
438440 .success_offset = 0 ,
439- .l2_gas = 0 ,
440- .da_gas = 0 ,
441+ .start_l2_gas_left = l2_gas_allocated_to_enqueued_call,
442+ .start_da_gas_left = da_gas_allocated_to_enqueued_call,
443+ .l2_gas_left = l2_gas_allocated_to_enqueued_call,
444+ .da_gas_left = da_gas_allocated_to_enqueued_call,
441445 .internal_return_ptr_stack = {},
442446 };
447+ trace_builder.allocate_gas_for_call (l2_gas_allocated_to_enqueued_call, da_gas_allocated_to_enqueued_call);
443448 // Find the bytecode based on contract address of the public call request
444449 std::vector<uint8_t > bytecode =
445450 trace_builder.get_bytecode (trace_builder.current_ext_call_ctx .contract_address , check_bytecode_membership);
@@ -451,11 +456,13 @@ AvmError Execution::execute_enqueued_call(AvmTraceBuilder& trace_builder,
451456 std::stack<uint32_t > debug_counter_stack;
452457 uint32_t counter = 0 ;
453458 trace_builder.set_call_ptr (context_id);
454- while (is_ok (error) && (pc = trace_builder.get_pc ()) < bytecode.size ()) {
459+ while ((pc = trace_builder.get_pc ()) < bytecode.size ()) {
455460 auto [inst, parse_error] = Deserialization::parse (bytecode, pc);
456- error = parse_error;
457461
462+ // FIXME: properly handle case when an instruction fails parsing
463+ // especially first instruction in bytecode
458464 if (!is_ok (error)) {
465+ error = parse_error;
459466 break ;
460467 }
461468
@@ -848,9 +855,10 @@ AvmError Execution::execute_enqueued_call(AvmTraceBuilder& trace_builder,
848855 std::get<uint16_t >(inst.operands .at (3 )),
849856 std::get<uint16_t >(inst.operands .at (4 )),
850857 std::get<uint16_t >(inst.operands .at (5 )));
858+ // TODO: what if an error is encountered on return or call which have already modified stack?
851859 // We hack it in here the logic to change contract address that we are processing
852860 bytecode = trace_builder.get_bytecode (trace_builder.current_ext_call_ctx .contract_address ,
853- check_bytecode_membership );
861+ /* check_membership= */ false );
854862 debug_counter_stack.push (counter);
855863 counter = 0 ;
856864 break ;
@@ -864,7 +872,7 @@ AvmError Execution::execute_enqueued_call(AvmTraceBuilder& trace_builder,
864872 std::get<uint16_t >(inst.operands .at (5 )));
865873 // We hack it in here the logic to change contract address that we are processing
866874 bytecode = trace_builder.get_bytecode (trace_builder.current_ext_call_ctx .contract_address ,
867- check_bytecode_membership );
875+ /* check_membership= */ false );
868876 debug_counter_stack.push (counter);
869877 counter = 0 ;
870878 break ;
@@ -873,53 +881,58 @@ AvmError Execution::execute_enqueued_call(AvmTraceBuilder& trace_builder,
873881 auto ret = trace_builder.op_return (std::get<uint8_t >(inst.operands .at (0 )),
874882 std::get<uint16_t >(inst.operands .at (1 )),
875883 std::get<uint16_t >(inst.operands .at (2 )));
876- // We hack it in here the logic to change contract address that we are processing
884+ // did the return opcode hit an exceptional halt?
885+ error = ret.error ;
877886 if (ret.is_top_level ) {
878- error = ret.error ;
879887 returndata.insert (returndata.end (), ret.return_data .begin (), ret.return_data .end ());
880-
881- } else {
888+ } else if ( is_ok (error)) {
889+ // switch back to caller's bytecode
882890 bytecode = trace_builder.get_bytecode (trace_builder.current_ext_call_ctx .contract_address ,
883- check_bytecode_membership );
891+ /* check_membership= */ false );
884892 counter = debug_counter_stack.top ();
885893 debug_counter_stack.pop ();
886894 }
895+ // on error/exceptional-halt, jumping back to parent code is handled at bottom of execution loop
887896 break ;
888897 }
889898 case OpCode::REVERT_8: {
890899 info (" HIT REVERT_8 " , " [PC=" + std::to_string (pc) + " ] " + inst.to_string ());
891900 auto ret = trace_builder.op_revert (std::get<uint8_t >(inst.operands .at (0 )),
892901 std::get<uint8_t >(inst.operands .at (1 )),
893902 std::get<uint8_t >(inst.operands .at (2 )));
903+ // error is only set here if the revert opcode hit an exceptional halt
904+ // revert itself does not trigger "error"
905+ error = ret.error ;
894906 if (ret.is_top_level ) {
895- error = ret.error ;
896907 returndata.insert (returndata.end (), ret.return_data .begin (), ret.return_data .end ());
897- } else {
898- // change to the current ext call ctx
908+ } else if ( is_ok (error)) {
909+ // switch back to caller's bytecode
899910 bytecode = trace_builder.get_bytecode (trace_builder.current_ext_call_ctx .contract_address ,
900- check_bytecode_membership );
911+ /* check_membership= */ false );
901912 counter = debug_counter_stack.top ();
902913 debug_counter_stack.pop ();
903914 }
904-
915+ // on error/exceptional-halt, jumping back to parent code is handled at bottom of execution loop
905916 break ;
906917 }
907918 case OpCode::REVERT_16: {
908919 info (" HIT REVERT_16 " , " [PC=" + std::to_string (pc) + " ] " + inst.to_string ());
909920 auto ret = trace_builder.op_revert (std::get<uint8_t >(inst.operands .at (0 )),
910921 std::get<uint16_t >(inst.operands .at (1 )),
911922 std::get<uint16_t >(inst.operands .at (2 )));
923+ // error is only set here if the revert opcode hit an exceptional halt
924+ // revert itself does not trigger "error"
925+ error = ret.error ;
912926 if (ret.is_top_level ) {
913- error = ret.error ;
914927 returndata.insert (returndata.end (), ret.return_data .begin (), ret.return_data .end ());
915- } else {
916- // change to the current ext call ctx
928+ } else if ( is_ok (error)) {
929+ // switch back to caller's bytecode
917930 bytecode = trace_builder.get_bytecode (trace_builder.current_ext_call_ctx .contract_address ,
918- check_bytecode_membership );
931+ /* check_membership= */ false );
919932 counter = debug_counter_stack.top ();
920933 debug_counter_stack.pop ();
921934 }
922-
935+ // on error/exceptional-halt, jumping back to parent code is handled at bottom of execution loop
923936 break ;
924937 }
925938
@@ -987,18 +1000,36 @@ AvmError Execution::execute_enqueued_call(AvmTraceBuilder& trace_builder,
9871000 " ." );
9881001 break ;
9891002 }
990- }
991- if (!is_ok (error)) {
992- auto const error_ic = counter - 1 ; // Need adjustement as counter increment occurs in loop body
993- std::string reason_prefix = exceptionally_halted (error) ? " exceptional halt" : " REVERT opcode" ;
994- info (" AVM enqueued call halted due to " ,
995- reason_prefix,
996- " . Error: " ,
997- to_name (error),
998- " at PC: " ,
999- pc,
1000- " IC: " ,
1001- error_ic);
1003+
1004+ if (!is_ok (error)) {
1005+ const bool is_top_level = trace_builder.current_ext_call_ctx .context_id == 0 ;
1006+
1007+ auto const error_ic = counter - 1 ; // Need adjustement as counter increment occurs in loop body
1008+ std::string call_type = is_top_level ? " enqueued" : " nested" ;
1009+ info (" AVM " ,
1010+ call_type,
1011+ " call exceptionally halted. Error: " ,
1012+ to_name (error),
1013+ " at PC: " ,
1014+ pc,
1015+ " IC: " ,
1016+ error_ic);
1017+
1018+ trace_builder.handle_exceptional_halt ();
1019+
1020+ if (is_top_level) {
1021+ break ;
1022+ }
1023+ // otherwise, handle exceptional halt and proceed with execution in caller/parent
1024+ // We hack it in here the logic to change contract address that we are processing
1025+ bytecode = trace_builder.get_bytecode (trace_builder.current_ext_call_ctx .contract_address ,
1026+ /* check_membership=*/ false );
1027+ counter = debug_counter_stack.top ();
1028+ debug_counter_stack.pop ();
1029+
1030+ // reset error as we've now returned to caller
1031+ error = AvmError::NO_ERROR;
1032+ }
10021033 }
10031034 return error;
10041035}
0 commit comments