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