From 24b885f6cec81e556a75376075d94d4e720d6ca3 Mon Sep 17 00:00:00 2001
From: Andrei Maiboroda <andrei@ethereum.org>
Date: Wed, 10 Aug 2022 12:40:58 +0200
Subject: [PATCH] Add CALLF and RETF instructions

---
 include/evmc/instructions.h            |  3 ++-
 lib/instructions/instruction_metrics.c |  4 ++--
 lib/instructions/instruction_names.c   |  4 ++--
 test/unittests/instructions_test.cpp   | 16 +++++++++++++++-
 4 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/include/evmc/instructions.h b/include/evmc/instructions.h
index 05af011f0..5eb6fbb17 100644
--- a/include/evmc/instructions.h
+++ b/include/evmc/instructions.h
@@ -175,7 +175,8 @@ enum evmc_opcode
     OP_CREATE2 = 0xf5,
 
     OP_STATICCALL = 0xfa,
-
+    OP_CALLF = 0xfb,
+    OP_RETF = 0xfc,
     OP_REVERT = 0xfd,
     OP_INVALID = 0xfe,
     OP_SELFDESTRUCT = 0xff
diff --git a/lib/instructions/instruction_metrics.c b/lib/instructions/instruction_metrics.c
index 30c64a7d8..335850958 100644
--- a/lib/instructions/instruction_metrics.c
+++ b/lib/instructions/instruction_metrics.c
@@ -286,8 +286,8 @@ static struct evmc_instruction_metrics cancun_metrics[256] = {
     /*                = 0xf8 */ {UNDEFINED, 0, 0},
     /*                = 0xf9 */ {UNDEFINED, 0, 0},
     /*     STATICCALL = 0xfa */ {WARM_STORAGE_READ_COST, 6, -5},
-    /*                = 0xfb */ {UNDEFINED, 0, 0},
-    /*                = 0xfc */ {UNDEFINED, 0, 0},
+    /*          CALLF = 0xfb */ {MID, 0, 0},
+    /*          RETF  = 0xfc */ {MID, 0, 0},
     /*         REVERT = 0xfd */ {ZERO, 2, -2},
     /*        INVALID = 0xfe */ {ZERO, 0, 0},
     /*   SELFDESTRUCT = 0xff */ {5000, 1, -1},
diff --git a/lib/instructions/instruction_names.c b/lib/instructions/instruction_names.c
index 21ae38e79..9aef43d1d 100644
--- a/lib/instructions/instruction_names.c
+++ b/lib/instructions/instruction_names.c
@@ -256,8 +256,8 @@ static const char* cancun_names[256] = {
     /* 0xf8 */ NULL,
     /* 0xf9 */ NULL,
     /* 0xfa */ "STATICCALL",
-    /* 0xfb */ NULL,
-    /* 0xfc */ NULL,
+    /* 0xfb */ "CALLF",
+    /* 0xfc */ "RETF",
     /* 0xfd */ "REVERT",
     /* 0xfe */ "INVALID",
     /* 0xff */ "SELFDESTRUCT",
diff --git a/test/unittests/instructions_test.cpp b/test/unittests/instructions_test.cpp
index 02213ac51..ae77d6f98 100644
--- a/test/unittests/instructions_test.cpp
+++ b/test/unittests/instructions_test.cpp
@@ -404,7 +404,7 @@ TEST(instructions, cancun_hard_fork)
 
     for (int op = 0x00; op <= 0xff; ++op)
     {
-        if (op == OP_RJUMP || op == OP_RJUMPI)
+        if (op == OP_RJUMP || op == OP_RJUMPI || op == OP_CALLF || op == OP_RETF)
             continue;
         EXPECT_EQ(c[op], s[op]) << op;
         EXPECT_STREQ(cn[op], sn[op]) << op;
@@ -423,4 +423,18 @@ TEST(instructions, cancun_hard_fork)
     EXPECT_EQ(s[OP_RJUMPI].gas_cost, 0);
     EXPECT_EQ(cn[OP_RJUMPI], std::string{"RJUMPI"});
     EXPECT_TRUE(sn[OP_RJUMPI] == nullptr);
+
+    // EIP-4750: EOF Functions
+    EXPECT_EQ(c[OP_CALLF].gas_cost, 8);
+    EXPECT_EQ(c[OP_CALLF].stack_height_required, 0);
+    EXPECT_EQ(c[OP_CALLF].stack_height_change, 0);
+    EXPECT_EQ(s[OP_CALLF].gas_cost, 0);
+    EXPECT_EQ(cn[OP_CALLF], std::string{"CALLF"});
+    EXPECT_TRUE(sn[OP_CALLF] == nullptr);
+    EXPECT_EQ(c[OP_RETF].gas_cost, 8);
+    EXPECT_EQ(c[OP_RETF].stack_height_required, 0);
+    EXPECT_EQ(c[OP_RETF].stack_height_change, 0);
+    EXPECT_EQ(s[OP_RETF].gas_cost, 0);
+    EXPECT_EQ(cn[OP_RETF], std::string{"RETF"});
+    EXPECT_TRUE(sn[OP_RETF] == nullptr);
 }