Skip to content

Commit 906cb05

Browse files
committed
add definitions.json generation script
1 parent f9bae8c commit 906cb05

File tree

2 files changed

+342
-28
lines changed

2 files changed

+342
-28
lines changed

tools/generate_definitions.py

Lines changed: 326 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
1+
"""Script to generate the definitions.json file from rippled source code."""
2+
3+
import re
4+
import sys
5+
6+
CAPITALIZATION_EXCEPTIONS = {
7+
"NFTOKEN": "NFToken",
8+
"URITOKEN": "URIToken",
9+
"URI": "URI",
10+
"UNL": "UNL",
11+
"XCHAIN": "XChain",
12+
"DID": "DID",
13+
"ID": "ID",
14+
"AMM": "AMM",
15+
}
16+
17+
if len(sys.argv) != 2:
18+
print("Usage: python " + sys.argv[0] + " path/to/rippled")
19+
sys.exit(1)
20+
21+
########################################################################
22+
# Get all necessary files from rippled
23+
########################################################################
24+
25+
26+
def _read_file(filename: str) -> str:
27+
with open(filename, "r") as f:
28+
return f.read()
29+
30+
31+
sfield_h_fn = sys.argv[1] + "/include/xrpl/protocol/SField.h"
32+
sfield_macro_fn = sys.argv[1] + "/include/xrpl/protocol/detail/sfields.macro"
33+
ledger_entries_macro_fn = (
34+
sys.argv[1] + "/include/xrpl/protocol/detail/ledger_entries.macro"
35+
)
36+
ter_h_fn = sys.argv[1] + "/include/xrpl/protocol/TER.h"
37+
transactions_macro_fn = sys.argv[1] + "/include/xrpl/protocol/detail/transactions.macro"
38+
39+
sfield_h = _read_file(sfield_h_fn)
40+
sfield_macro_file = _read_file(sfield_macro_fn)
41+
ledger_entries_file = _read_file(ledger_entries_macro_fn)
42+
ter_h = _read_file(ter_h_fn)
43+
transactions_file = _read_file(transactions_macro_fn)
44+
45+
46+
# Translate from rippled string format to what the binary codecs expect
47+
def _translate(inp: str) -> str:
48+
if re.match(r"^UINT", inp):
49+
if re.search(r"256|160|128", inp):
50+
return inp.replace("UINT", "Hash")
51+
else:
52+
return inp.replace("UINT", "UInt")
53+
if inp == "OBJECT" or inp == "ARRAY":
54+
return "ST" + inp[0:1].upper() + inp[1:].lower()
55+
if inp == "ACCOUNT":
56+
return "AccountID"
57+
if inp == "LEDGERENTRY":
58+
return "LedgerEntry"
59+
if inp == "NOTPRESENT":
60+
return "NotPresent"
61+
if inp == "PATHSET":
62+
return "PathSet"
63+
if inp == "VL":
64+
return "Blob"
65+
if inp == "DIR_NODE":
66+
return "DirectoryNode"
67+
if inp == "PAYCHAN":
68+
return "PayChannel"
69+
70+
parts = inp.split("_")
71+
result = ""
72+
for part in parts:
73+
if part in CAPITALIZATION_EXCEPTIONS:
74+
result += CAPITALIZATION_EXCEPTIONS[part]
75+
else:
76+
result += part[0:1].upper() + part[1:].lower()
77+
return result
78+
79+
80+
########################################################################
81+
# Serialized type processing
82+
########################################################################
83+
print("{")
84+
print(' "TYPES": {')
85+
print(' "Done": -1,')
86+
87+
type_hits = re.findall(
88+
r"^ *STYPE\(STI_([^ ]*?) *, *([0-9-]+) *\) *\\?$", sfield_h, re.MULTILINE
89+
)
90+
if len(type_hits) == 0:
91+
type_hits = re.findall(
92+
r"^ *STI_([^ ]*?) *= *([0-9-]+) *,?$", sfield_h, re.MULTILINE
93+
)
94+
for x in range(len(type_hits)):
95+
print(
96+
' "'
97+
+ _translate(type_hits[x][0])
98+
+ '": '
99+
+ type_hits[x][1]
100+
+ ("," if x < len(type_hits) - 1 else "")
101+
)
102+
103+
print(" },")
104+
105+
########################################################################
106+
# Ledger entry type processing
107+
########################################################################
108+
print(' "LEDGER_ENTRY_TYPES": {')
109+
print(' "Any": -3,')
110+
print(' "Child": -2,')
111+
print(' "Invalid": -1,')
112+
113+
114+
def _unhex(x: str) -> str:
115+
if (x + "")[0:2] == "0x":
116+
return str(int(x, 16))
117+
return x
118+
119+
120+
lt_hits = re.findall(
121+
r"^ *LEDGER_ENTRY\(lt[A-Z_]+ *, *([x0-9a-f]+) *, *([^,]+), \({$",
122+
ledger_entries_file,
123+
re.MULTILINE,
124+
)
125+
for x in range(len(lt_hits)):
126+
print(
127+
' "'
128+
+ lt_hits[x][1]
129+
+ '": '
130+
+ _unhex(lt_hits[x][0])
131+
+ ("," if x < len(lt_hits) - 1 else "")
132+
)
133+
print(" },")
134+
135+
########################################################################
136+
# SField processing
137+
########################################################################
138+
print(' "FIELDS": [')
139+
# The ones that are harder to parse directly from SField.cpp
140+
print(
141+
""" [
142+
"Generic",
143+
{
144+
"nth": 0,
145+
"isVLEncoded": false,
146+
"isSerialized": false,
147+
"isSigningField": false,
148+
"type": "Unknown"
149+
}
150+
],
151+
[
152+
"Invalid",
153+
{
154+
"nth": -1,
155+
"isVLEncoded": false,
156+
"isSerialized": false,
157+
"isSigningField": false,
158+
"type": "Unknown"
159+
}
160+
],
161+
[
162+
"ObjectEndMarker",
163+
{
164+
"nth": 1,
165+
"isVLEncoded": false,
166+
"isSerialized": true,
167+
"isSigningField": true,
168+
"type": "STObject"
169+
}
170+
],
171+
[
172+
"ArrayEndMarker",
173+
{
174+
"nth": 1,
175+
"isVLEncoded": false,
176+
"isSerialized": true,
177+
"isSigningField": true,
178+
"type": "STArray"
179+
}
180+
],
181+
[
182+
"hash",
183+
{
184+
"nth": 257,
185+
"isVLEncoded": false,
186+
"isSerialized": false,
187+
"isSigningField": false,
188+
"type": "Hash256"
189+
}
190+
],
191+
[
192+
"index",
193+
{
194+
"nth": 258,
195+
"isVLEncoded": false,
196+
"isSerialized": false,
197+
"isSigningField": false,
198+
"type": "Hash256"
199+
}
200+
],
201+
[
202+
"taker_gets_funded",
203+
{
204+
"nth": 258,
205+
"isVLEncoded": false,
206+
"isSerialized": false,
207+
"isSigningField": false,
208+
"type": "Amount"
209+
}
210+
],
211+
[
212+
"taker_pays_funded",
213+
{
214+
"nth": 259,
215+
"isVLEncoded": false,
216+
"isSerialized": false,
217+
"isSigningField": false,
218+
"type": "Amount"
219+
}
220+
],"""
221+
)
222+
223+
224+
def _is_vl_encoded(t: str) -> str:
225+
if t == "VL" or t == "ACCOUNT" or t == "VECTOR256":
226+
return "true"
227+
return "false"
228+
229+
230+
def _is_serialized(t: str) -> str:
231+
if t == "LEDGERENTRY" or t == "TRANSACTION" or t == "VALIDATION" or t == "METADATA":
232+
return "false"
233+
return "true"
234+
235+
236+
def _is_signing_field(t: str, not_signing_field: str) -> str:
237+
if not_signing_field == "notSigning":
238+
return "false"
239+
if t == "LEDGERENTRY" or t == "TRANSACTION" or t == "VALIDATION" or t == "METADATA":
240+
return "false"
241+
return "true"
242+
243+
244+
# Parse SField.cpp for all the SFields and their serialization info
245+
sfield_hits = re.findall(
246+
r"^ *[A-Z]*TYPED_SFIELD *\( *sf([^,\n]*),[ \n]*([^, \n]+)[ \n]*,[ \n]*"
247+
r"([0-9]+)(,.*?(notSigning))?",
248+
sfield_macro_file,
249+
re.MULTILINE,
250+
)
251+
for x in range(len(sfield_hits)):
252+
print(" [")
253+
print(' "' + sfield_hits[x][0] + '",')
254+
print(" {")
255+
print(' "nth": ' + sfield_hits[x][2] + ",")
256+
print(' "isVLEncoded": ' + _is_vl_encoded(sfield_hits[x][1]) + ",")
257+
print(' "isSerialized": ' + _is_serialized(sfield_hits[x][1]) + ",")
258+
print(
259+
' "isSigningField": '
260+
+ _is_signing_field(sfield_hits[x][1], sfield_hits[x][4])
261+
+ ","
262+
)
263+
print(' "type": "' + _translate(sfield_hits[x][1]) + '"')
264+
print(" }")
265+
print(" ]" + ("," if x < len(sfield_hits) - 1 else ""))
266+
267+
print(" ],")
268+
269+
########################################################################
270+
# TER code processing
271+
########################################################################
272+
print(' "TRANSACTION_RESULTS": {')
273+
ter_h = str(ter_h).replace("[[maybe_unused]]", "")
274+
275+
ter_code_hits = re.findall(
276+
r"^ *((tel|tem|tef|ter|tes|tec)[A-Z_]+)( *= *([0-9-]+))? *,? *(\/\/[^\n]*)?$",
277+
ter_h,
278+
re.MULTILINE,
279+
)
280+
upto = -1
281+
last = ""
282+
283+
for x in range(len(ter_code_hits)):
284+
if ter_code_hits[x][3] != "":
285+
upto = int(ter_code_hits[x][3])
286+
287+
current = ter_code_hits[x][1]
288+
if current != last and last != "":
289+
print("")
290+
pass
291+
last = current
292+
293+
print(
294+
' "'
295+
+ ter_code_hits[x][0]
296+
+ '": '
297+
+ str(upto)
298+
+ ("," if x < len(ter_code_hits) - 1 else "")
299+
)
300+
301+
upto += 1
302+
303+
print(" },")
304+
305+
########################################################################
306+
# Transaction type processing
307+
########################################################################
308+
print(' "TRANSACTION_TYPES": {')
309+
print(' "Invalid": -1,')
310+
311+
tx_hits = re.findall(
312+
r"^ *TRANSACTION\(tt[A-Z_]+ *,* ([0-9]+) *, *([A-Za-z]+).*$",
313+
transactions_file,
314+
re.MULTILINE,
315+
)
316+
for x in range(len(tx_hits)):
317+
print(
318+
' "'
319+
+ tx_hits[x][1]
320+
+ '": '
321+
+ tx_hits[x][0]
322+
+ ("," if x < len(tx_hits) - 1 else "")
323+
)
324+
325+
print(" }")
326+
print("}")

0 commit comments

Comments
 (0)