diff --git a/nimbus/evm/interpreter/gas_costs.nim b/nimbus/evm/interpreter/gas_costs.nim index a145c4916..d6a174968 100644 --- a/nimbus/evm/interpreter/gas_costs.nim +++ b/nimbus/evm/interpreter/gas_costs.nim @@ -630,6 +630,9 @@ template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) = # 5c & 5d: Transient storage operations Tload: fixed GasWarmStorageRead, Tstore: fixed GasWarmStorageRead, + + # 5e: Memory copy + Mcopy: memExpansion `prefix gasCopy`, # 5f, 60s & 70s: Push Operations Push0: fixed GasBase, diff --git a/nimbus/evm/interpreter/op_codes.nim b/nimbus/evm/interpreter/op_codes.nim index c11f4890a..46ec4f8bd 100644 --- a/nimbus/evm/interpreter/op_codes.nim +++ b/nimbus/evm/interpreter/op_codes.nim @@ -130,7 +130,7 @@ type Tload = 0x5c, ## Load word from transient storage. Tstore = 0x5d, ## Save word to transient storage. - Nop0x5E = 0x5e, ## Transfers control to a subroutine. + Mcopy = 0x5e, ## Memory copy # 5f, 60s & 70s: Push Operations. Push0 = 0x5f, ## Place 0 on stack. EIP-3855 diff --git a/nimbus/evm/interpreter/op_handlers/oph_memory.nim b/nimbus/evm/interpreter/op_handlers/oph_memory.nim index d3d0d0665..40c058bb5 100644 --- a/nimbus/evm/interpreter/op_handlers/oph_memory.nim +++ b/nimbus/evm/interpreter/op_handlers/oph_memory.nim @@ -321,6 +321,19 @@ const val = k.cpt.stack.popInt() k.cpt.setTransientStorage(slot, val) + mCopyOp: Vm2OpFn = proc (k: var Vm2Ctx) = + ## 0x5e, Copy memory + let (dst, src, size) = k.cpt.stack.popInt(3) + + let (dstPos, srcPos, len) = + (dst.cleanMemRef, src.cleanMemRef, size.cleanMemRef) + + k.cpt.gasMeter.consumeGas( + k.cpt.gasCosts[Mcopy].m_handler(k.cpt.memory.len, max(dstPos, srcPos), len), + reason = "Mcopy fee") + + k.cpt.memory.copy(dstPos, srcPos, len) + #[ EIP-2315: temporary disabled Reason : not included in berlin hard fork @@ -525,6 +538,14 @@ const info: "Save word to transient storage", exec: (prep: vm2OpIgnore, run: tstoreOp, + post: vm2OpIgnore)), + + (opCode: Mcopy, ## 0x5e, Copy memory + forks: Vm2OpCancunAndLater, + name: "MCopy", + info: "Copy memory", + exec: (prep: vm2OpIgnore, + run: mCopyOp, post: vm2OpIgnore))] #[ diff --git a/nimbus/evm/memory.nim b/nimbus/evm/memory.nim index bbe010074..f1271d245 100644 --- a/nimbus/evm/memory.nim +++ b/nimbus/evm/memory.nim @@ -52,3 +52,15 @@ proc write*(memory: var Memory, startPos: Natural, value: openArray[byte]) = validateLte(startPos + size, memory.len) for z, b in value: memory.bytes[z + startPos] = b + +proc copy*(memory: var Memory, dst, src, len: Natural) = + if len <= 0: return + memory.extend(max(dst, src), len) + if dst == src: + return + elif dst < src: + for i in 0.. dst + for i in countdown(len-1, 0): + memory.bytes[dst+i] = memory.bytes[src+i] diff --git a/tests/test_op_memory.nim b/tests/test_op_memory.nim index 14227ed50..060192bbc 100644 --- a/tests/test_op_memory.nim +++ b/tests/test_op_memory.nim @@ -812,5 +812,113 @@ proc opMemoryMain*() = "0x00" "0x0000000000000000000000000000002000000000000000000000000000000000" + assembler: + title: "MCOPY 1" + code: + PUSH32 "0x0000000000000000000000000000000000000000000000000000000000000000" + PUSH1 "0x00" + MSTORE + PUSH32 "0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" + PUSH1 "0x20" + MSTORE + PUSH1 "0x20" # len + PUSH1 "0x20" # src + PUSH1 "0x00" # dst + MCOPY + memory: + "0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" + "0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" + fork: Cancun + + assembler: + title: "MCOPY 2: Overlap" + code: + PUSH32 "0x0101010101010101010101010101010101010101010101010101010101010101" + PUSH1 "0x00" + MSTORE + PUSH1 "0x20" # len + PUSH1 "0x00" # src + PUSH1 "0x00" # dst + MCOPY + memory: + "0x0101010101010101010101010101010101010101010101010101010101010101" + fork: Cancun + + assembler: + title: "MCOPY 3" + code: + PUSH1 "0x00" + PUSH1 "0x00" + MSTORE8 + PUSH1 "0x01" + PUSH1 "0x01" + MSTORE8 + PUSH1 "0x02" + PUSH1 "0x02" + MSTORE8 + PUSH1 "0x03" + PUSH1 "0x03" + MSTORE8 + PUSH1 "0x04" + PUSH1 "0x04" + MSTORE8 + PUSH1 "0x05" + PUSH1 "0x05" + MSTORE8 + PUSH1 "0x06" + PUSH1 "0x06" + MSTORE8 + PUSH1 "0x07" + PUSH1 "0x07" + MSTORE8 + PUSH1 "0x08" + PUSH1 "0x08" + MSTORE8 + PUSH1 "0x08" # len + PUSH1 "0x01" # src + PUSH1 "0x00" # dst + MCOPY + memory: + "0x0102030405060708080000000000000000000000000000000000000000000000" + fork: Cancun + + assembler: + title: "MCOPY 4" + code: + PUSH1 "0x00" + PUSH1 "0x00" + MSTORE8 + PUSH1 "0x01" + PUSH1 "0x01" + MSTORE8 + PUSH1 "0x02" + PUSH1 "0x02" + MSTORE8 + PUSH1 "0x03" + PUSH1 "0x03" + MSTORE8 + PUSH1 "0x04" + PUSH1 "0x04" + MSTORE8 + PUSH1 "0x05" + PUSH1 "0x05" + MSTORE8 + PUSH1 "0x06" + PUSH1 "0x06" + MSTORE8 + PUSH1 "0x07" + PUSH1 "0x07" + MSTORE8 + PUSH1 "0x08" + PUSH1 "0x08" + MSTORE8 + PUSH1 "0x08" # len + PUSH1 "0x00" # src + PUSH1 "0x01" # dst + MCOPY + memory: + "0x0000010203040506070000000000000000000000000000000000000000000000" + fork: Cancun + when isMainModule: opMemoryMain()