Skip to content

Commit 7fdc527

Browse files
authored
history test (#8)
Signed-off-by: turuslan <turuslan.devbox@gmail.com>
1 parent d7621e8 commit 7fdc527

23 files changed

+833
-147
lines changed

.gitmodules

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
[submodule "test-vectors/jamtestvectors"]
22
path = test-vectors/jamtestvectors
3-
url = https://github.com/w3f/jamtestvectors/
3+
url = https://github.com/davxy/jam-test-vectors

CMakeLists.txt

+6
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ find_package(Boost CONFIG REQUIRED)
2222
find_package(fmt CONFIG REQUIRED)
2323
find_package(scale CONFIG REQUIRED)
2424

25+
add_library(headers INTERFACE)
26+
target_include_directories(headers INTERFACE
27+
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src>
28+
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
29+
)
30+
2531
add_subdirectory(src)
2632

2733
if(TESTING)

python/asn1.py

+136-64
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,24 @@
22

33
import asn1tools
44
import os.path
5+
import sys
6+
57

68
DIR = os.path.dirname(__file__)
79
TEST_VECTORS_DIR = os.path.join(DIR, "../test-vectors")
810
OUTPUT_NAME = "types"
9-
OUTPUT_DIR = os.path.join(TEST_VECTORS_DIR, "safrole")
10-
SAFROLE_DIR = os.path.join(TEST_VECTORS_DIR, "jamtestvectors/safrole")
11-
ARGS = ["validators-count", "epoch-length"]
12-
NS = "jam::test_vectors_safrole"
1311

1412

1513
def flatten(aaa: list[list]):
1614
return [a for aa in aaa for a in aa]
1715

1816

19-
def safrole_file(name: str):
20-
return os.path.join(SAFROLE_DIR, name + ".asn")
17+
def asn_file(name: str):
18+
return os.path.join(TEST_VECTORS_DIR, "jamtestvectors", name + ".asn")
2119

2220

23-
def write(ext: str, lines: list[str]):
24-
with open(os.path.join(OUTPUT_DIR, OUTPUT_NAME + ext), "w") as f:
21+
def write(path: str, lines: list[str]):
22+
with open(path, "w") as f:
2523
f.writelines(line + "\n" for line in lines)
2624

2725

@@ -33,7 +31,7 @@ def c_struct(name: str, members):
3331
return [
3432
"struct %s {" % name,
3533
*((" %s %s;" % (t, k) for k, t in members)),
36-
" bool operator==(const %s &)const = default;" % name,
34+
" bool operator==(const %s &) const = default;" % name,
3735
"};",
3836
]
3937

@@ -49,19 +47,24 @@ def indent(lines):
4947

5048

5149
class Type:
50+
ignore_args = True
51+
5252
def __init__(self, name: str):
5353
self.name = name
5454
self.args: list[str] = []
5555
self.decl: list[str] = []
5656
self.scale: list[str] = []
57+
self.diff: list[str] = []
5758

5859
def c_tdecl(self):
59-
if not self.args:
60+
if self.ignore_args or not self.args:
6061
return []
61-
return ["template<%s>" % ", ".join("uint32_t %s" % c_dash(x) for x in self.args)]
62+
return [
63+
"template<%s>" % ", ".join("uint32_t %s" % c_dash(x) for x in self.args)
64+
]
6265

6366
def c_targs(self):
64-
if not self.args:
67+
if self.ignore_args or not self.args:
6568
return ""
6669
return "<%s>" % ", ".join(c_dash(x) for x in self.args)
6770

@@ -98,7 +101,7 @@ def deep(k: str):
98101
return deps1, deps2
99102

100103

101-
def asn_args(types: dict, deps2: dict[str, set[str]]):
104+
def asn_args(ARGS: list[str], types: dict, deps2: dict[str, set[str]]):
102105
args = {
103106
k: {
104107
s[0]
@@ -122,10 +125,11 @@ def c_scale(ty: Type, encode: list[str], decode: list[str]):
122125
" return s;",
123126
"}",
124127
*ty.c_tdecl(),
125-
"inline scale::ScaleDecoderStream &operator>>(scale::ScaleDecoderStream &s, %s &v) {"
128+
"scale::ScaleDecoderStream &operator>>(scale::ScaleDecoderStream &s, %s &) = delete;"
129+
% ty.c_tname(),
130+
"void decodeConfig(scale::ScaleDecoderStream &s, %s &v, const auto &config) {"
126131
% ty.c_tname(),
127132
*indent(decode),
128-
" return s;",
129133
"}",
130134
]
131135

@@ -134,13 +138,22 @@ def c_scale_struct(ty: Type, members: list[str]):
134138
return c_scale(
135139
ty,
136140
["s << v.%s;" % x for x in members],
137-
["s >> v.%s;" % x for x in members],
141+
["decodeConfig(s, v.%s, config);" % x for x in members],
138142
)
139143

140144

141-
def parse_types(path: str):
145+
def c_diff(NS: str, ty: Type, lines: list[str]):
146+
return [
147+
*ty.c_tdecl(),
148+
"DIFF_F(%s::%s) {" % (NS, ty.c_tname()),
149+
*indent(lines),
150+
"}",
151+
]
152+
153+
154+
def parse_types(NS: str, ARGS: list[str], path: str, key: str):
142155
def asn_sequence_of(t):
143-
(size,) = t["size"]
156+
(size,) = t.get("size", (None,))
144157
fixed = isinstance(size, (int, str))
145158
T = t["element"]["type"]
146159
assert T in asn_types
@@ -149,10 +162,14 @@ def asn_sequence_of(t):
149162
return "qtils::BytesN<%s>" % c_dash(size)
150163
return "qtils::Bytes"
151164
if fixed:
165+
if isinstance(size, str):
166+
return "jam::ConfigVec<%s, ConfigField::%s>" % (T, c_dash(size))
152167
return "std::array<%s, %s>" % (T, c_dash(size))
153168
return "std::vector<%s>" % T
154169

155170
def asn_member(t):
171+
if t["type"] == "OCTET STRING":
172+
t = dict(type="SEQUENCE OF", element=dict(type="U8"), size=t["size"])
156173
if t["type"] == "SEQUENCE OF":
157174
r = asn_sequence_of(t)
158175
elif t["type"] in asn_types:
@@ -163,10 +180,12 @@ def asn_member(t):
163180
return "std::optional<%s>" % r
164181
return r
165182

166-
asn_types: dict = asn1tools.parse_files([path])["SafroleModule"]["types"]
183+
asn_types: dict = asn1tools.parse_files([path])[key]["types"]
184+
if "U8" not in asn_types:
185+
asn_types["U8"] = dict(type="INTEGER")
167186
deps1, deps2 = asn_deps(asn_types)
168187
types = {tname: Type(tname) for tname in asn_types}
169-
for tname, args in asn_args(asn_types, deps2).items():
188+
for tname, args in asn_args(ARGS, asn_types, deps2).items():
170189
types[tname].args = args
171190
enum_trait = []
172191
for tname, t in asn_types.items():
@@ -177,7 +196,15 @@ def asn_member(t):
177196
if tname == "U32":
178197
ty.decl = c_using(tname, "uint32_t")
179198
continue
199+
if t["type"] == "NULL":
200+
t = dict(type="SEQUENCE", members=[])
180201
if t["type"] == "CHOICE":
202+
if tname == "MmrPeak":
203+
assert [x["name"] for x in t["members"]] == ["none", "some"]
204+
ty.decl = c_using(
205+
tname, "std::optional<%s>" % asn_member(t["members"][1])
206+
)
207+
continue
181208
ty.decl = c_struct(
182209
tname,
183210
[
@@ -188,7 +215,7 @@ def asn_member(t):
188215
)
189216
],
190217
)
191-
ty.scale.extend(c_scale_struct(ty, ["v"]))
218+
ty.scale += c_scale_struct(ty, ["v"])
192219
continue
193220
if t["type"] == "ENUMERATED":
194221
values = [x[1] for x in t["values"]]
@@ -198,14 +225,13 @@ def asn_member(t):
198225
*(" %s," % c_dash(x[0]) for x in t["values"]),
199226
"};",
200227
]
201-
ns = "%s::generic" % NS
202228
enum_trait.append(
203229
"SCALE_DEFINE_ENUM_VALUE_LIST(%s, %s, %s)"
204230
% (
205-
ns,
231+
NS,
206232
ty.name,
207233
", ".join(
208-
"%s::%s::%s" % (ns, ty.name, c_dash(x[0])) for x in t["values"]
234+
"%s::%s::%s" % (NS, ty.name, c_dash(x[0])) for x in t["values"]
209235
),
210236
)
211237
)
@@ -214,8 +240,9 @@ def asn_member(t):
214240
ty.decl = c_struct(
215241
tname, [(c_dash(x["name"]), asn_member(x)) for x in t["members"]]
216242
)
217-
ty.scale.extend(
218-
c_scale_struct(ty, [c_dash(x["name"]) for x in t["members"]])
243+
ty.scale += c_scale_struct(ty, [c_dash(x["name"]) for x in t["members"]])
244+
ty.diff = c_diff(
245+
NS, ty, ["DIFF_M(%s);" % c_dash(x["name"]) for x in t["members"]]
219246
)
220247
continue
221248
ty.decl = c_using(tname, asn_member(t))
@@ -224,49 +251,94 @@ def asn_member(t):
224251
return [types[k] for k in order], enum_trait
225252

226253

227-
def parse_const(path: str):
228-
values: dict = asn1tools.parse_files([path])["SafroleConstants"]["values"]
254+
def parse_const(path: str, key: str):
255+
values: dict = asn1tools.parse_files([path])[key]["values"]
229256
assert all(v["type"] == "INTEGER" for v in values.values())
230257
return {k: v["value"] for k, v in values.items()}
231258

232259

233-
types, enum_trait = parse_types(safrole_file("safrole"))
260+
class Gen:
261+
def __init__(self, NS: str, ARGS: list[str], path: str, key: str, configs):
262+
g_config = [
263+
"struct ConfigField {",
264+
*[" struct %s {};" % c_dash(a) for a in ARGS],
265+
"};",
266+
"struct Config {",
267+
*[" uint32_t %s;" % c_dash(a) for a in ARGS],
268+
*[
269+
" auto get(ConfigField::%s) const { return %s; }"
270+
% (c_dash(a), c_dash(a))
271+
for a in ARGS
272+
],
273+
"};",
274+
]
275+
for name, args in configs:
276+
g_config += [
277+
"constexpr Config config_%s {" % name,
278+
*[" .%s = %s," % (c_dash(a), args[a]) for a in ARGS],
279+
"};",
280+
]
281+
self.types, self.enum_trait = parse_types(NS, ARGS, path, key)
282+
self.g_types = flatten([*ty.c_tdecl(), *ty.decl] for ty in self.types)
283+
self.g_types = g_config + self.g_types
284+
self.g_types = ["namespace %s {" % NS, *indent(self.g_types), "}"]
285+
self.g_types = [
286+
"#pragma once",
287+
"#include <boost/variant.hpp>",
288+
"#include <qtils/bytes.hpp>",
289+
"#include <test-vectors/config-types.hpp>",
290+
*self.g_types,
291+
]
292+
self.g_scale = flatten(ty.scale for ty in self.types)
293+
self.g_scale = ["namespace %s {" % NS, *indent(self.g_scale), "}"]
294+
self.g_scale = [
295+
"#pragma once",
296+
"#include <scale/scale.hpp>",
297+
"#include <test-vectors/config-types-scale.hpp>",
298+
'#include "%s.hpp"' % OUTPUT_NAME,
299+
*self.g_scale,
300+
*self.enum_trait,
301+
]
302+
self.g_diff = flatten(ty.diff for ty in self.types)
303+
self.g_diff = [
304+
"#pragma once",
305+
"#include <test-vectors/diff.hpp>",
306+
'#include "%s.hpp"' % OUTPUT_NAME,
307+
*self.g_diff,
308+
]
309+
310+
def write(self, name: str):
311+
prefix = os.path.join(TEST_VECTORS_DIR, name, OUTPUT_NAME)
312+
write(prefix + ".hpp", self.g_types)
313+
write(prefix + ".scale.hpp", self.g_scale)
314+
write(prefix + ".diff.hpp", self.g_diff)
234315

235316

236-
g_types = flatten([*ty.c_tdecl(), *ty.decl] for ty in types)
237-
g_types = ["namespace %s::generic {" % NS, *indent(g_types), "}"]
238-
for name in ["tiny", "full"]:
239-
args = parse_const(safrole_file(name))
240-
g_args = [
241-
*["static constexpr uint32_t %s = %s;" % (c_dash(a), args[a]) for a in ARGS],
242-
*flatten(
243-
c_using(ty.name, "%s::generic::%s" % (NS, ty.c_tname())) for ty in types
244-
),
245-
]
246-
g_args = ["struct %s {" % name, *indent(g_args), "};"]
247-
g_types.extend(
317+
def safrole():
318+
g = Gen(
319+
"jam::test_vectors_safrole",
320+
["validators-count", "epoch-length"],
321+
asn_file("safrole/safrole"),
322+
"SafroleModule",
248323
[
249-
"namespace %s {" % NS,
250-
*indent(g_args),
251-
"}",
252-
]
324+
(name, parse_const(asn_file("safrole/%s" % name), "Constants"))
325+
for name in ["tiny", "full"]
326+
],
327+
)
328+
g.write("safrole")
329+
330+
331+
def history():
332+
g = Gen(
333+
"jam::test_vectors_history",
334+
[],
335+
asn_file("history/history"),
336+
"HistoryModule",
337+
[],
253338
)
254-
g_types = [
255-
"#pragma once",
256-
"#include <boost/variant.hpp>",
257-
"#include <qtils/bytes.hpp>",
258-
*g_types,
259-
]
260-
261-
g_scale = flatten(ty.scale for ty in types)
262-
g_scale = ["namespace %s::generic {" % NS, *indent(g_scale), "}"]
263-
g_scale = [
264-
"#pragma once",
265-
"#include <scale/scale.hpp>",
266-
'#include "%s.hpp"' % OUTPUT_NAME,
267-
*g_scale,
268-
*enum_trait,
269-
]
270-
271-
write(".hpp", g_types)
272-
write(".scale.hpp", g_scale)
339+
g.write("history")
340+
341+
342+
if __name__ == "__main__":
343+
for arg in sys.argv[1:]:
344+
dict(safrole=safrole, history=history)[arg]()

0 commit comments

Comments
 (0)