Skip to content

Commit ed0056e

Browse files
committed
test: Add evmmax unit tests
1 parent 38f9bc3 commit ed0056e

File tree

3 files changed

+318
-0
lines changed

3 files changed

+318
-0
lines changed

test/unittests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ target_sources(
3535
evmmax_bn254_add_test.cpp
3636
evmmax_bn254_mul_test.cpp
3737
evmmax_test.cpp
38+
evmmax_instructions_test.cpp
3839
evmmax_secp256k1_test.cpp
3940
evmone_test.cpp
4041
execution_state_test.cpp
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
// evmone: Fast Ethereum Virtual Machine implementation
2+
// Copyright 2023 The evmone Authors.
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
#include "evm_fixture.hpp"
6+
#include <evmmax/evmmax.hpp>
7+
#include <gtest/gtest.h>
8+
#include <array>
9+
10+
using namespace intx;
11+
using namespace evmmax;
12+
using namespace evmc::literals;
13+
using evmone::test::evm;
14+
15+
TEST_P(evm, evmmax_32bytes_modulus_test)
16+
{
17+
if (is_advanced())
18+
return;
19+
20+
rev = EVMC_PRAGUE; /// TODO: Use EVMC_EVMMAX
21+
// Modulus == 7
22+
auto code = mstore(0, 0x07);
23+
// 3 values slots
24+
// Modulus size in bytes
25+
// Modulus offset in EVM memory
26+
// Modulus ID
27+
code += setupx(3, 32, 0, 1);
28+
// value 3
29+
code += mstore(32, 0x03);
30+
// value 6
31+
code += mstore(64, 0x06);
32+
// num values
33+
// values offset
34+
// store values
35+
code += storex(2, 32, 0);
36+
// ADDMODX for values in slots 0 and 1 save result in slot 2
37+
code += addmodx(2, 1, 0);
38+
// MULMODX for values in slots 1 and 2 save result in slot 2
39+
code += mulmodx(2, 2, 1);
40+
// SUBMODX for values in slots 1 and 2 save result in slot 2
41+
code += submodx(2, 2, 1);
42+
// load values from slot 2 into EVM memory
43+
code += loadx(1, 2, 96);
44+
// return loaded result
45+
code += ret(96, 32);
46+
47+
execute(1000, code);
48+
EXPECT_EQ(result.status_code, EVMC_SUCCESS);
49+
EXPECT_OUTPUT_INT(6);
50+
}
51+
52+
TEST_P(evm, evmmax_1byte_modulus_test)
53+
{
54+
if (is_advanced())
55+
return;
56+
57+
rev = EVMC_PRAGUE; /// TODO: Use EVMC_EVMMAX
58+
// Modulus == 7
59+
auto code = mstore8(0, 0x07);
60+
// 3 values slots
61+
// Modulus size in bytes
62+
// Modulus offset in EVM memory
63+
// Modulus ID
64+
code += setupx(3, 1, 0, 1);
65+
// value 3
66+
code += mstore8(8, 0x03);
67+
// value 6
68+
code += mstore8(16, 0x06);
69+
// num values
70+
// values offset
71+
// store values
72+
code += storex(2, 1, 0);
73+
// ADDMODX for values in slots 0 and 1 save result in slot 2
74+
code += addmodx(2, 1, 0);
75+
// MULMODX for values in slots 1 and 2 save result in slot 2
76+
code += mulmodx(2, 2, 1);
77+
// SUBMODX for values in slots 1 and 2 save result in slot 2
78+
code += submodx(2, 2, 1);
79+
// load values from slot 2 into EVM memory
80+
code += loadx(1, 2, 17);
81+
// return loaded result
82+
code += ret(17, 8);
83+
84+
execute(1000, code);
85+
EXPECT_EQ(result.status_code, EVMC_SUCCESS);
86+
87+
ASSERT_EQ(result.output_size, 8);
88+
EXPECT_EQ(hex({result.output_data, result.output_size}), "0000000000000006");
89+
}
90+
91+
TEST_P(evm, evmmax_2byte_modulus_test)
92+
{
93+
if (is_advanced())
94+
return;
95+
96+
rev = EVMC_PRAGUE; /// TODO: Use EVMC_EVMMAX
97+
// Modulus == 263 (0x0107)
98+
auto code = mstore8(0, 0x01);
99+
code += mstore8(1, 0x07);
100+
// 3 values slots
101+
// Modulus size in bytes
102+
// Modulus offset in EVM memory
103+
// Modulus ID
104+
code += setupx(3, 2, 0, 1);
105+
// value 258
106+
code += mstore8(8, 0x01);
107+
code += mstore8(9, 0x02);
108+
// value 254
109+
code += mstore8(16, 0x00);
110+
code += mstore8(17, 0xfe);
111+
// num values
112+
// values offset
113+
// store values
114+
code += storex(2, 2, 0);
115+
// ADDMODX for values in slots 0 and 1 save result in slot 2
116+
code += addmodx(2, 1, 0); // 258 + 254 = 249 mod 263
117+
// MULMODX for values in slots 1 and 2 save result in slot 2
118+
code += mulmodx(2, 2, 1); // 249 * 254 = 126 mod 263
119+
// SUBMODX for values in slots 1 and 2 save result in slot 2
120+
code += submodx(2, 2, 1); // 126 - 254 = 135 mod 263
121+
// load values from slot 2 into EVM memory
122+
code += loadx(1, 2, 18);
123+
// return loaded result
124+
code += ret(18, 8);
125+
126+
execute(1000, code);
127+
EXPECT_EQ(result.status_code, EVMC_SUCCESS);
128+
129+
ASSERT_EQ(result.output_size, 8);
130+
EXPECT_EQ(hex({result.output_data, result.output_size}), "0000000000000087");
131+
}

test/unittests/evmmax_test.cpp

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22
// Copyright 2023 The evmone Authors.
33
// SPDX-License-Identifier: Apache-2.0
44

5+
#include "evm_fixture.hpp"
56
#include <evmmax/evmmax.hpp>
67
#include <gtest/gtest.h>
78
#include <array>
89

910
using namespace intx;
1011
using namespace evmmax;
12+
using evmone::test::evm;
1113

1214
// TODO(intx): Add ""_u384.
1315
inline constexpr auto operator""_u384(const char* s)
@@ -140,3 +142,187 @@ TYPED_TEST(evmmax_test, mul)
140142
}
141143
}
142144
}
145+
146+
namespace
147+
{
148+
template <typename UintT>
149+
inline bytecode create_test_bytecode()
150+
{
151+
constexpr auto size = sizeof(UintT);
152+
return calldatacopy(push(0), push(0), push(size * 3)) + setupx(3, size, 0, 1) +
153+
storex(2, size, 0) + mulmodx(2, 1, 0) + loadx(1, 2, size * 3) + ret(size * 3, size);
154+
}
155+
156+
} // namespace
157+
158+
TEST_P(evm, exec_bn254_test)
159+
{
160+
using namespace evmone::test;
161+
162+
if (evm::is_advanced())
163+
return;
164+
165+
evm::rev = EVMC_PRAGUE; /// TODO: Use EVMC_EVMMAX
166+
167+
const ModA<uint256, BN254Mod> m;
168+
169+
uint8_t calldata[3 * sizeof(uint256)];
170+
intx::be::unsafe::store(&calldata[0], BN254Mod);
171+
172+
const auto values = get_test_values(m);
173+
174+
const auto code = create_test_bytecode<uint256>();
175+
176+
for (const auto& x : values)
177+
{
178+
for (const auto& y : values)
179+
{
180+
const auto expected = udivrem(umul(x, y), m.mod).rem;
181+
182+
intx::be::unsafe::store(&calldata[32], x);
183+
intx::be::unsafe::store(&calldata[64], y);
184+
185+
execute(1000, code, {calldata, 96});
186+
EXPECT_EQ(result.status_code, EVMC_SUCCESS);
187+
EXPECT_OUTPUT_INT(expected);
188+
}
189+
}
190+
}
191+
192+
TEST_P(evm, exec_bls_test)
193+
{
194+
using namespace evmone::test;
195+
196+
if (evm::is_advanced())
197+
return;
198+
199+
evm::rev = EVMC_PRAGUE; /// TODO: Use EVMC_EVMMAX
200+
201+
const ModA<uint384, BLS12384Mod> m;
202+
203+
constexpr auto size = sizeof(uint384);
204+
uint8_t calldata[3 * size];
205+
intx::be::unsafe::store(&calldata[0], BLS12384Mod);
206+
207+
const auto values = get_test_values(m);
208+
209+
const auto code = create_test_bytecode<uint384>();
210+
211+
for (const auto& x : values)
212+
{
213+
for (const auto& y : values)
214+
{
215+
const auto expected = udivrem(umul(x, y), m.mod).rem;
216+
217+
intx::be::unsafe::store(&calldata[size], x);
218+
intx::be::unsafe::store(&calldata[size * 2], y);
219+
220+
execute(1000, code, {calldata, size * 3});
221+
EXPECT_EQ(result.status_code, EVMC_SUCCESS);
222+
ASSERT_EQ(result.output_size, size);
223+
EXPECT_EQ(intx::be::unsafe::load<uint384>(result.output_data), expected);
224+
}
225+
}
226+
}
227+
228+
TEST_P(evm, exec_invalid_test)
229+
{
230+
using namespace evmone::test;
231+
232+
if (evm::is_advanced())
233+
return;
234+
235+
evm::rev = EVMC_PRAGUE; /// TODO: Use EVMC_EVMMAX
236+
237+
{
238+
// Even modulus
239+
constexpr auto size = sizeof(uint256);
240+
uint8_t calldata[3 * size];
241+
242+
const auto code = create_test_bytecode<uint256>();
243+
intx::be::unsafe::store(&calldata[0], BN254Mod + 1);
244+
execute(1000, code, {calldata, size * 3});
245+
EXPECT_EQ(result.status_code, EVMC_FAILURE);
246+
}
247+
248+
{
249+
// Modulus too big
250+
constexpr auto size = sizeof(intx::uint<4160>);
251+
uint8_t calldata[3 * size];
252+
253+
const auto code = create_test_bytecode<intx::uint<4160>>();
254+
intx::be::unsafe::store(&calldata[0], intx::uint<4160>(7));
255+
execute(1000, code, {calldata, size * 3});
256+
EXPECT_EQ(result.status_code, EVMC_FAILURE);
257+
}
258+
259+
{
260+
// Too many value slots
261+
constexpr auto size = sizeof(uint256);
262+
uint8_t calldata[size];
263+
264+
const auto code = calldatacopy(push(0), push(0), push(size)) + setupx(257, size, 0, 1);
265+
intx::be::unsafe::store(&calldata[0], BN254Mod);
266+
execute(1000, code, {calldata, size});
267+
EXPECT_EQ(result.status_code, EVMC_FAILURE);
268+
}
269+
270+
{
271+
// not enough gas
272+
constexpr auto size = sizeof(uint256);
273+
uint8_t calldata[3 * size];
274+
275+
const auto code = create_test_bytecode<uint256>();
276+
intx::be::unsafe::store(&calldata[0], BN254Mod);
277+
execute(45, code, {calldata, size * 3});
278+
EXPECT_EQ(result.status_code, EVMC_OUT_OF_GAS);
279+
}
280+
281+
{
282+
// Too much evmmax memory used
283+
constexpr auto size = sizeof(intx::uint<2048>);
284+
uint8_t calldata[size * 3];
285+
286+
const auto code = calldatacopy(push(0), push(0), push(size)) + setupx(1, size, 0, 1) +
287+
setupx(256, size, 0, 2);
288+
intx::be::unsafe::store(&calldata[0], intx::uint<2048>(BN254Mod));
289+
execute(1000, code, {calldata, size});
290+
EXPECT_EQ(result.status_code, EVMC_FAILURE);
291+
}
292+
293+
{
294+
// Invalid instruction index
295+
constexpr auto size = sizeof(intx::uint<256>);
296+
uint8_t calldata[size * 3];
297+
298+
const auto common_code = calldatacopy(push(0), push(0), push(size)) + setupx(1, size, 0, 1);
299+
intx::be::unsafe::store(&calldata[0], intx::uint<256>(BN254Mod));
300+
301+
execute(1000, common_code + addmodx(0, 0, 2), {calldata, size});
302+
EXPECT_EQ(result.status_code, EVMC_FAILURE);
303+
304+
execute(1000, common_code + mulmodx(0, 0, 2), {calldata, size});
305+
EXPECT_EQ(result.status_code, EVMC_FAILURE);
306+
307+
execute(1000, common_code + submodx(0, 0, 2), {calldata, size});
308+
EXPECT_EQ(result.status_code, EVMC_FAILURE);
309+
}
310+
311+
{
312+
// No active modulus
313+
execute(1000, addmodx(0, 0, 1));
314+
EXPECT_EQ(result.status_code, EVMC_FAILURE);
315+
316+
execute(1000, mulmodx(0, 0, 2));
317+
EXPECT_EQ(result.status_code, EVMC_FAILURE);
318+
319+
execute(1000, submodx(0, 0, 2));
320+
EXPECT_EQ(result.status_code, EVMC_FAILURE);
321+
322+
execute(1000, loadx(1, 0, 0));
323+
EXPECT_EQ(result.status_code, EVMC_FAILURE);
324+
325+
execute(1000, storex(1, 0, 0));
326+
EXPECT_EQ(result.status_code, EVMC_FAILURE);
327+
}
328+
}

0 commit comments

Comments
 (0)