Skip to content

Commit cf40b3f

Browse files
committed
fix(fw): max stack height calculation in __add__
1 parent 061e41c commit cf40b3f

File tree

1 file changed

+28
-5
lines changed

1 file changed

+28
-5
lines changed

src/ethereum_test_vm/bytecode.py

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -148,12 +148,35 @@ def __add__(self, other: "Bytecode | int | None") -> "Bytecode":
148148
a_min, a_max = self.min_stack_height, self.max_stack_height
149149
b_pop, b_push = other.popped_stack_items, other.pushed_stack_items
150150
b_min, b_max = other.min_stack_height, other.max_stack_height
151-
a_out = a_min - a_pop + a_push
152151

153-
c_pop = max(0, a_pop + (b_pop - a_push))
154-
c_push = max(0, a_push + b_push - b_pop)
155-
c_min = a_min if a_out >= b_min else (b_min - a_out) + a_min
156-
c_max = max(a_max + max(0, b_min - a_out), b_max + max(0, a_out - b_min))
152+
# NOTE: "_pop" is understood as the number of elements required by an instruction or
153+
# bytecode to be popped off the stack before it starts returning (pushing).
154+
155+
# Auxiliary variables representing "stages" of the execution of `c = a + b` bytecode:
156+
# Assume starting point 0 as reference:
157+
a_start = 0
158+
# A (potentially) pops some elements and reaches its "bottom", might be negative:
159+
a_bottom = a_start - a_pop
160+
# After this A pushes some elements, then B pops and reaches its "bottom":
161+
b_bottom = a_bottom + a_push - b_pop
162+
163+
# C's bottom is either at the bottom of A or B:
164+
c_bottom = min(a_bottom, b_bottom)
165+
if c_bottom == a_bottom:
166+
# C pops the same as A to reach its bottom, then the rest of A and B are C's "push"
167+
c_pop = a_pop
168+
c_push = a_push - b_pop + b_push
169+
else:
170+
# A and B are C's "pop" to reach its bottom, then pushes the same as B
171+
c_pop = a_pop - a_push + b_pop
172+
c_push = b_push
173+
174+
# C's minimum required stack is either A's or B's shifted by the net stack balance of A
175+
c_min = max(a_min, b_min + a_pop - a_push)
176+
177+
# C starts from c_min, then reaches max either in the spot where A reached a_max or in the
178+
# spot where B reached b_max, after A had completed.
179+
c_max = max(c_min + a_max - a_min, c_min - a_pop + a_push + b_max - b_min)
157180

158181
return Bytecode(
159182
bytes(self) + bytes(other),

0 commit comments

Comments
 (0)