diff --git a/include/evmc/instructions.h b/include/evmc/instructions.h index 1c22f848b..5eb6fbb17 100644 --- a/include/evmc/instructions.h +++ b/include/evmc/instructions.h @@ -93,6 +93,8 @@ enum evmc_opcode OP_MSIZE = 0x59, OP_GAS = 0x5a, OP_JUMPDEST = 0x5b, + OP_RJUMP = 0x5c, + OP_RJUMPI = 0x5d, OP_PUSH0 = 0x5f, OP_PUSH1 = 0x60, @@ -173,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 059ba76f0..335850958 100644 --- a/lib/instructions/instruction_metrics.c +++ b/lib/instructions/instruction_metrics.c @@ -127,8 +127,8 @@ static struct evmc_instruction_metrics cancun_metrics[256] = { /* MSIZE = 0x59 */ {BASE, 0, 1}, /* GAS = 0x5a */ {BASE, 0, 1}, /* JUMPDEST = 0x5b */ {1, 0, 0}, - /* = 0x5c */ {UNDEFINED, 0, 0}, - /* = 0x5d */ {UNDEFINED, 0, 0}, + /* RJUMP = 0x5c */ {LOW, 0, 0}, + /* RJUMPI = 0x5d */ {7, 1, -1}, /* = 0x5e */ {UNDEFINED, 0, 0}, /* PUSH0 = 0x5f */ {BASE, 0, 1}, /* PUSH1 = 0x60 */ {VERYLOW, 0, 1}, @@ -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 64a21592d..9aef43d1d 100644 --- a/lib/instructions/instruction_names.c +++ b/lib/instructions/instruction_names.c @@ -97,8 +97,8 @@ static const char* cancun_names[256] = { /* 0x59 */ "MSIZE", /* 0x5a */ "GAS", /* 0x5b */ "JUMPDEST", - /* 0x5c */ NULL, - /* 0x5d */ NULL, + /* 0x5c */ "RJUMP", + /* 0x5d */ "RJUMPI", /* 0x5e */ NULL, /* 0x5f */ "PUSH0", /* 0x60 */ "PUSH1", @@ -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 a4216be4c..ae77d6f98 100644 --- a/test/unittests/instructions_test.cpp +++ b/test/unittests/instructions_test.cpp @@ -394,3 +394,47 @@ TEST(instructions, shanghai_hard_fork) EXPECT_EQ(sn[OP_PUSH0], std::string{"PUSH0"}); EXPECT_TRUE(pn[OP_PUSH0] == nullptr); } + +TEST(instructions, cancun_hard_fork) +{ + const auto c = evmc_get_instruction_metrics_table(EVMC_CANCUN); + const auto s = evmc_get_instruction_metrics_table(EVMC_SHANGHAI); + const auto cn = evmc_get_instruction_names_table(EVMC_CANCUN); + const auto sn = evmc_get_instruction_names_table(EVMC_SHANGHAI); + + for (int op = 0x00; op <= 0xff; ++op) + { + 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; + } + + // EIP-4200: Static relative jumps + EXPECT_EQ(c[OP_RJUMP].gas_cost, 5); + EXPECT_EQ(c[OP_RJUMP].stack_height_required, 0); + EXPECT_EQ(c[OP_RJUMP].stack_height_change, 0); + EXPECT_EQ(s[OP_RJUMP].gas_cost, 0); + EXPECT_EQ(cn[OP_RJUMP], std::string{"RJUMP"}); + EXPECT_TRUE(sn[OP_RJUMP] == nullptr); + EXPECT_EQ(c[OP_RJUMPI].gas_cost, 7); + EXPECT_EQ(c[OP_RJUMPI].stack_height_required, 1); + EXPECT_EQ(c[OP_RJUMPI].stack_height_change, -1); + 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); +}