Skip to content

Commit

Permalink
feat(fw): create MSTORE macro
Browse files Browse the repository at this point in the history
  • Loading branch information
marioevz committed Jul 10, 2024
1 parent f3d5a8c commit f5797b5
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 0 deletions.
43 changes: 43 additions & 0 deletions src/ethereum_test_tools/tests/test_vm.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,49 @@
b"\x60\x00\x60\x00\x60\x01\xF9",
id="Op.EXTDELEGATECALL(address=1)",
),
pytest.param(
Om.MSTORE(b""),
b"",
id='Om.MSTORE(b"")',
),
pytest.param(
Om.MSTORE(bytes(range(32))),
bytes(Op.MSTORE(0, bytes(range(32)))),
id="Om.MSTORE(bytes(range(32)))",
),
pytest.param(
Om.MSTORE(bytes(range(64))),
bytes(Op.MSTORE(0, bytes(range(32))) + Op.MSTORE(32, bytes(range(32, 64)))),
id="Om.MSTORE(bytes(range(64)))",
),
pytest.param(
Om.MSTORE(bytes(range(33))),
bytes(
Op.MSTORE(0, bytes(range(32)))
+ Op.MLOAD(32)
+ Op.PUSH31[-1]
+ Op.AND
+ Op.PUSH32[b"\x20".ljust(32, b"\x00")]
+ Op.OR
+ Op.PUSH1(32)
+ Op.MSTORE
),
id="Om.MSTORE(bytes(range(33)))",
),
pytest.param(
Om.MSTORE(bytes(range(63))),
bytes(
Op.MSTORE(0, bytes(range(32)))
+ Op.MLOAD(32)
+ Op.PUSH1[-1]
+ Op.AND
+ Op.PUSH32[bytes(range(32, 63)).ljust(32, b"\x00")]
+ Op.OR
+ Op.PUSH1(32)
+ Op.MSTORE
),
id="Om.MSTORE(bytes(range(63)))",
),
],
)
def test_opcodes(opcodes: bytes, expected: bytes):
Expand Down
46 changes: 46 additions & 0 deletions src/ethereum_test_tools/vm/opcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -5706,6 +5706,35 @@ class Opcodes(Opcode, Enum):
]


def _mstore_operation(data: OpcodeCallArg = b"", offset: OpcodeCallArg = 0) -> Bytecode:
"""
Helper function to generate the bytecode that stores an arbitrary amount of data in memory.
"""
assert isinstance(offset, int)
if isinstance(data, int):
data = data.to_bytes(32, "big")
data = to_bytes(data) # type: ignore
bytecode = Bytecode()
for i in range(0, len(data), 32):
chunk = data[i : i + 32]
if len(chunk) == 32:
bytecode += Opcodes.MSTORE(offset, chunk)
else:
# We need to MLOAD the existing data at the offset and then do a bitwise OR with the
# new data to store it in memory.
bytecode += Opcodes.MLOAD(offset)
# Create a mask to zero out the leftmost bytes of the existing data.
mask_size = 32 - len(chunk)
bytecode += _push_opcodes_byte_list[mask_size - 1][-1]
bytecode += Opcodes.AND
bytecode += Opcodes.PUSH32[chunk.ljust(32, b"\x00")]
bytecode += Opcodes.OR
bytecode += _stack_argument_to_bytecode(offset)
bytecode += Opcodes.MSTORE
offset += len(chunk)
return bytecode


class Macros(Macro, Enum):
"""
Enum containing all macros.
Expand Down Expand Up @@ -5745,6 +5774,23 @@ class Macros(Macro, Enum):
SHA3(0, 100000000000)
"""

MSTORE = Macro(lambda_operation=_mstore_operation)
"""
MSTORE(data, offset)
----
Place data of arbitrary length into memory at a given offset.
Inputs
----
- data: The data to store in memory. Can be an integer or bytes.
- offset: The offset in memory to store the data.
Outputs
----
- None
"""


class UndefinedOpcodes(Opcode, Enum):
"""
Expand Down

0 comments on commit f5797b5

Please sign in to comment.