1 // EVMC: Ethereum Client-VM Connector API.
2 // Copyright 2018-2019 The EVMC Authors.
3 // Licensed under the Apache License, Version 2.0.
4 
5 #include <evmc/instructions.h>
6 
7 #include <gtest/gtest.h>
8 
operator ==(const evmc_instruction_metrics & a,const evmc_instruction_metrics & b)9 bool operator==(const evmc_instruction_metrics& a, const evmc_instruction_metrics& b) noexcept
10 {
11     return a.gas_cost == b.gas_cost && a.stack_height_required == b.stack_height_required &&
12            a.stack_height_change == b.stack_height_change;
13 }
14 
TEST(instructions,name_gas_cost_equivalence)15 TEST(instructions, name_gas_cost_equivalence)
16 {
17     for (auto r = int{EVMC_FRONTIER}; r <= EVMC_MAX_REVISION; ++r)
18     {
19         const auto rev = static_cast<evmc_revision>(r);
20         const auto names = evmc_get_instruction_names_table(rev);
21         const auto metrics = evmc_get_instruction_metrics_table(rev);
22 
23         for (int i = 0; i < 256; ++i)
24         {
25             auto name = names[i];
26             auto gas_cost = metrics[i].gas_cost;
27 
28             if (name != nullptr)
29                 EXPECT_GE(gas_cost, 0);
30             else
31                 EXPECT_EQ(gas_cost, 0);
32         }
33     }
34 }
35 
TEST(instructions,homestead_hard_fork)36 TEST(instructions, homestead_hard_fork)
37 {
38     const auto f = evmc_get_instruction_metrics_table(EVMC_FRONTIER);
39     const auto h = evmc_get_instruction_metrics_table(EVMC_HOMESTEAD);
40     const auto fn = evmc_get_instruction_names_table(EVMC_FRONTIER);
41     const auto hn = evmc_get_instruction_names_table(EVMC_HOMESTEAD);
42 
43     for (int op{OP_STOP}; op <= OP_SELFDESTRUCT; ++op)
44     {
45         switch (op)  // NOLINT
46         {
47         case OP_DELEGATECALL:
48             continue;
49         default:
50             EXPECT_EQ(h[op], f[op]) << op;
51             EXPECT_STREQ(hn[op], fn[op]) << op;
52             break;
53         }
54     }
55 
56     EXPECT_EQ(f[OP_DELEGATECALL].gas_cost, 0);
57     EXPECT_EQ(h[OP_DELEGATECALL].gas_cost, 40);
58     EXPECT_TRUE(fn[OP_DELEGATECALL] == nullptr);
59     EXPECT_EQ(hn[OP_DELEGATECALL], std::string{"DELEGATECALL"});
60 }
61 
TEST(instructions,tangerine_whistle_hard_fork)62 TEST(instructions, tangerine_whistle_hard_fork)
63 {
64     const auto h = evmc_get_instruction_metrics_table(EVMC_HOMESTEAD);
65     const auto tw = evmc_get_instruction_metrics_table(EVMC_TANGERINE_WHISTLE);
66     const auto hn = evmc_get_instruction_names_table(EVMC_HOMESTEAD);
67     const auto twn = evmc_get_instruction_names_table(EVMC_TANGERINE_WHISTLE);
68 
69     for (int op{OP_STOP}; op <= OP_SELFDESTRUCT; ++op)
70     {
71         switch (op)
72         {
73         case OP_EXTCODESIZE:
74         case OP_EXTCODECOPY:
75         case OP_BALANCE:
76         case OP_SLOAD:
77         case OP_CALL:
78         case OP_CALLCODE:
79         case OP_DELEGATECALL:
80         case OP_SELFDESTRUCT:
81             continue;
82         default:
83             EXPECT_EQ(tw[op], h[op]) << op;
84             EXPECT_STREQ(twn[op], hn[op]) << op;
85             break;
86         }
87     }
88 
89     EXPECT_EQ(h[OP_EXTCODESIZE].gas_cost, 20);
90     EXPECT_EQ(tw[OP_EXTCODESIZE].gas_cost, 700);
91 
92     EXPECT_EQ(h[OP_EXTCODECOPY].gas_cost, 20);
93     EXPECT_EQ(tw[OP_EXTCODECOPY].gas_cost, 700);
94 
95     EXPECT_EQ(h[OP_BALANCE].gas_cost, 20);
96     EXPECT_EQ(tw[OP_BALANCE].gas_cost, 400);
97 
98     EXPECT_EQ(h[OP_SLOAD].gas_cost, 50);
99     EXPECT_EQ(tw[OP_SLOAD].gas_cost, 200);
100 
101     EXPECT_EQ(h[OP_CALL].gas_cost, 40);
102     EXPECT_EQ(tw[OP_CALL].gas_cost, 700);
103 
104     EXPECT_EQ(h[OP_CALLCODE].gas_cost, 40);
105     EXPECT_EQ(tw[OP_CALLCODE].gas_cost, 700);
106 
107     EXPECT_EQ(h[OP_DELEGATECALL].gas_cost, 40);
108     EXPECT_EQ(tw[OP_DELEGATECALL].gas_cost, 700);
109 
110     EXPECT_EQ(h[OP_SELFDESTRUCT].gas_cost, 0);
111     EXPECT_EQ(tw[OP_SELFDESTRUCT].gas_cost, 5000);
112 }
113 
TEST(instructions,spurious_dragon_hard_fork)114 TEST(instructions, spurious_dragon_hard_fork)
115 {
116     const auto sd = evmc_get_instruction_metrics_table(EVMC_SPURIOUS_DRAGON);
117     const auto tw = evmc_get_instruction_metrics_table(EVMC_TANGERINE_WHISTLE);
118     const auto sdn = evmc_get_instruction_names_table(EVMC_SPURIOUS_DRAGON);
119     const auto twn = evmc_get_instruction_names_table(EVMC_TANGERINE_WHISTLE);
120 
121     for (int op{OP_STOP}; op <= OP_SELFDESTRUCT; ++op)
122     {
123         switch (op)  // NOLINT
124         {
125         case OP_EXP:
126             continue;
127         default:
128             EXPECT_EQ(sd[op], tw[op]) << op;
129             EXPECT_STREQ(sdn[op], twn[op]) << op;
130             break;
131         }
132     }
133 
134     EXPECT_EQ(sd[OP_EXP].gas_cost, 10);
135     EXPECT_EQ(tw[OP_EXP].gas_cost, 10);
136 }
137 
TEST(instructions,byzantium_hard_fork)138 TEST(instructions, byzantium_hard_fork)
139 {
140     const auto b = evmc_get_instruction_metrics_table(EVMC_BYZANTIUM);
141     const auto sd = evmc_get_instruction_metrics_table(EVMC_SPURIOUS_DRAGON);
142     const auto bn = evmc_get_instruction_names_table(EVMC_BYZANTIUM);
143     const auto sdn = evmc_get_instruction_names_table(EVMC_SPURIOUS_DRAGON);
144 
145     for (int op{OP_STOP}; op <= OP_SELFDESTRUCT; ++op)
146     {
147         switch (op)
148         {
149         case OP_REVERT:
150         case OP_RETURNDATACOPY:
151         case OP_RETURNDATASIZE:
152         case OP_STATICCALL:
153             continue;
154         default:
155             EXPECT_EQ(b[op], sd[op]) << op;
156             EXPECT_STREQ(bn[op], sdn[op]) << op;
157             break;
158         }
159     }
160 
161     EXPECT_EQ(b[OP_REVERT].gas_cost, 0);
162     EXPECT_EQ(b[OP_REVERT].stack_height_required, 2);
163     EXPECT_EQ(b[OP_REVERT].stack_height_change, -2);
164     EXPECT_EQ(sd[OP_REVERT].gas_cost, 0);
165     EXPECT_EQ(bn[OP_REVERT], std::string{"REVERT"});
166     EXPECT_TRUE(sdn[OP_REVERT] == nullptr);
167 
168     EXPECT_EQ(b[OP_RETURNDATACOPY].gas_cost, 3);
169     EXPECT_EQ(sd[OP_RETURNDATACOPY].gas_cost, 0);
170     EXPECT_EQ(bn[OP_RETURNDATACOPY], std::string{"RETURNDATACOPY"});
171     EXPECT_TRUE(sdn[OP_RETURNDATACOPY] == nullptr);
172 
173     EXPECT_EQ(b[OP_RETURNDATASIZE].gas_cost, 2);
174     EXPECT_EQ(sd[OP_RETURNDATASIZE].gas_cost, 0);
175     EXPECT_EQ(bn[OP_RETURNDATASIZE], std::string{"RETURNDATASIZE"});
176     EXPECT_TRUE(sdn[OP_RETURNDATASIZE] == nullptr);
177 
178     EXPECT_EQ(b[OP_STATICCALL].gas_cost, 700);
179     EXPECT_EQ(sd[OP_STATICCALL].gas_cost, 0);
180     EXPECT_EQ(bn[OP_STATICCALL], std::string{"STATICCALL"});
181     EXPECT_TRUE(sdn[OP_STATICCALL] == nullptr);
182 }
183 
TEST(instructions,constantinople_hard_fork)184 TEST(instructions, constantinople_hard_fork)
185 {
186     const auto c = evmc_get_instruction_metrics_table(EVMC_CONSTANTINOPLE);
187     const auto b = evmc_get_instruction_metrics_table(EVMC_BYZANTIUM);
188     const auto cn = evmc_get_instruction_names_table(EVMC_CONSTANTINOPLE);
189     const auto bn = evmc_get_instruction_names_table(EVMC_BYZANTIUM);
190 
191     for (int op{OP_STOP}; op <= OP_SELFDESTRUCT; ++op)
192     {
193         switch (op)
194         {
195         case OP_CREATE2:
196         case OP_EXTCODEHASH:
197         case OP_SHL:
198         case OP_SHR:
199         case OP_SAR:
200             continue;
201         default:
202             EXPECT_EQ(c[op], b[op]) << op;
203             EXPECT_STREQ(cn[op], bn[op]) << op;
204             break;
205         }
206     }
207 
208     for (auto op : {OP_SHL, OP_SHR, OP_SAR})
209     {
210         const auto m = c[op];
211         EXPECT_EQ(m.gas_cost, 3);
212         EXPECT_EQ(m.stack_height_required, 2);
213         EXPECT_EQ(m.stack_height_change, -1);
214     }
215 
216     EXPECT_EQ(c[OP_CREATE2].gas_cost, 32000);
217     EXPECT_EQ(c[OP_CREATE2].stack_height_required, 4);
218     EXPECT_EQ(c[OP_CREATE2].stack_height_change, -3);
219     EXPECT_EQ(b[OP_CREATE2].gas_cost, 0);
220     EXPECT_EQ(cn[OP_CREATE2], std::string{"CREATE2"});
221     EXPECT_TRUE(bn[OP_CREATE2] == nullptr);
222 
223     EXPECT_EQ(c[OP_EXTCODEHASH].gas_cost, 400);
224     EXPECT_EQ(c[OP_EXTCODEHASH].stack_height_required, 1);
225     EXPECT_EQ(c[OP_EXTCODEHASH].stack_height_change, 0);
226     EXPECT_EQ(b[OP_EXTCODEHASH].gas_cost, 0);
227     EXPECT_EQ(cn[OP_EXTCODEHASH], std::string{"EXTCODEHASH"});
228     EXPECT_TRUE(bn[OP_EXTCODEHASH] == nullptr);
229 }
230 
TEST(instructions,petersburg_hard_fork)231 TEST(instructions, petersburg_hard_fork)
232 {
233     const auto p = evmc_get_instruction_metrics_table(EVMC_PETERSBURG);
234     const auto c = evmc_get_instruction_metrics_table(EVMC_CONSTANTINOPLE);
235     const auto pn = evmc_get_instruction_names_table(EVMC_PETERSBURG);
236     const auto cn = evmc_get_instruction_names_table(EVMC_CONSTANTINOPLE);
237 
238     for (int op{OP_STOP}; op <= OP_SELFDESTRUCT; ++op)
239     {
240         EXPECT_EQ(p[op], c[op]) << op;
241         EXPECT_STREQ(pn[op], cn[op]) << op;
242     }
243 }
244 
TEST(instructions,istanbul_hard_fork)245 TEST(instructions, istanbul_hard_fork)
246 {
247     const auto i = evmc_get_instruction_metrics_table(EVMC_ISTANBUL);
248     const auto p = evmc_get_instruction_metrics_table(EVMC_PETERSBURG);
249     const auto in = evmc_get_instruction_names_table(EVMC_ISTANBUL);
250     const auto pn = evmc_get_instruction_names_table(EVMC_PETERSBURG);
251 
252     for (int op{OP_STOP}; op <= OP_SELFDESTRUCT; ++op)
253     {
254         switch (op)
255         {
256         case OP_BALANCE:
257         case OP_EXTCODEHASH:
258         case OP_CHAINID:
259         case OP_SELFBALANCE:
260         case OP_SLOAD:
261             continue;
262         default:
263             EXPECT_EQ(i[op], p[op]) << op;
264             EXPECT_STREQ(in[op], pn[op]) << op;
265             break;
266         }
267     }
268 
269     EXPECT_EQ(i[OP_CHAINID].gas_cost, 2);
270     EXPECT_EQ(i[OP_CHAINID].stack_height_required, 0);
271     EXPECT_EQ(i[OP_CHAINID].stack_height_change, 1);
272     EXPECT_EQ(p[OP_CHAINID].gas_cost, 0);
273     EXPECT_EQ(in[OP_CHAINID], std::string{"CHAINID"});
274     EXPECT_TRUE(pn[OP_CHAINID] == nullptr);
275 
276     EXPECT_EQ(i[OP_SELFBALANCE].gas_cost, 5);
277     EXPECT_EQ(i[OP_SELFBALANCE].stack_height_required, 0);
278     EXPECT_EQ(i[OP_SELFBALANCE].stack_height_change, 1);
279     EXPECT_EQ(p[OP_SELFBALANCE].gas_cost, 0);
280     EXPECT_EQ(in[OP_SELFBALANCE], std::string{"SELFBALANCE"});
281     EXPECT_TRUE(pn[OP_SELFBALANCE] == nullptr);
282 
283     // Repricings
284     EXPECT_EQ(i[OP_BALANCE].gas_cost, 700);
285     EXPECT_EQ(i[OP_EXTCODEHASH].gas_cost, 700);
286     EXPECT_EQ(i[OP_SLOAD].gas_cost, 800);
287 }
288 
TEST(instructions,berlin_hard_fork)289 TEST(instructions, berlin_hard_fork)
290 {
291     const auto b = evmc_get_instruction_metrics_table(EVMC_BERLIN);
292     const auto i = evmc_get_instruction_metrics_table(EVMC_ISTANBUL);
293     const auto bn = evmc_get_instruction_names_table(EVMC_BERLIN);
294     const auto in = evmc_get_instruction_names_table(EVMC_ISTANBUL);
295 
296     for (int op{OP_STOP}; op <= OP_SELFDESTRUCT; ++op)
297     {
298         EXPECT_EQ(b[op], i[op]) << op;
299         EXPECT_STREQ(bn[op], in[op]) << op;
300     }
301 }
302