@@ -61,21 +61,25 @@ TEST(ContextConstrainingTest, ContextSwitchingCallReturn)
6161 { C::execution_context_id, 1 },
6262 { C::execution_next_context_id, 2 },
6363 { C::execution_bytecode_id, top_bytecode_id },
64+ { C::execution_is_static, 0 }, // Non-static context
6465 { C::execution_parent_l2_gas_limit, 2000 },
6566 { C::execution_parent_da_gas_limit, 4000 },
6667 { C::execution_parent_l2_gas_used, 500 },
6768 { C::execution_parent_da_gas_used, 1500 },
69+ { C::execution_enqueued_call_start, 1 },
6870 },
6971 // CALL
7072 {
7173 { C::execution_sel, 1 },
7274 { C::execution_pc, 1 },
7375 { C::execution_next_pc, 2 },
7476 { C::execution_sel_execute_call, 1 },
77+ { C::execution_sel_execute_static_call, 0 }, // Regular CALL, not STATICCALL
7578 { C::execution_sel_enter_call, 1 },
7679 { C::execution_context_id, 1 },
7780 { C::execution_next_context_id, 2 },
7881 { C::execution_bytecode_id, top_bytecode_id }, // Same as previous row (propagated)
82+ { C::execution_is_static, 0 }, // Still non-static
7983 { C::execution_rop_4_, /* cd offset=*/ 10 },
8084 { C::execution_register_2_, /* contract address=*/ 0xdeadbeef },
8185 { C::execution_register_3_, /* cd size=*/ 1 },
@@ -96,6 +100,7 @@ TEST(ContextConstrainingTest, ContextSwitchingCallReturn)
96100 { C::execution_has_parent_ctx, 1 },
97101 { C::execution_contract_address, 0xdeadbeef },
98102 { C::execution_bytecode_id, nested_bytecode_id }, // New bytecode_id on entering new context
103+ { C::execution_is_static, 0 }, // Remains non-static after regular CALL
99104 { C::execution_parent_calldata_addr, 10 },
100105 { C::execution_parent_calldata_size, 1 },
101106 },
@@ -633,6 +638,134 @@ TEST(ContextConstrainingTest, BytecodeIdPropagation)
633638 " BYTECODE_ID_NEXT_ROW" ); // Should fail constraint
634639}
635640
641+ TEST (ContextConstrainingTest, IsStaticRegularCallFromNonStaticContext)
642+ {
643+ // Non-static context making a regular CALL - should remain non-static
644+ TestTraceContainer trace ({
645+ { { C::precomputed_first_row, 1 } },
646+ {
647+ { C::execution_sel, 1 },
648+ { C::execution_context_id, 1 },
649+ { C::execution_next_context_id, 2 },
650+ { C::execution_is_static, 0 }, // Non-static context
651+ { C::execution_sel_enter_call, 1 },
652+ { C::execution_sel_execute_call, 1 }, // Regular CALL
653+ { C::execution_sel_execute_static_call, 0 },
654+ },
655+ {
656+ { C::execution_sel, 1 },
657+ { C::execution_context_id, 2 },
658+ { C::execution_next_context_id, 3 },
659+ { C::execution_is_static, 0 }, // Should remain non-static
660+ },
661+ });
662+ check_relation<context>(trace, context::SR_IS_STATIC_IF_STATIC_CALL);
663+
664+ // Negative test: change is_static
665+ // regular call from non-static context cannot become static
666+ trace.set (C::execution_is_static, 2 , 1 );
667+ EXPECT_THROW_WITH_MESSAGE (check_relation<context>(trace, context::SR_IS_STATIC_IF_STATIC_CALL),
668+ " IS_STATIC_IF_STATIC_CALL" );
669+
670+ // reset is_static
671+ trace.set (C::execution_is_static, 2 , 0 );
672+ }
673+
674+ TEST (ContextConstrainingTest, IsStaticStaticCallFromNonStaticContext)
675+ {
676+ // Non-static context making a STATICCALL - should become static
677+ TestTraceContainer trace ({
678+ { { C::precomputed_first_row, 1 } },
679+ {
680+ { C::execution_sel, 1 },
681+ { C::execution_context_id, 1 },
682+ { C::execution_next_context_id, 2 },
683+ { C::execution_is_static, 0 }, // Non-static context
684+ { C::execution_sel_enter_call, 1 },
685+ { C::execution_sel_execute_call, 0 },
686+ { C::execution_sel_execute_static_call, 1 }, // STATICCALL
687+ },
688+ {
689+ { C::execution_sel, 1 },
690+ { C::execution_context_id, 2 },
691+ { C::execution_next_context_id, 3 },
692+ { C::execution_is_static, 1 }, // Should become static
693+ },
694+ });
695+ check_relation<context>(trace, context::SR_IS_STATIC_IF_STATIC_CALL);
696+
697+ // Negative test: change is_static
698+ // static call from non-static context MUST become static
699+ trace.set (C::execution_is_static, 2 , 0 );
700+ EXPECT_THROW_WITH_MESSAGE (check_relation<context>(trace, context::SR_IS_STATIC_IF_STATIC_CALL),
701+ " IS_STATIC_IF_STATIC_CALL" );
702+
703+ // reset is_static
704+ trace.set (C::execution_is_static, 2 , 1 );
705+ }
706+
707+ TEST (ContextConstrainingTest, IsStaticCallFromStaticContext)
708+ {
709+ // Static context making any call - must remain static
710+ TestTraceContainer trace ({
711+ { { C::precomputed_first_row, 1 } },
712+ {
713+ { C::execution_sel, 1 },
714+ { C::execution_context_id, 1 },
715+ { C::execution_next_context_id, 2 },
716+ { C::execution_is_static, 1 }, // Static context
717+ { C::execution_sel_enter_call, 1 },
718+ { C::execution_sel_execute_call, 1 }, // Regular CALL
719+ { C::execution_sel_execute_static_call, 0 },
720+ },
721+ {
722+ { C::execution_sel, 1 },
723+ { C::execution_context_id, 2 },
724+ { C::execution_next_context_id, 3 },
725+ { C::execution_is_static, 1 }, // Must remain static
726+ },
727+ });
728+ check_relation<context>(trace, context::SR_IS_STATIC_IF_CALL_FROM_STATIC_CONTEXT);
729+
730+ // Negative test: change is_static
731+ // static call from static context MUST remain static
732+ trace.set (C::execution_is_static, 2 , 0 );
733+ EXPECT_THROW_WITH_MESSAGE (check_relation<context>(trace, context::SR_IS_STATIC_IF_CALL_FROM_STATIC_CONTEXT),
734+ " IS_STATIC_IF_CALL_FROM_STATIC_CONTEXT" );
735+
736+ // reset is_static
737+ trace.set (C::execution_is_static, 2 , 1 );
738+ }
739+
740+ TEST (ContextConstrainingTest, IsStaticPropagationWithoutCalls)
741+ {
742+ // is_static propagation without calls
743+ TestTraceContainer trace ({
744+ { { C::precomputed_first_row, 1 } },
745+ {
746+ { C::execution_sel, 1 },
747+ { C::execution_context_id, 1 },
748+ { C::execution_next_context_id, 1 },
749+ { C::execution_is_static, 1 }, // Static context
750+ },
751+ {
752+ { C::execution_sel, 1 },
753+ { C::execution_context_id, 1 },
754+ { C::execution_next_context_id, 1 },
755+ { C::execution_is_static, 1 }, // Should propagate
756+ },
757+ });
758+ check_relation<context>(trace, context::SR_IS_STATIC_NEXT_ROW);
759+
760+ // Negative test: change is_static
761+ // staticness must propagate without calls
762+ trace.set (C::execution_is_static, 2 , 0 );
763+ EXPECT_THROW_WITH_MESSAGE (check_relation<context>(trace, context::SR_IS_STATIC_NEXT_ROW), " IS_STATIC_NEXT_ROW" );
764+
765+ // reset is_static
766+ trace.set (C::execution_is_static, 2 , 1 );
767+ }
768+
636769TEST (ContextConstrainingTest, ContextIdPropagation)
637770{
638771 TestTraceContainer trace ({
0 commit comments