|
| 1 | +from typing import ( |
| 2 | + List, |
| 3 | +) |
| 4 | + |
| 5 | +from eth.exceptions import ( |
| 6 | + InsufficientStack, |
| 7 | + FullStack, |
| 8 | +) |
| 9 | + |
| 10 | +from eth.validation import ( |
| 11 | + validate_stack_int, |
| 12 | +) |
| 13 | + |
| 14 | +from eth.utils import ( |
| 15 | + big_endian_to_int, |
| 16 | + ValidationError, |
| 17 | +) |
| 18 | + |
| 19 | + |
| 20 | +""" |
| 21 | +This module simply implements for the return stack the exact same design used for the data stack. As this stack must simply push_int or pop1_int any time a subroutine is accessed or left, only those two functions are provided. For the same reason, the class RStack doesn't inherit from the abc StackAPI, as it would require to implement all the abstract methods defined. |
| 22 | +""" |
| 23 | + |
| 24 | +class RStack(): |
| 25 | + """ |
| 26 | + VM Return Stack |
| 27 | + """ |
| 28 | + |
| 29 | + __slots__ = ['values', '_append', '_pop_int', '__len__'] |
| 30 | + |
| 31 | + def __init__(self) -> None: |
| 32 | + values: List[int] |
| 33 | + self.values = values |
| 34 | + self._append = values.append |
| 35 | + self._pop_typed = values.pop |
| 36 | + self.__len__ = values.__len__ |
| 37 | + |
| 38 | + def push_int(self) -> int: |
| 39 | + if len(self.values) > 1023: |
| 40 | + raise FullStack('Stack limit reached') |
| 41 | + |
| 42 | + validate_stack_int(value) |
| 43 | + |
| 44 | + self._append((int, value)) |
| 45 | + |
| 46 | + |
| 47 | +def pop1_int(self) -> int: |
| 48 | + # |
| 49 | + # Note: This function is optimized for speed over readability. |
| 50 | + # |
| 51 | + if not self.values: |
| 52 | + raise InsufficientStack("Wanted 1 stack item as int, had none") |
| 53 | + else: |
| 54 | + item_type, popped = self._pop_typed() |
| 55 | + if item_type is int: |
| 56 | + return popped # type: ignore |
| 57 | + elif item_type is bytes: |
| 58 | + return big_endian_to_int(popped) # type: ignore |
| 59 | + else: |
| 60 | + raise _busted_type(item_type, popped) |
| 61 | + |
| 62 | +def _busted_type(item_type: type, value: Union[int, bytes]) -> ValidationError: |
| 63 | + return ValidationError( |
| 64 | + "Stack must always be bytes or int, " |
| 65 | + f"got {item_type!r} type, val {value!r}" |
| 66 | + ) |
| 67 | + |
| 68 | + |
0 commit comments