@@ -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,137 @@ 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>(
663+ trace, context::SR_IS_STATIC_IF_STATIC_CALL, context::SR_IS_STATIC_IF_CALL_FROM_STATIC_CONTEXT);
664+
665+ // Negative test: change is_static
666+ // regular call from non-static context cannot become static
667+ trace.set (C::execution_is_static, 2 , 1 );
668+ EXPECT_THROW_WITH_MESSAGE (check_relation<context>(trace, context::SR_IS_STATIC_IF_STATIC_CALL),
669+ " IS_STATIC_IF_STATIC_CALL" );
670+
671+ // reset is_static
672+ trace.set (C::execution_is_static, 2 , 0 );
673+ }
674+
675+ TEST (ContextConstrainingTest, IsStaticStaticCallFromNonStaticContext)
676+ {
677+ // Non-static context making a STATICCALL - should become static
678+ TestTraceContainer trace ({
679+ { { C::precomputed_first_row, 1 } },
680+ {
681+ { C::execution_sel, 1 },
682+ { C::execution_context_id, 1 },
683+ { C::execution_next_context_id, 2 },
684+ { C::execution_is_static, 0 }, // Non-static context
685+ { C::execution_sel_enter_call, 1 },
686+ { C::execution_sel_execute_call, 0 },
687+ { C::execution_sel_execute_static_call, 1 }, // STATICCALL
688+ },
689+ {
690+ { C::execution_sel, 1 },
691+ { C::execution_context_id, 2 },
692+ { C::execution_next_context_id, 3 },
693+ { C::execution_is_static, 1 }, // Should become static
694+ },
695+ });
696+ check_relation<context>(
697+ trace, context::SR_IS_STATIC_IF_STATIC_CALL, context::SR_IS_STATIC_IF_CALL_FROM_STATIC_CONTEXT);
698+
699+ // Negative test: change is_static
700+ // static call from non-static context MUST become static
701+ trace.set (C::execution_is_static, 2 , 0 );
702+ EXPECT_THROW_WITH_MESSAGE (check_relation<context>(trace, context::SR_IS_STATIC_IF_STATIC_CALL),
703+ " IS_STATIC_IF_STATIC_CALL" );
704+
705+ // reset is_static
706+ trace.set (C::execution_is_static, 2 , 1 );
707+ }
708+
709+ TEST (ContextConstrainingTest, IsStaticCallFromStaticContext)
710+ {
711+ // Static context making any call - must remain static
712+ TestTraceContainer trace ({
713+ { { C::precomputed_first_row, 1 } },
714+ {
715+ { C::execution_sel, 1 },
716+ { C::execution_context_id, 1 },
717+ { C::execution_next_context_id, 2 },
718+ { C::execution_is_static, 1 }, // Static context
719+ { C::execution_sel_enter_call, 1 },
720+ { C::execution_sel_execute_call, 1 }, // Regular CALL
721+ { C::execution_sel_execute_static_call, 0 },
722+ },
723+ {
724+ { C::execution_sel, 1 },
725+ { C::execution_context_id, 2 },
726+ { C::execution_next_context_id, 3 },
727+ { C::execution_is_static, 1 }, // Must remain static
728+ },
729+ });
730+ check_relation<context>(
731+ trace, context::SR_IS_STATIC_IF_STATIC_CALL, context::SR_IS_STATIC_IF_CALL_FROM_STATIC_CONTEXT);
732+
733+ // Negative test: change is_static
734+ // static call from static context MUST remain static
735+ trace.set (C::execution_is_static, 2 , 0 );
736+ EXPECT_THROW_WITH_MESSAGE (check_relation<context>(trace, context::SR_IS_STATIC_IF_CALL_FROM_STATIC_CONTEXT),
737+ " IS_STATIC_IF_CALL_FROM_STATIC_CONTEXT" );
738+
739+ // reset is_static
740+ trace.set (C::execution_is_static, 2 , 1 );
741+ }
742+
743+ TEST (ContextConstrainingTest, IsStaticPropagationWithoutCalls)
744+ {
745+ // is_static propagation without calls
746+ TestTraceContainer trace ({
747+ { { C::precomputed_first_row, 1 } },
748+ {
749+ { C::execution_sel, 1 },
750+ { C::execution_context_id, 1 },
751+ { C::execution_next_context_id, 1 },
752+ { C::execution_is_static, 1 }, // Static context
753+ },
754+ {
755+ { C::execution_sel, 1 },
756+ { C::execution_context_id, 1 },
757+ { C::execution_next_context_id, 1 },
758+ { C::execution_is_static, 1 }, // Should propagate
759+ },
760+ });
761+ check_relation<context>(trace, context::SR_IS_STATIC_NEXT_ROW);
762+
763+ // Negative test: change is_static
764+ // staticness must propagate without calls
765+ trace.set (C::execution_is_static, 2 , 0 );
766+ EXPECT_THROW_WITH_MESSAGE (check_relation<context>(trace, context::SR_IS_STATIC_NEXT_ROW), " IS_STATIC_NEXT_ROW" );
767+
768+ // reset is_static
769+ trace.set (C::execution_is_static, 2 , 1 );
770+ }
771+
636772TEST (ContextConstrainingTest, ContextIdPropagation)
637773{
638774 TestTraceContainer trace ({
0 commit comments