Skip to content

Commit

Permalink
Implement EIP-7480
Browse files Browse the repository at this point in the history
  • Loading branch information
gurukamath committed Jul 9, 2024
1 parent 7dc0cfd commit f672f5d
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 0 deletions.
8 changes: 8 additions & 0 deletions src/ethereum/prague/vm/eof.py
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,10 @@ def get_valid_instructions(code: bytes) -> Set[int]:
if len(code) < counter + 2:
raise InvalidEOF("CALLF target code section index missing")
counter += 2
elif opcode == Ops.DATALOADN:
if len(code) < counter + 2:
raise InvalidEOF("DATALOADN offset missing")
counter += 2

return valid_instructions

Expand Down Expand Up @@ -509,6 +513,10 @@ def validate_code_section(
elif opcode == Ops.RETF:
if code_section_index == 0:
raise InvalidEOF("First code section cannot return")
elif opcode == Ops.DATALOADN:
offset = Uint.from_be_bytes(code[counter + 1 : counter + 3])
if offset >= eof_meta.data_size:
raise InvalidEOF("Invalid DATALOADN offset")


def validate_eof_code(eof_meta: EOFMetadata) -> None:
Expand Down
3 changes: 3 additions & 0 deletions src/ethereum/prague/vm/gas.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@
GAS_RETF = Uint(3)
EOF_CALL_MIN_RETAINED_GAS = Uint(5000)
EOF_CALL_MIN_CALLEE_GAS = Uint(2300)
GAS_DATALOAD = Uint(4)
GAS_DATALOADN = Uint(3)
GAS_DATASIZE = Uint(2)

TARGET_BLOB_GAS_PER_BLOCK = U64(393216)
GAS_PER_BLOB = Uint(2**17)
Expand Down
4 changes: 4 additions & 0 deletions src/ethereum/prague/vm/instructions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,10 @@ class Ops(enum.Enum):
Ops.LOG2: log_instructions.log2,
Ops.LOG3: log_instructions.log3,
Ops.LOG4: log_instructions.log4,
Ops.DATALOAD: environment_instructions.dataload,
Ops.DATALOADN: environment_instructions.dataload_n,
Ops.DATASIZE: environment_instructions.datasize,
Ops.DATACOPY: environment_instructions.datacopy,
Ops.RJUMP: control_flow_instructions.rjump,
Ops.RJUMPI: control_flow_instructions.rjumpi,
Ops.RJUMPV: control_flow_instructions.rjumpv,
Expand Down
112 changes: 112 additions & 0 deletions src/ethereum/prague/vm/instructions/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
GAS_BLOBHASH_OPCODE,
GAS_COLD_ACCOUNT_ACCESS,
GAS_COPY,
GAS_DATALOAD,
GAS_DATALOADN,
GAS_DATASIZE,
GAS_FAST_STEP,
GAS_RETURN_DATA_COPY,
GAS_VERY_LOW,
Expand Down Expand Up @@ -623,3 +626,112 @@ def returndataload(evm: Evm) -> None:

# PROGRAM COUNTER
evm.pc += 1


def dataload(evm: Evm) -> None:
"""
Pushes 32-byte word to stack.
Parameters
----------
evm :
The current EVM frame.
"""
# STACK
offset = pop(evm.stack)

# GAS
charge_gas(evm, GAS_DATALOAD)

# OPERATION
assert evm.eof_meta is not None
value = U256.from_be_bytes(
buffer_read(evm.eof_meta.data_section_contents, offset, U256(32))
)
push(evm.stack, value)

# PROGRAM COUNTER
evm.pc += 1


def dataload_n(evm: Evm) -> None:
"""
Pushes 32-byte word to stack where the word is addressed
by a static immediate argument
Parameters
----------
evm :
The current EVM frame.
"""
# STACK
pass

# GAS
charge_gas(evm, GAS_DATALOADN)

# OPERATION
assert evm.eof_meta is not None
offset = U256.from_be_bytes(evm.code[evm.pc + 1 : evm.pc + 3])
value = U256.from_be_bytes(
buffer_read(evm.eof_meta.data_section_contents, offset, U256(32))
)
push(evm.stack, value)

# PROGRAM COUNTER
# 1 + 2 bytes of immediate data
evm.pc += 3


def datasize(evm: Evm) -> None:
"""
Pushes the data section size.
Parameters
----------
evm :
The current EVM frame.
"""
# STACK
pass

# GAS
charge_gas(evm, GAS_DATASIZE)

# OPERATION
assert evm.eof_meta is not None
push(evm.stack, U256(len(evm.eof_meta.data_section_contents)))

# PROGRAM COUNTER
evm.pc += 1


def datacopy(evm: Evm) -> None:
"""
Copies a segment of data section to memory.
Parameters
----------
evm :
The current EVM frame.
"""
# STACK
memory_start_index = pop(evm.stack)
offset = pop(evm.stack)
size = pop(evm.stack)

# GAS
copy_gas_cost = 3 + 3 * ((Uint(size) + 31) // 32)
extend_memory = calculate_gas_extend_memory(
evm.memory, [(memory_start_index, size)]
)
charge_gas(evm, copy_gas_cost + extend_memory.cost)

# OPERATION
assert evm.eof_meta is not None
evm.memory += b"\x00" * extend_memory.expand_by
value = buffer_read(evm.eof_meta.data_section_contents, offset, size)
memory_write(evm.memory, memory_start_index, value)

# PROGRAM COUNTER
evm.pc += 1
1 change: 1 addition & 0 deletions tests/prague/test_eof.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
TEST_DIRS = (
"tests/fixtures/latest_fork_tests/eof_tests/prague/eip7692_eof_v1/eip3540_eof_v1",
"tests/fixtures/latest_fork_tests/eof_tests/prague/eip7692_eof_v1/eip4200_relative_jumps",
"tests/fixtures/latest_fork_tests/eof_tests/prague/eip7692_eof_v1/eip7480_data_section",
)


Expand Down
1 change: 1 addition & 0 deletions tests/prague/test_state_transition.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
"tests/fixtures/latest_fork_tests/blockchain_tests/prague/eip7692_eof_v1/eip3540_eof_v1",
"tests/fixtures/latest_fork_tests/blockchain_tests/prague/eip7692_eof_v1/eip4200_relative_jumps",
"tests/fixtures/latest_fork_tests/blockchain_tests/prague/eip7692_eof_v1/eip7069_extcall",
"tests/fixtures/latest_fork_tests/blockchain_tests/prague/eip7692_eof_v1/eip7480_data_section",
)


Expand Down

0 comments on commit f672f5d

Please sign in to comment.