From aef11c0265d088cf5ff9cdb9ed07dc9b76078516 Mon Sep 17 00:00:00 2001 From: Manuel Bilbao Date: Tue, 9 Apr 2024 15:44:50 -0300 Subject: [PATCH 01/29] Add jump and jumpdest opcodes --- system-contracts/contracts/EvmInterpreter.yul | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index dc3470df6..82e2ff9c5 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -289,6 +289,21 @@ object "EVMInterpreter" { sp := pushStackItem(sp, mulmod(a, b, N)) } + // NOTE: We don't currently do full jumpdest validation + // (i.e. validating a jumpdest isn't in PUSH data) + case 0x56 { // OP_JUMP + let counter + + counter, sp := popStackItem(sp) + + ip := add(add(BYTECODE_OFFSET(), 32), counter) + + // Check next opcode is JUMPDEST + let nextOpcode := readIP(ip) + if iszero(eq(nextOpcode, 0x5B)) { + revert(0, 0) + } + } case 0x55 { // OP_SSTORE let key, value @@ -299,6 +314,7 @@ object "EVMInterpreter" { // TODO: Handle cold/warm slots and updates, etc for gas costs. evmGasLeft := chargeGas(evmGasLeft, 100) } + case 0x5B {} // OP_JUMPDEST case 0x5F { // OP_PUSH0 let value := 0 From fd7fb79dae4c90e042c5f0178d22d0c6ce9a93fd Mon Sep 17 00:00:00 2001 From: Manuel Bilbao Date: Tue, 9 Apr 2024 16:09:35 -0300 Subject: [PATCH 02/29] Add jumpi opcode --- system-contracts/contracts/EvmInterpreter.yul | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index 82e2ff9c5..d9d98111b 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -304,6 +304,24 @@ object "EVMInterpreter" { revert(0, 0) } } + case 0x57 { // OP_JUMPI + let counter, b + + counter, sp := popStackItem(sp) + b, sp := popStackItem(sp) + + if iszero(b) { + continue + } + + ip := add(add(BYTECODE_OFFSET(), 32), counter) + + // Check next opcode is JUMPDEST + let nextOpcode := readIP(ip) + if iszero(eq(nextOpcode, 0x5B)) { + revert(0, 0) + } + } case 0x55 { // OP_SSTORE let key, value From 3fc1b85a699594bc63770999ab574ddab41913e6 Mon Sep 17 00:00:00 2001 From: Manuel Bilbao Date: Tue, 9 Apr 2024 16:42:09 -0300 Subject: [PATCH 03/29] Charge gas on jumps --- system-contracts/contracts/EvmInterpreter.yul | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index d9d98111b..474882222 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -298,6 +298,8 @@ object "EVMInterpreter" { ip := add(add(BYTECODE_OFFSET(), 32), counter) + evmGasLeft = chargeGas(evmGasLeft, 8) + // Check next opcode is JUMPDEST let nextOpcode := readIP(ip) if iszero(eq(nextOpcode, 0x5B)) { @@ -310,6 +312,8 @@ object "EVMInterpreter" { counter, sp := popStackItem(sp) b, sp := popStackItem(sp) + evmGasLeft = chargeGas(evmGasLeft, 10) + if iszero(b) { continue } From 8d599fb29cec1a4c665aa1fc50b32bca4edb8ce8 Mon Sep 17 00:00:00 2001 From: Manuel Bilbao Date: Tue, 9 Apr 2024 16:50:10 -0300 Subject: [PATCH 04/29] Add lt opcode --- system-contracts/contracts/EvmInterpreter.yul | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index b78d997ce..6aebd3b56 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -326,6 +326,16 @@ object "EVMInterpreter" { sp := pushStackItem(sp, mulmod(a, b, N)) } + case 0x10 { // OP_LT + let a, b + + a, sp := popStackItem(sp) + b, sp := popStackItem(sp) + + sp := pushStackItem(sp, lt(a, b)) + + evmGasLeft := chargeGas(evmGasLeft, 3) + } case 0x55 { // OP_SSTORE let key, value From f599f8d21a1bc6d9a82cc0099302557c5ed48af3 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Tue, 9 Apr 2024 16:55:33 -0300 Subject: [PATCH 05/29] Implement dup opcodes --- system-contracts/contracts/EvmInterpreter.yul | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index dc3470df6..bb3a33cf2 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -75,6 +75,20 @@ object "EVMInterpreter" { } } + function dupStackItem(sp, position) -> newSp { + let tempSp := sub(sp, mul(0x20, position)) + + if or(gt(tempSp, BYTECODE_OFFSET()), eq(tempSp, BYTECODE_OFFSET())) { + revert(0, 0) + } + + for { let i := 0 } lt(i, position + 1) { i := add(i, 1) } { + dup := mload(tempSp) + } + newSp := add(sp, 0x20) + mstore(newSp, item) + } + function popStackItem(sp) -> a, newSp { // We can not return any error here, because it would break compatibility if lt(sp, STACK_OFFSET()) { @@ -498,6 +512,86 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, 3) } + case 0x80 { // OP_DUP1 + dupStackItem(sp, 1) + + evmGasLeft := chargeGas(evmGasLeft, 3) + } + case 0x81 { // OP_DUP2 + dupStackItem(sp, 2) + + evmGasLeft := chargeGas(evmGasLeft, 3) + } + case 0x82 { // OP_DUP3 + dupStackItem(sp, 3) + + evmGasLeft := chargeGas(evmGasLeft, 3) + } + case 0x83 { // OP_DUP4 + dupStackItem(sp, 4) + + evmGasLeft := chargeGas(evmGasLeft, 3) + } + case 0x84 { // OP_DUP5 + dupStackItem(sp, 5) + + evmGasLeft := chargeGas(evmGasLeft, 3) + } + case 0x85 { // OP_DUP6 + dupStackItem(sp, 6) + + evmGasLeft := chargeGas(evmGasLeft, 3) + } + case 0x86 { // OP_DUP7 + dupStackItem(sp, 7) + + evmGasLeft := chargeGas(evmGasLeft, 3) + } + case 0x87 { // OP_DUP8 + dupStackItem(sp, 8) + + evmGasLeft := chargeGas(evmGasLeft, 3) + } + case 0x88 { // OP_DUP9 + dupStackItem(sp, 9) + + evmGasLeft := chargeGas(evmGasLeft, 3) + } + case 0x89 { // OP_DUP10 + dupStackItem(sp, 10) + + evmGasLeft := chargeGas(evmGasLeft, 3) + } + case 0x8A { // OP_DUP11 + dupStackItem(sp, 11) + + evmGasLeft := chargeGas(evmGasLeft, 3) + } + case 0x8B { // OP_DUP12 + dupStackItem(sp, 12) + + evmGasLeft := chargeGas(evmGasLeft, 3) + } + case 0x8C { // OP_DUP13 + dupStackItem(sp, 13) + + evmGasLeft := chargeGas(evmGasLeft, 3) + } + case 0x8D { // OP_DUP14 + dupStackItem(sp, 14) + + evmGasLeft := chargeGas(evmGasLeft, 3) + } + case 0x8E { // OP_DUP15 + dupStackItem(sp, 15) + + evmGasLeft := chargeGas(evmGasLeft, 3) + } + case 0x8F { // OP_DUP16 + dupStackItem(sp, 16) + + evmGasLeft := chargeGas(evmGasLeft, 3) + } // TODO: REST OF OPCODES default { // TODO: Revert properly here and report the unrecognized opcode From 34eeb1cdb8e9a183dc3094ad2f68c2f75c9999fa Mon Sep 17 00:00:00 2001 From: Manuel Bilbao Date: Tue, 9 Apr 2024 16:59:09 -0300 Subject: [PATCH 06/29] Add gt opcode --- system-contracts/contracts/EvmInterpreter.yul | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index 6aebd3b56..987389afd 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -336,6 +336,16 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, 3) } + case 0x11 { // OP_GT + let a, b + + a, sp := popStackItem(sp) + b, sp := popStackItem(sp) + + sp := pushStackItem(sp, gt(a, b)) + + evmGasLeft := chargeGas(evmGasLeft, 3) + } case 0x55 { // OP_SSTORE let key, value From f7bb8102f76d21f26ed4461d8c8d05c222368dc0 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Tue, 9 Apr 2024 17:10:55 -0300 Subject: [PATCH 07/29] refactor(dup opcode): move chargeGas() location --- system-contracts/contracts/EvmInterpreter.yul | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index bb3a33cf2..4cfb1d699 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -512,85 +512,85 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, 3) } - case 0x80 { // OP_DUP1 - dupStackItem(sp, 1) - + case 0x80 { // OP_DUP1 evmGasLeft := chargeGas(evmGasLeft, 3) + + dupStackItem(sp, 1) } case 0x81 { // OP_DUP2 - dupStackItem(sp, 2) - evmGasLeft := chargeGas(evmGasLeft, 3) + + dupStackItem(sp, 2) } case 0x82 { // OP_DUP3 - dupStackItem(sp, 3) - evmGasLeft := chargeGas(evmGasLeft, 3) + + dupStackItem(sp, 3) } - case 0x83 { // OP_DUP4 - dupStackItem(sp, 4) + case 0x83 { // OP_DUP4 + evmGasLeft := chargeGas(evmGasLeft, 3) - evmGasLeft := chargeGas(evmGasLeft, 3) + dupStackItem(sp, 4) } case 0x84 { // OP_DUP5 - dupStackItem(sp, 5) - evmGasLeft := chargeGas(evmGasLeft, 3) + + dupStackItem(sp, 5) } case 0x85 { // OP_DUP6 - dupStackItem(sp, 6) - evmGasLeft := chargeGas(evmGasLeft, 3) - } - case 0x86 { // OP_DUP7 - dupStackItem(sp, 7) + dupStackItem(sp, 6) + } + case 0x86 { // OP_DUP7 evmGasLeft := chargeGas(evmGasLeft, 3) + + dupStackItem(sp, 7) } case 0x87 { // OP_DUP8 - dupStackItem(sp, 8) - evmGasLeft := chargeGas(evmGasLeft, 3) + + dupStackItem(sp, 8) } case 0x88 { // OP_DUP9 - dupStackItem(sp, 9) - evmGasLeft := chargeGas(evmGasLeft, 3) - } - case 0x89 { // OP_DUP10 - dupStackItem(sp, 10) + dupStackItem(sp, 9) + } + case 0x89 { // OP_DUP10 evmGasLeft := chargeGas(evmGasLeft, 3) + + dupStackItem(sp, 10) } case 0x8A { // OP_DUP11 - dupStackItem(sp, 11) - evmGasLeft := chargeGas(evmGasLeft, 3) + + dupStackItem(sp, 11) } case 0x8B { // OP_DUP12 - dupStackItem(sp, 12) - evmGasLeft := chargeGas(evmGasLeft, 3) + + dupStackItem(sp, 12) } case 0x8C { // OP_DUP13 - dupStackItem(sp, 13) - evmGasLeft := chargeGas(evmGasLeft, 3) + + dupStackItem(sp, 13) } case 0x8D { // OP_DUP14 - dupStackItem(sp, 14) - evmGasLeft := chargeGas(evmGasLeft, 3) + + dupStackItem(sp, 14) } case 0x8E { // OP_DUP15 - dupStackItem(sp, 15) - evmGasLeft := chargeGas(evmGasLeft, 3) + + dupStackItem(sp, 15) } case 0x8F { // OP_DUP16 - dupStackItem(sp, 16) - evmGasLeft := chargeGas(evmGasLeft, 3) + + dupStackItem(sp, 16) } // TODO: REST OF OPCODES default { From e73e62729866a3babdc645e0aa3bf563240ba186 Mon Sep 17 00:00:00 2001 From: Manuel Bilbao Date: Tue, 9 Apr 2024 17:15:18 -0300 Subject: [PATCH 08/29] Add slt opcode --- system-contracts/contracts/EvmInterpreter.yul | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index 987389afd..da8f5f34c 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -346,6 +346,16 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, 3) } + case 0x12 { // OP_SLT + let a, b + + a, sp := popStackItem(sp) + b, sp := popStackItem(sp) + + sp := pushStackItem(sp, slt(a, b)) + + evmGasLeft := chargeGas(evmGasLeft, 3) + } case 0x55 { // OP_SSTORE let key, value From 65e5776363ab79b2f6221dc33d591ac2d3f597be Mon Sep 17 00:00:00 2001 From: Manuel Bilbao Date: Tue, 9 Apr 2024 17:21:59 -0300 Subject: [PATCH 09/29] Add sgt opcode --- system-contracts/contracts/EvmInterpreter.yul | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index da8f5f34c..e5dd44ec6 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -356,6 +356,16 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, 3) } + case 0x13 { // OP_SGT + let a, b + + a, sp := popStackItem(sp) + b, sp := popStackItem(sp) + + sp := pushStackItem(sp, sgt(a, b)) + + evmGasLeft := chargeGas(evmGasLeft, 3) + } case 0x55 { // OP_SSTORE let key, value From e9ffbca1c19d0f1e33ec9d519731d46c817ed71d Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Tue, 9 Apr 2024 17:27:02 -0300 Subject: [PATCH 10/29] fix(dup-opcode): Replace + with add() --- system-contracts/contracts/EvmInterpreter.yul | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index 4cfb1d699..78d4db39f 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -82,7 +82,7 @@ object "EVMInterpreter" { revert(0, 0) } - for { let i := 0 } lt(i, position + 1) { i := add(i, 1) } { + for { let i := 0 } lt(i, add(position, 1)) { i := add(i, 1) } { dup := mload(tempSp) } newSp := add(sp, 0x20) From 8feb51f6c84b408c1e57d457560fce68bd43ee8b Mon Sep 17 00:00:00 2001 From: Manuel Bilbao Date: Tue, 9 Apr 2024 17:30:29 -0300 Subject: [PATCH 11/29] Add eq opcode --- system-contracts/contracts/EvmInterpreter.yul | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index e5dd44ec6..73ce5dfe0 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -366,6 +366,16 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, 3) } + case 0x14 { // OP_EQ + let a, b + + a, sp := popStackItem(sp) + b, sp := popStackItem(sp) + + sp := pushStackItem(sp, eq(a, b)) + + evmGasLeft := chargeGas(evmGasLeft, 3) + } case 0x55 { // OP_SSTORE let key, value From f7bf68eda7ff97e94233c447409d1e01657e272d Mon Sep 17 00:00:00 2001 From: Manuel Bilbao Date: Tue, 9 Apr 2024 17:36:41 -0300 Subject: [PATCH 12/29] Add iszero opcode --- system-contracts/contracts/EvmInterpreter.yul | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index 73ce5dfe0..49a578629 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -376,6 +376,15 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, 3) } + case 0x15 { // OP_ISZERO + let a + + a, sp := popStackItem(sp) + + sp := pushStackItem(sp, iszero(a)) + + evmGasLeft := chargeGas(evmGasLeft, 3) + } case 0x55 { // OP_SSTORE let key, value From 67d035740c19d904f383f5b6a5f593aa66df16f1 Mon Sep 17 00:00:00 2001 From: Manuel Bilbao Date: Tue, 9 Apr 2024 17:47:07 -0300 Subject: [PATCH 13/29] Add xor opcode --- system-contracts/contracts/EvmInterpreter.yul | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index 49a578629..904308d1f 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -385,6 +385,16 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, 3) } + case 0x18 { // OP_XOR + let a, b + + a, sp := popStackItem(sp) + b, sp := popStackItem(sp) + + sp := pushStackItem(sp, xor(a, b)) + + evmGasLeft := chargeGas(evmGasLeft, 3) + } case 0x55 { // OP_SSTORE let key, value From d2a33c33dd8fc3ee835fdeb23baee361f2e5305b Mon Sep 17 00:00:00 2001 From: Manuel Bilbao Date: Tue, 9 Apr 2024 17:53:29 -0300 Subject: [PATCH 14/29] Add not opcode --- system-contracts/contracts/EvmInterpreter.yul | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index 904308d1f..231954ba9 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -395,6 +395,15 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, 3) } + case 0x19 { // OP_NOT + let a + + a, sp := popStackItem(sp) + + sp := pushStackItem(sp, not(a)) + + evmGasLeft := chargeGas(evmGasLeft, 3) + } case 0x55 { // OP_SSTORE let key, value From e0d3ea05448c17e8aae5b963d3948a8bd0dbc630 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Tue, 9 Apr 2024 18:23:15 -0300 Subject: [PATCH 15/29] feat(dup-opcode): Implement tested opcode --- system-contracts/contracts/EvmInterpreter.yul | 80 ++++++------------- 1 file changed, 26 insertions(+), 54 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index 78d4db39f..eac1bb96b 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -75,18 +75,22 @@ object "EVMInterpreter" { } } - function dupStackItem(sp, position) -> newSp { - let tempSp := sub(sp, mul(0x20, position)) + function dupStackItem(sp, evmGas, position) -> newSp, evmGasLeft { + evmGasLeft := chargeGas(evmGas, 3) + let tempSp := sub(sp, mul(0x20, sub(position, 1))) if or(gt(tempSp, BYTECODE_OFFSET()), eq(tempSp, BYTECODE_OFFSET())) { revert(0, 0) } - - for { let i := 0 } lt(i, add(position, 1)) { i := add(i, 1) } { - dup := mload(tempSp) + + if lt(tempSp, STACK_OFFSET()) { + revert(0, 0) } + + let dup := mload(tempSp) + newSp := add(sp, 0x20) - mstore(newSp, item) + mstore(newSp, dup) } function popStackItem(sp) -> a, newSp { @@ -513,84 +517,52 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, 3) } case 0x80 { // OP_DUP1 - evmGasLeft := chargeGas(evmGasLeft, 3) - - dupStackItem(sp, 1) + sp, evmGasLeft := dupStackItem(sp, evmGasLeft, 1) } case 0x81 { // OP_DUP2 - evmGasLeft := chargeGas(evmGasLeft, 3) - - dupStackItem(sp, 2) + sp, evmGasLeft := dupStackItem(sp, evmGasLeft, 2) } case 0x82 { // OP_DUP3 - evmGasLeft := chargeGas(evmGasLeft, 3) - - dupStackItem(sp, 3) + sp, evmGasLeft := dupStackItem(sp, evmGasLeft, 3) } case 0x83 { // OP_DUP4 - evmGasLeft := chargeGas(evmGasLeft, 3) - - dupStackItem(sp, 4) + sp, evmGasLeft := dupStackItem(sp, evmGasLeft, 4) } case 0x84 { // OP_DUP5 - evmGasLeft := chargeGas(evmGasLeft, 3) - - dupStackItem(sp, 5) + sp, evmGasLeft := dupStackItem(sp, evmGasLeft, 5) } case 0x85 { // OP_DUP6 - evmGasLeft := chargeGas(evmGasLeft, 3) - - dupStackItem(sp, 6) + sp, evmGasLeft := dupStackItem(sp, evmGasLeft, 6) } case 0x86 { // OP_DUP7 - evmGasLeft := chargeGas(evmGasLeft, 3) - - dupStackItem(sp, 7) + sp, evmGasLeft := dupStackItem(sp, evmGasLeft, 7) } case 0x87 { // OP_DUP8 - evmGasLeft := chargeGas(evmGasLeft, 3) - - dupStackItem(sp, 8) + sp, evmGasLeft := dupStackItem(sp, evmGasLeft, 8) } case 0x88 { // OP_DUP9 - evmGasLeft := chargeGas(evmGasLeft, 3) - - dupStackItem(sp, 9) + sp, evmGasLeft := dupStackItem(sp, evmGasLeft, 9) } case 0x89 { // OP_DUP10 - evmGasLeft := chargeGas(evmGasLeft, 3) - - dupStackItem(sp, 10) + sp, evmGasLeft := dupStackItem(sp, evmGasLeft, 10) } case 0x8A { // OP_DUP11 - evmGasLeft := chargeGas(evmGasLeft, 3) - - dupStackItem(sp, 11) + sp, evmGasLeft := dupStackItem(sp, evmGasLeft, 11) } case 0x8B { // OP_DUP12 - evmGasLeft := chargeGas(evmGasLeft, 3) - - dupStackItem(sp, 12) + sp, evmGasLeft := dupStackItem(sp, evmGasLeft, 12) } case 0x8C { // OP_DUP13 - evmGasLeft := chargeGas(evmGasLeft, 3) - - dupStackItem(sp, 13) + sp, evmGasLeft := dupStackItem(sp, evmGasLeft, 13) } case 0x8D { // OP_DUP14 - evmGasLeft := chargeGas(evmGasLeft, 3) - - dupStackItem(sp, 14) + sp, evmGasLeft := dupStackItem(sp, evmGasLeft, 14) } case 0x8E { // OP_DUP15 - evmGasLeft := chargeGas(evmGasLeft, 3) - - dupStackItem(sp, 15) + sp, evmGasLeft := dupStackItem(sp, evmGasLeft, 15) } case 0x8F { // OP_DUP16 - evmGasLeft := chargeGas(evmGasLeft, 3) - - dupStackItem(sp, 16) + sp, evmGasLeft := dupStackItem(sp, evmGasLeft, 16) } // TODO: REST OF OPCODES default { From 0b86f675b0b194fd3e4df3f91219908e8a56f3cb Mon Sep 17 00:00:00 2001 From: Manuel Bilbao Date: Wed, 10 Apr 2024 10:34:39 -0300 Subject: [PATCH 16/29] Add byte opcode --- system-contracts/contracts/EvmInterpreter.yul | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index 231954ba9..69f6b8a96 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -404,6 +404,16 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, 3) } + case 0x1A { // OP_BYTE + let i, x + + i, sp := popStackItem(sp) + x, sp := popStackItem(sp) + + sp := pushStackItem(sp, byte(i, x)) + + evmGasLeft := chargeGas(evmGasLeft, 3) + } case 0x55 { // OP_SSTORE let key, value From 546745e13f6b1e2620c6126c9188ac980503d7b4 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 10 Apr 2024 10:36:21 -0300 Subject: [PATCH 17/29] feat(swap-opcode): Add swap opcodes --- system-contracts/contracts/EvmInterpreter.yul | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index eac1bb96b..860243f1e 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -93,6 +93,26 @@ object "EVMInterpreter" { mstore(newSp, dup) } + function swapStackItem(sp, evmGas, position) -> evmGasLeft { + evmGasLeft := chargeGas(evmGas, 3) + let tempSp := sub(sp, mul(0x20, position)) + + if or(gt(tempSp, BYTECODE_OFFSET()), eq(tempSp, BYTECODE_OFFSET())) { + revert(0, 0) + } + + if lt(tempSp, STACK_OFFSET()) { + revert(0, 0) + } + + + let s2 := mload(sp) + let s1 := mload(tempSp) + + mstore(sp, s1) + mstore(tempSp, s2) + } + function popStackItem(sp) -> a, newSp { // We can not return any error here, because it would break compatibility if lt(sp, STACK_OFFSET()) { @@ -564,6 +584,54 @@ object "EVMInterpreter" { case 0x8F { // OP_DUP16 sp, evmGasLeft := dupStackItem(sp, evmGasLeft, 16) } + case 0x90 { // OP_SWAP1 + evmGasLeft := swapStackItem(sp, evmGasLeft, 1) + } + case 0x91 { // OP_SWAP2 + evmGasLeft := swapStackItem(sp, evmGasLeft, 2) + } + case 0x92 { // OP_SWAP3 + evmGasLeft := swapStackItem(sp, evmGasLeft, 3) + } + case 0x93 { // OP_SWAP4 + evmGasLeft := swapStackItem(sp, evmGasLeft, 4) + } + case 0x94 { // OP_SWAP5 + evmGasLeft := swapStackItem(sp, evmGasLeft, 5) + } + case 0x95 { // OP_SWAP6 + evmGasLeft := swapStackItem(sp, evmGasLeft, 6) + } + case 0x96 { // OP_SWAP7 + evmGasLeft := swapStackItem(sp, evmGasLeft, 7) + } + case 0x97 { // OP_SWAP8 + evmGasLeft := swapStackItem(sp, evmGasLeft, 8) + } + case 0x98 { // OP_SWAP9 + evmGasLeft := swapStackItem(sp, evmGasLeft, 9) + } + case 0x99 { // OP_SWAP10 + evmGasLeft := swapStackItem(sp, evmGasLeft, 10) + } + case 0x9A { // OP_SWAP11 + evmGasLeft := swapStackItem(sp, evmGasLeft, 11) + } + case 0x9B { // OP_SWAP12 + evmGasLeft := swapStackItem(sp, evmGasLeft, 12) + } + case 0x9C { // OP_SWAP13 + evmGasLeft := swapStackItem(sp, evmGasLeft, 13) + } + case 0x9D { // OP_SWAP14 + evmGasLeft := swapStackItem(sp, evmGasLeft, 14) + } + case 0x9E { // OP_SWAP15 + evmGasLeft := swapStackItem(sp, evmGasLeft, 15) + } + case 0x9F { // OP_SWAP16 + evmGasLeft := swapStackItem(sp, evmGasLeft, 16) + } // TODO: REST OF OPCODES default { // TODO: Revert properly here and report the unrecognized opcode From 3dafe74bb6e139b4baf3416ed669925aeeba6def Mon Sep 17 00:00:00 2001 From: Manuel Bilbao Date: Wed, 10 Apr 2024 12:07:27 -0300 Subject: [PATCH 18/29] Fix sintaxis error --- system-contracts/contracts/EvmInterpreter.yul | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index 0c6df778d..d45f31e91 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -345,7 +345,7 @@ object "EVMInterpreter" { ip := add(add(BYTECODE_OFFSET(), 32), counter) - evmGasLeft = chargeGas(evmGasLeft, 8) + evmGasLeft := chargeGas(evmGasLeft, 8) // Check next opcode is JUMPDEST let nextOpcode := readIP(ip) @@ -359,7 +359,7 @@ object "EVMInterpreter" { counter, sp := popStackItem(sp) b, sp := popStackItem(sp) - evmGasLeft = chargeGas(evmGasLeft, 10) + evmGasLeft := chargeGas(evmGasLeft, 10) if iszero(b) { continue From 00cf1e87ae27a10d0cc0ba5a753df6cff03c940a Mon Sep 17 00:00:00 2001 From: Manuel Bilbao Date: Wed, 10 Apr 2024 11:25:40 -0300 Subject: [PATCH 19/29] Add pop opcode --- system-contracts/contracts/EvmInterpreter.yul | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index d3dbbb93d..f36f5c0b4 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -337,6 +337,13 @@ object "EVMInterpreter" { sp := pushStackItem(sp, mulmod(a, b, N)) } + case 0x50 { // OP_POP + let _y + + _y, sp := popStackItem(sp) + + evmGasLeft := chargeGas(evmGasLeft, 2) + } case 0x55 { // OP_SSTORE let key, value From c49c0eda67403403839deb490151ed091147b83c Mon Sep 17 00:00:00 2001 From: Javier Chatruc Date: Wed, 10 Apr 2024 14:35:28 -0300 Subject: [PATCH 20/29] Make prints not clobber each other when called in succesion --- system-contracts/contracts/EvmInterpreter.yul | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index d3dbbb93d..85ce817ea 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -182,16 +182,23 @@ object "EVMInterpreter" { gasRemaining := sub(prevGas, toCharge) } + // Essentially a NOP that will not get optimized away by the compiler + function $llvm_NoInline_llvm$_unoptimized() { + pop(1) + } + function printHex(value) { mstore(add(DEBUG_SLOT_OFFSET(), 0x20), 0x00debdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebde) mstore(add(DEBUG_SLOT_OFFSET(), 0x40), value) mstore(DEBUG_SLOT_OFFSET(), 0x4A15830341869CAA1E99840C97043A1EA15D2444DA366EFFF5C43B4BEF299681) + $llvm_NoInline_llvm$_unoptimized() } function printString(value) { mstore(add(DEBUG_SLOT_OFFSET(), 0x20), 0x00debdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdf) mstore(add(DEBUG_SLOT_OFFSET(), 0x40), value) mstore(DEBUG_SLOT_OFFSET(), 0x4A15830341869CAA1E99840C97043A1EA15D2444DA366EFFF5C43B4BEF299681) + $llvm_NoInline_llvm$_unoptimized() } //////////////////////////////////////////////////////////////// From 159cf9a012c1120743d4e309fb17b18634216033 Mon Sep 17 00:00:00 2001 From: Manuel Bilbao Date: Wed, 10 Apr 2024 15:53:23 -0300 Subject: [PATCH 21/29] Add mload and mstore opcodes --- system-contracts/contracts/EvmInterpreter.yul | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index 62bd7e670..ad1196f3f 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -182,6 +182,18 @@ object "EVMInterpreter" { gasRemaining := sub(prevGas, toCharge) } + function roundUp(value, multiple) -> rounded { + let reminder := mod(value, multiple) + + switch reminder + case 0 { + rounded := value + } + default { + rounded := sub(add(value, multiple), reminder) + } + } + // Essentially a NOP that will not get optimized away by the compiler function $llvm_NoInline_llvm$_unoptimized() { pop(1) @@ -351,6 +363,35 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, 2) } + case 0x51 { // OP_MLOAD + let offset + + offset, sp := popStackItem(sp) + + let end := add(offset, 32) + if gt(end, mload(MEM_OFFSET())) { + let newSize := roundUp(end, 32) + mstore(sub(add(MEM_OFFSET_INNER(), newSize), 32), 0) + mstore(MEM_OFFSET(), newSize) + } + + sp := pushStackItem(sp, mload(add(MEM_OFFSET_INNER(), offset))) + } + case 0x52 { // OP_MSTORE + let offset, value + + offset, sp := popStackItem(sp) + value, sp := popStackItem(sp) + + let end := add(offset, 32) + if gt(end, mload(MEM_OFFSET())) { + let newSize := roundUp(end, 32) + mstore(sub(add(MEM_OFFSET_INNER(), newSize), 32), 0) + mstore(MEM_OFFSET(), newSize) + } + + mstore(add(MEM_OFFSET_INNER(), offset), value) + } case 0x55 { // OP_SSTORE let key, value From a280712aced0600d32c6a4f8b601ad93ae850ef1 Mon Sep 17 00:00:00 2001 From: Manuel Bilbao Date: Wed, 10 Apr 2024 16:28:20 -0300 Subject: [PATCH 22/29] Fix memory expansion on mload and mstore Before, it only set the latest 32 bytes to 0. Now it sets all the necessary --- system-contracts/contracts/EvmInterpreter.yul | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index ad1196f3f..17c0f8877 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -369,9 +369,12 @@ object "EVMInterpreter" { offset, sp := popStackItem(sp) let end := add(offset, 32) - if gt(end, mload(MEM_OFFSET())) { + let currentEnd := mload(MEM_OFFSET()) + if gt(end, currentEnd) { let newSize := roundUp(end, 32) - mstore(sub(add(MEM_OFFSET_INNER(), newSize), 32), 0) + for {} lt(currentEnd, newSize) { currentEnd := add(currentEnd, 32) } { + mstore(currentEnd, 0) + } mstore(MEM_OFFSET(), newSize) } @@ -384,9 +387,12 @@ object "EVMInterpreter" { value, sp := popStackItem(sp) let end := add(offset, 32) + let currentEnd := mload(MEM_OFFSET()) if gt(end, mload(MEM_OFFSET())) { let newSize := roundUp(end, 32) - mstore(sub(add(MEM_OFFSET_INNER(), newSize), 32), 0) + for {} lt(currentEnd, newSize) { currentEnd := add(currentEnd, 32) } { + mstore(currentEnd, 0) + } mstore(MEM_OFFSET(), newSize) } From 930912d6ff7dd2ade4b8f58bbbd57c05a93b2961 Mon Sep 17 00:00:00 2001 From: Manuel Bilbao Date: Wed, 10 Apr 2024 16:34:16 -0300 Subject: [PATCH 23/29] Replace expression with already calculated variable --- system-contracts/contracts/EvmInterpreter.yul | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index 17c0f8877..e8768ef28 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -388,7 +388,7 @@ object "EVMInterpreter" { let end := add(offset, 32) let currentEnd := mload(MEM_OFFSET()) - if gt(end, mload(MEM_OFFSET())) { + if gt(end, currentEnd) { let newSize := roundUp(end, 32) for {} lt(currentEnd, newSize) { currentEnd := add(currentEnd, 32) } { mstore(currentEnd, 0) From 115074a943c9708ce7e910afa86d2f8f6d52873f Mon Sep 17 00:00:00 2001 From: Manuel Bilbao Date: Wed, 10 Apr 2024 16:41:13 -0300 Subject: [PATCH 24/29] Charge gas on mload and mstore --- system-contracts/contracts/EvmInterpreter.yul | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index e8768ef28..bec6f7523 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -368,17 +368,21 @@ object "EVMInterpreter" { offset, sp := popStackItem(sp) + let gasCounter := 3 + let end := add(offset, 32) let currentEnd := mload(MEM_OFFSET()) if gt(end, currentEnd) { let newSize := roundUp(end, 32) for {} lt(currentEnd, newSize) { currentEnd := add(currentEnd, 32) } { + gasCounter := add(gasCounter, 3) mstore(currentEnd, 0) } mstore(MEM_OFFSET(), newSize) } sp := pushStackItem(sp, mload(add(MEM_OFFSET_INNER(), offset))) + evmGasLeft := chargeGas(evmGasLeft, gasCounter) } case 0x52 { // OP_MSTORE let offset, value @@ -386,17 +390,21 @@ object "EVMInterpreter" { offset, sp := popStackItem(sp) value, sp := popStackItem(sp) + let gasCounter := 3 + let end := add(offset, 32) let currentEnd := mload(MEM_OFFSET()) if gt(end, currentEnd) { let newSize := roundUp(end, 32) for {} lt(currentEnd, newSize) { currentEnd := add(currentEnd, 32) } { + gasCounter := add(gasCounter, 3) mstore(currentEnd, 0) } mstore(MEM_OFFSET(), newSize) } mstore(add(MEM_OFFSET_INNER(), offset), value) + evmGasLeft := chargeGas(evmGasLeft, gasCounter) } case 0x55 { // OP_SSTORE let key, value From 257788e143f9a96902b9dc2023fd38314edad23c Mon Sep 17 00:00:00 2001 From: Manuel Bilbao Date: Wed, 10 Apr 2024 17:04:38 -0300 Subject: [PATCH 25/29] Add mstore8 opcode --- system-contracts/contracts/EvmInterpreter.yul | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index bec6f7523..941bceed6 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -406,6 +406,24 @@ object "EVMInterpreter" { mstore(add(MEM_OFFSET_INNER(), offset), value) evmGasLeft := chargeGas(evmGasLeft, gasCounter) } + case 0x53 { // OP_MSTORE8 + let offset, value + + offset, sp := popStackItem(sp) + value, sp := popStackItem(sp) + + let end := add(offset, 1) + let currentEnd := mload(MEM_OFFSET()) + if gt(end, currentEnd) { + let newSize := roundUp(end, 32) + for {} lt(currentEnd, newSize) {currentEnd := add(currentEnd, 32)} { + mstore(currentEnd, 0) + } + mstore(MEM_OFFSET(), newSize) + } + + mstore8(add(MEM_OFFSET_INNER(), offset), value) + } case 0x55 { // OP_SSTORE let key, value From cffd0cf90943a3705723e584af6a6944159ec7b1 Mon Sep 17 00:00:00 2001 From: Manuel Bilbao Date: Wed, 10 Apr 2024 17:08:20 -0300 Subject: [PATCH 26/29] Charge gas on mstore8 --- system-contracts/contracts/EvmInterpreter.yul | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index 941bceed6..cf30a967c 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -412,17 +412,21 @@ object "EVMInterpreter" { offset, sp := popStackItem(sp) value, sp := popStackItem(sp) + let gasCounter := 3 + let end := add(offset, 1) let currentEnd := mload(MEM_OFFSET()) if gt(end, currentEnd) { let newSize := roundUp(end, 32) for {} lt(currentEnd, newSize) {currentEnd := add(currentEnd, 32)} { + gasCounter := add(gasCounter, 3) mstore(currentEnd, 0) } mstore(MEM_OFFSET(), newSize) } mstore8(add(MEM_OFFSET_INNER(), offset), value) + evmGasLeft := chargeGas(evmGasLeft, gasCounter) } case 0x55 { // OP_SSTORE let key, value From db9cd5849bd27b2fb7e845fbb88b147fa55ded6f Mon Sep 17 00:00:00 2001 From: Manuel Bilbao Date: Wed, 10 Apr 2024 17:13:34 -0300 Subject: [PATCH 27/29] Move memory expansion to function --- system-contracts/contracts/EvmInterpreter.yul | 59 +++++++------------ 1 file changed, 20 insertions(+), 39 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index cf30a967c..760be563d 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -194,6 +194,20 @@ object "EVMInterpreter" { } } + function expandMemory(end) -> gasCost { + gasCost := 3 + + let currentEnd := mload(MEM_OFFSET()) + if gt(end, currentEnd) { + let newSize := roundUp(end, 32) + for {} lt(currentEnd, newSize) { currentEnd := add(currentEnd, 32) } { + gasCost := add(gasCost, 3) + mstore(currentEnd, 0) + } + mstore(MEM_OFFSET(), newSize) + } + } + // Essentially a NOP that will not get optimized away by the compiler function $llvm_NoInline_llvm$_unoptimized() { pop(1) @@ -368,21 +382,10 @@ object "EVMInterpreter" { offset, sp := popStackItem(sp) - let gasCounter := 3 - - let end := add(offset, 32) - let currentEnd := mload(MEM_OFFSET()) - if gt(end, currentEnd) { - let newSize := roundUp(end, 32) - for {} lt(currentEnd, newSize) { currentEnd := add(currentEnd, 32) } { - gasCounter := add(gasCounter, 3) - mstore(currentEnd, 0) - } - mstore(MEM_OFFSET(), newSize) - } + let expansionGas := expandMemory(add(offset, 32)) sp := pushStackItem(sp, mload(add(MEM_OFFSET_INNER(), offset))) - evmGasLeft := chargeGas(evmGasLeft, gasCounter) + evmGasLeft := chargeGas(evmGasLeft, add(3, expansionGas)) } case 0x52 { // OP_MSTORE let offset, value @@ -390,21 +393,10 @@ object "EVMInterpreter" { offset, sp := popStackItem(sp) value, sp := popStackItem(sp) - let gasCounter := 3 - - let end := add(offset, 32) - let currentEnd := mload(MEM_OFFSET()) - if gt(end, currentEnd) { - let newSize := roundUp(end, 32) - for {} lt(currentEnd, newSize) { currentEnd := add(currentEnd, 32) } { - gasCounter := add(gasCounter, 3) - mstore(currentEnd, 0) - } - mstore(MEM_OFFSET(), newSize) - } + let expansionGas := expandMemory(add(offset, 32)) mstore(add(MEM_OFFSET_INNER(), offset), value) - evmGasLeft := chargeGas(evmGasLeft, gasCounter) + evmGasLeft := chargeGas(evmGasLeft, add(3, expansionGas)) } case 0x53 { // OP_MSTORE8 let offset, value @@ -412,21 +404,10 @@ object "EVMInterpreter" { offset, sp := popStackItem(sp) value, sp := popStackItem(sp) - let gasCounter := 3 - - let end := add(offset, 1) - let currentEnd := mload(MEM_OFFSET()) - if gt(end, currentEnd) { - let newSize := roundUp(end, 32) - for {} lt(currentEnd, newSize) {currentEnd := add(currentEnd, 32)} { - gasCounter := add(gasCounter, 3) - mstore(currentEnd, 0) - } - mstore(MEM_OFFSET(), newSize) - } + let expansionGas := expandMemory(add(offset, 1)) mstore8(add(MEM_OFFSET_INNER(), offset), value) - evmGasLeft := chargeGas(evmGasLeft, gasCounter) + evmGasLeft := chargeGas(evmGasLeft, add(3, expansionGas)) } case 0x55 { // OP_SSTORE let key, value From afc421bebc5ae69985de5c362a62752603b8cc1d Mon Sep 17 00:00:00 2001 From: Javier Chatruc Date: Wed, 10 Apr 2024 17:21:45 -0300 Subject: [PATCH 28/29] Add memory expansion function --- system-contracts/contracts/EvmInterpreter.yul | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index 85ce817ea..74f1392d6 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -182,6 +182,35 @@ object "EVMInterpreter" { gasRemaining := sub(prevGas, toCharge) } + // Note, that this function can overflow. It's up to the caller to ensure that it does not. + function memCost(memSizeWords) -> gasCost { + // The first term of the sum is the quadratic cost, the second one the linear one. + gasCost := add(div(mul(memSizeWords, memSizeWords), 512), mul(3, memSizeWords)) + } + + // This function can overflow, it is the job of the caller to ensure that it does not. + // The argument to this function is the offset into the memory region IN BYTES. + function expandMemory(newSize) -> gasCost { + let oldSizeInWords := mload(MEM_OFFSET()) + + // The add 31 here before dividing is there to account for misaligned + // memory expansions, where someone calls this with a newSize that is not + // a multiple of 32. For instance, if someone calls it with an offset of 33, + // the new size in words should be 2, not 1, but dividing by 32 will give 1. + // Adding 31 solves it. + let newSizeInWords := div(add(newSize, 31), 32) + + if gt(newSizeInWords, oldSizeInWords) { + // TODO: Check this, it feels like there might be a more optimized way + // of doing this cost calculation. + let oldCost := memCost(oldSizeInWords) + let newCost := memCost(newSizeInWords) + + gasCost := sub(newCost, oldCost) + mstore(MEM_OFFSET(), newSizeInWords) + } + } + // Essentially a NOP that will not get optimized away by the compiler function $llvm_NoInline_llvm$_unoptimized() { pop(1) From 2cd9dc20a6513796a22b25e2b32f4148fc1120e1 Mon Sep 17 00:00:00 2001 From: Manuel Bilbao Date: Fri, 12 Apr 2024 14:55:06 -0300 Subject: [PATCH 29/29] Improve legibility --- system-contracts/contracts/EvmInterpreter.yul | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index 7a337f671..8fb89483f 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -513,7 +513,8 @@ object "EVMInterpreter" { let expansionGas := expandMemory(add(offset, 32)) - sp := pushStackItem(sp, mload(add(MEM_OFFSET_INNER(), offset))) + let memValue := mload(add(MEM_OFFSET_INNER(), offset)) + sp := pushStackItem(sp, memValue) evmGasLeft := chargeGas(evmGasLeft, add(3, expansionGas)) } case 0x52 { // OP_MSTORE