@witnet/sdk 1.0.4 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (211) hide show
  1. package/.env_witnet +6 -6
  2. package/LICENSE +21 -21
  3. package/README.md +103 -103
  4. package/dist/package.json +3 -4
  5. package/dist/src/bin/helpers.js +1 -1
  6. package/dist/src/index.js +1 -1
  7. package/dist/src/lib/crypto/account.d.ts +3 -1
  8. package/dist/src/lib/crypto/account.d.ts.map +1 -1
  9. package/dist/src/lib/crypto/account.js +7 -1
  10. package/dist/src/lib/crypto/coinbase.js +1 -1
  11. package/dist/src/lib/crypto/index.js +1 -1
  12. package/dist/src/lib/crypto/interfaces.d.ts +2 -0
  13. package/dist/src/lib/crypto/interfaces.d.ts.map +1 -1
  14. package/dist/src/lib/crypto/interfaces.js +1 -1
  15. package/dist/src/lib/crypto/payloads/DataRequestPayload.js +1 -1
  16. package/dist/src/lib/crypto/payloads/StakePayload.js +1 -1
  17. package/dist/src/lib/crypto/payloads/UnstakePayload.js +1 -1
  18. package/dist/src/lib/crypto/payloads/ValueTransferPayload.js +1 -1
  19. package/dist/src/lib/crypto/payloads.d.ts.map +1 -1
  20. package/dist/src/lib/crypto/payloads.js +12 -1
  21. package/dist/src/lib/crypto/signer.d.ts +1 -0
  22. package/dist/src/lib/crypto/signer.d.ts.map +1 -1
  23. package/dist/src/lib/crypto/signer.js +18 -1
  24. package/dist/src/lib/crypto/transmitters/DataRequests.js +1 -1
  25. package/dist/src/lib/crypto/transmitters/StakeDeposits.js +1 -1
  26. package/dist/src/lib/crypto/transmitters/StakeWithdrawals.js +1 -1
  27. package/dist/src/lib/crypto/transmitters/ValueTransfers.js +1 -1
  28. package/dist/src/lib/crypto/transmitters.js +4 -4
  29. package/dist/src/lib/crypto/types.d.ts.map +1 -1
  30. package/dist/src/lib/crypto/types.js +2 -1
  31. package/dist/src/lib/crypto/utils.js +1 -1
  32. package/dist/src/lib/crypto/wallet.d.ts +3 -1
  33. package/dist/src/lib/crypto/wallet.d.ts.map +1 -1
  34. package/dist/src/lib/crypto/wallet.js +10 -1
  35. package/dist/src/lib/index.js +1 -1
  36. package/dist/src/lib/radon/ccdr/eth.js +1 -1
  37. package/dist/src/lib/radon/ccdr/index.js +1 -1
  38. package/dist/src/lib/radon/ccdr/wit.js +1 -1
  39. package/dist/src/lib/radon/filters.js +1 -1
  40. package/dist/src/lib/radon/index.js +1 -1
  41. package/dist/src/lib/radon/reducers.js +1 -1
  42. package/dist/src/lib/radon/types.js +1 -1
  43. package/dist/src/lib/radon/utils.js +1 -1
  44. package/dist/src/lib/rpc/index.js +1 -1
  45. package/dist/src/lib/rpc/nodes.js +1 -1
  46. package/dist/src/lib/rpc/provider.js +1 -1
  47. package/dist/src/lib/rpc/types.d.ts +6 -4
  48. package/dist/src/lib/rpc/types.d.ts.map +1 -1
  49. package/dist/src/lib/rpc/types.js +1 -1
  50. package/dist/src/lib/types.d.ts +0 -1
  51. package/dist/src/lib/types.d.ts.map +1 -1
  52. package/dist/src/lib/types.js +1 -1
  53. package/dist/src/lib/utils.js +1 -1
  54. package/dist/witnet/assets/index.js +1 -1
  55. package/dist/witnet/assets/modals/index.js +1 -1
  56. package/dist/witnet/assets/modals/web3/eth.js +1 -1
  57. package/dist/witnet/assets/modals/web3/ipfs.js +1 -1
  58. package/dist/witnet/assets/modals/web3/wit.js +1 -1
  59. package/dist/witnet/assets/requests.js +1 -1
  60. package/package.json +3 -4
  61. package/src/bin/cli/history.js +31 -31
  62. package/src/bin/cli/inspect.js +405 -405
  63. package/src/bin/cli/network.js +594 -594
  64. package/src/bin/cli/nodes.js +364 -364
  65. package/src/bin/cli/radon.js +817 -815
  66. package/src/bin/cli/wallet.js +1121 -1117
  67. package/src/bin/helpers.js +840 -840
  68. package/src/bin/postinstall.js +9 -9
  69. package/src/bin/toolkit.js +295 -295
  70. package/witnet/assets/_index.js +8 -8
  71. package/witnet/assets/_requests.js +25 -25
  72. package/witnet/assets/_sources.js +36 -36
  73. package/witnet/assets/_templates.js +36 -36
  74. package/witnet/assets/index.js +4 -4
  75. package/witnet/assets/modals/index.js +9 -9
  76. package/witnet/assets/modals/web3/eth.js +29 -29
  77. package/witnet/assets/modals/web3/ipfs.js +19 -19
  78. package/witnet/assets/modals/web3/wit.js +21 -21
  79. package/witnet/assets/requests.js +95 -95
  80. package/dist/bin/helpers.d.ts +0 -88
  81. package/dist/bin/helpers.d.ts.map +0 -1
  82. package/dist/bin/helpers.js +0 -866
  83. package/dist/index.d.ts +0 -4
  84. package/dist/index.d.ts.map +0 -1
  85. package/dist/index.js +0 -42
  86. package/dist/lib/crypto/account.d.ts +0 -18
  87. package/dist/lib/crypto/account.d.ts.map +0 -1
  88. package/dist/lib/crypto/account.js +0 -152
  89. package/dist/lib/crypto/coinbase.d.ts +0 -9
  90. package/dist/lib/crypto/coinbase.d.ts.map +0 -1
  91. package/dist/lib/crypto/coinbase.js +0 -39
  92. package/dist/lib/crypto/index.d.ts +0 -7
  93. package/dist/lib/crypto/index.d.ts.map +0 -1
  94. package/dist/lib/crypto/index.js +0 -28
  95. package/dist/lib/crypto/interfaces.d.ts +0 -80
  96. package/dist/lib/crypto/interfaces.d.ts.map +0 -1
  97. package/dist/lib/crypto/interfaces.js +0 -3
  98. package/dist/lib/crypto/payloads/DataRequestPayload.d.ts +0 -47
  99. package/dist/lib/crypto/payloads/DataRequestPayload.d.ts.map +0 -1
  100. package/dist/lib/crypto/payloads/DataRequestPayload.js +0 -384
  101. package/dist/lib/crypto/payloads/StakePayload.d.ts +0 -27
  102. package/dist/lib/crypto/payloads/StakePayload.d.ts.map +0 -1
  103. package/dist/lib/crypto/payloads/StakePayload.js +0 -184
  104. package/dist/lib/crypto/payloads/UnstakePayload.d.ts +0 -35
  105. package/dist/lib/crypto/payloads/UnstakePayload.d.ts.map +0 -1
  106. package/dist/lib/crypto/payloads/UnstakePayload.js +0 -244
  107. package/dist/lib/crypto/payloads/ValueTransferPayload.d.ts +0 -24
  108. package/dist/lib/crypto/payloads/ValueTransferPayload.d.ts.map +0 -1
  109. package/dist/lib/crypto/payloads/ValueTransferPayload.js +0 -182
  110. package/dist/lib/crypto/payloads.d.ts +0 -54
  111. package/dist/lib/crypto/payloads.d.ts.map +0 -1
  112. package/dist/lib/crypto/payloads.js +0 -224
  113. package/dist/lib/crypto/signer.d.ts +0 -26
  114. package/dist/lib/crypto/signer.d.ts.map +0 -1
  115. package/dist/lib/crypto/signer.js +0 -299
  116. package/dist/lib/crypto/transmitters/DataRequests.d.ts +0 -14
  117. package/dist/lib/crypto/transmitters/DataRequests.d.ts.map +0 -1
  118. package/dist/lib/crypto/transmitters/DataRequests.js +0 -62
  119. package/dist/lib/crypto/transmitters/StakeDeposits.d.ts +0 -11
  120. package/dist/lib/crypto/transmitters/StakeDeposits.d.ts.map +0 -1
  121. package/dist/lib/crypto/transmitters/StakeDeposits.js +0 -48
  122. package/dist/lib/crypto/transmitters/StakeWithdrawals.d.ts +0 -17
  123. package/dist/lib/crypto/transmitters/StakeWithdrawals.d.ts.map +0 -1
  124. package/dist/lib/crypto/transmitters/StakeWithdrawals.js +0 -115
  125. package/dist/lib/crypto/transmitters/ValueTransfers.d.ts +0 -10
  126. package/dist/lib/crypto/transmitters/ValueTransfers.d.ts.map +0 -1
  127. package/dist/lib/crypto/transmitters/ValueTransfers.js +0 -47
  128. package/dist/lib/crypto/transmitters.d.ts +0 -46
  129. package/dist/lib/crypto/transmitters.d.ts.map +0 -1
  130. package/dist/lib/crypto/transmitters.js +0 -506
  131. package/dist/lib/crypto/types.d.ts +0 -127
  132. package/dist/lib/crypto/types.d.ts.map +0 -1
  133. package/dist/lib/crypto/types.js +0 -261
  134. package/dist/lib/crypto/utils.d.ts +0 -10
  135. package/dist/lib/crypto/utils.d.ts.map +0 -1
  136. package/dist/lib/crypto/utils.js +0 -97
  137. package/dist/lib/crypto/wallet.d.ts +0 -26
  138. package/dist/lib/crypto/wallet.d.ts.map +0 -1
  139. package/dist/lib/crypto/wallet.js +0 -327
  140. package/dist/lib/helpers.d.ts +0 -90
  141. package/dist/lib/helpers.d.ts.map +0 -1
  142. package/dist/lib/helpers.js +0 -1031
  143. package/dist/lib/index.d.ts +0 -5
  144. package/dist/lib/index.d.ts.map +0 -1
  145. package/dist/lib/index.js +0 -21
  146. package/dist/lib/radon/artifacts.d.ts +0 -55
  147. package/dist/lib/radon/artifacts.d.ts.map +0 -1
  148. package/dist/lib/radon/artifacts.js +0 -347
  149. package/dist/lib/radon/ccdr/eth.d.ts +0 -100
  150. package/dist/lib/radon/ccdr/eth.d.ts.map +0 -1
  151. package/dist/lib/radon/ccdr/eth.js +0 -237
  152. package/dist/lib/radon/ccdr/index.d.ts +0 -34
  153. package/dist/lib/radon/ccdr/index.d.ts.map +0 -1
  154. package/dist/lib/radon/ccdr/index.js +0 -63
  155. package/dist/lib/radon/ccdr/wit.d.ts +0 -29
  156. package/dist/lib/radon/ccdr/wit.d.ts.map +0 -1
  157. package/dist/lib/radon/ccdr/wit.js +0 -60
  158. package/dist/lib/radon/filters.d.ts +0 -14
  159. package/dist/lib/radon/filters.d.ts.map +0 -1
  160. package/dist/lib/radon/filters.js +0 -47
  161. package/dist/lib/radon/index.d.ts +0 -36
  162. package/dist/lib/radon/index.d.ts.map +0 -1
  163. package/dist/lib/radon/index.js +0 -154
  164. package/dist/lib/radon/reducers.d.ts +0 -29
  165. package/dist/lib/radon/reducers.d.ts.map +0 -1
  166. package/dist/lib/radon/reducers.js +0 -101
  167. package/dist/lib/radon/retrievals.d.ts +0 -120
  168. package/dist/lib/radon/retrievals.d.ts.map +0 -1
  169. package/dist/lib/radon/retrievals.js +0 -358
  170. package/dist/lib/radon/sources.d.ts +0 -102
  171. package/dist/lib/radon/sources.d.ts.map +0 -1
  172. package/dist/lib/radon/sources.js +0 -294
  173. package/dist/lib/radon/types.d.ts +0 -521
  174. package/dist/lib/radon/types.d.ts.map +0 -1
  175. package/dist/lib/radon/types.js +0 -1066
  176. package/dist/lib/radon/utils.d.ts +0 -55
  177. package/dist/lib/radon/utils.d.ts.map +0 -1
  178. package/dist/lib/radon/utils.js +0 -181
  179. package/dist/lib/rpc/farm.d.ts +0 -66
  180. package/dist/lib/rpc/farm.d.ts.map +0 -1
  181. package/dist/lib/rpc/farm.js +0 -808
  182. package/dist/lib/rpc/index.d.ts +0 -3
  183. package/dist/lib/rpc/index.d.ts.map +0 -1
  184. package/dist/lib/rpc/index.js +0 -19
  185. package/dist/lib/rpc/node.d.ts +0 -38
  186. package/dist/lib/rpc/node.d.ts.map +0 -1
  187. package/dist/lib/rpc/node.js +0 -335
  188. package/dist/lib/rpc/nodes.d.ts +0 -40
  189. package/dist/lib/rpc/nodes.d.ts.map +0 -1
  190. package/dist/lib/rpc/nodes.js +0 -531
  191. package/dist/lib/rpc/provider.d.ts +0 -72
  192. package/dist/lib/rpc/provider.d.ts.map +0 -1
  193. package/dist/lib/rpc/provider.js +0 -402
  194. package/dist/lib/rpc/reporter.d.ts +0 -18
  195. package/dist/lib/rpc/reporter.d.ts.map +0 -1
  196. package/dist/lib/rpc/reporter.js +0 -99
  197. package/dist/lib/rpc/types.d.ts +0 -396
  198. package/dist/lib/rpc/types.d.ts.map +0 -1
  199. package/dist/lib/rpc/types.js +0 -81
  200. package/dist/lib/rpc/wallet.d.ts +0 -72
  201. package/dist/lib/rpc/wallet.d.ts.map +0 -1
  202. package/dist/lib/rpc/wallet.js +0 -41
  203. package/dist/lib/types.d.ts +0 -19
  204. package/dist/lib/types.d.ts.map +0 -1
  205. package/dist/lib/types.js +0 -7
  206. package/dist/lib/utils.d.ts +0 -5
  207. package/dist/lib/utils.d.ts.map +0 -1
  208. package/dist/lib/utils.js +0 -51
  209. package/dist/src/lib/rpc/reporter.d.ts +0 -17
  210. package/dist/src/lib/rpc/reporter.d.ts.map +0 -1
  211. package/dist/src/lib/rpc/reporter.js +0 -27
@@ -1,815 +1,817 @@
1
- const fs = require("fs")
2
- const inquirer = require("inquirer")
3
- const merge = require("lodash.merge")
4
- const path = require("path")
5
-
6
- const helpers = require("../helpers")
7
- const { Witnet } = require("../../../dist/src")
8
-
9
- const WITNET_ASSETS_PATH = process.env.WITNET_SDK_RADON_ASSETS_PATH || "../../../../../witnet/assets"
10
-
11
- /// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
12
- /// CLI SUBMODULE CONSTANTS ===========================================================================================
13
-
14
- const isModuleInitialized = fs.existsSync("./witnet/assets/index.js")
15
-
16
- module.exports = {
17
- flags: {
18
- module: {
19
- hint: "Package where to fetch Radon assets from (supersedes --legacy).",
20
- param: "NPM_PACKAGE",
21
- },
22
- },
23
- router: isModuleInitialized
24
- ? {
25
- assets: {
26
- hint: "List available Witnet Radon assets.",
27
- params: "[RADON_ASSETS ...]",
28
- options: {
29
- legacy: {
30
- hint: "List only those declared in witnet/assets folder.",
31
- },
32
- filter: {
33
- hint: "Restrict output to name-matching assets.",
34
- },
35
- },
36
- },
37
- check: {
38
- hint: "Check correctness of Witnet Radon artifacts declared in witnet/assets folder.",
39
- params: [],
40
- options: {},
41
- },
42
- decode: {
43
- hint: "Break down specs of one or more Radon assets.",
44
- params: ["RAD_BYTECODE | RAD_HASH | RADON_ASSET"],
45
- options: {
46
- json: {
47
- hint: "Outputs data in JSON format.",
48
- },
49
- headline: {
50
- hint: "Settles output report headline.",
51
- param: ":string",
52
- },
53
- indent: {
54
- hint: "Prefixes given number of white spaces for every output line.",
55
- param: ":number",
56
- },
57
- },
58
- },
59
- "dry-run": {
60
- hint: "Simulate resolution of one or more Radon assets, as if solved by the Wit/Oracle.",
61
- params: ["RAD_BYTECODE | RAD_HASH | RADON_ASSET"],
62
- options: {
63
- default: {
64
- hint: "Use default sample parameters on parametrized Radon assets.",
65
- },
66
- json: {
67
- hint: "Outputs data in JSON format.",
68
- },
69
- headline: {
70
- hint: "Settles output report headline.",
71
- param: ":string",
72
- },
73
- indent: {
74
- hint: "Prefixes given number of white spaces for every output line.",
75
- param: ":number",
76
- },
77
- verbose: {
78
- hint: "Outputs detailed dry-run report.",
79
- },
80
- },
81
- },
82
- }
83
- : {
84
- assets: {
85
- hint: "List available Witnet Radon assets.",
86
- params: "[RADON_ASSETS ...]",
87
- options: {
88
- filter: {
89
- hint: "Restrict output to name-matching assets.",
90
- },
91
- },
92
- },
93
- decode: {
94
- hint: "Break down specs of one or more Radon assets.",
95
- params: ["RAD_BYTECODE | RAD_HASH | RADON_ASSET"],
96
- options: {
97
- json: {
98
- hint: "Outputs data in JSON format.",
99
- },
100
- headline: {
101
- hint: "Settles output report headline.",
102
- param: ":string",
103
- },
104
- indent: {
105
- hint: "Prefixes given number of white spaces for every output line.",
106
- param: ":number",
107
- },
108
- },
109
- },
110
- "dry-run": {
111
- hint: "Simulate resolution of one or more Radon assets, as if solved by the Wit/Oracle.",
112
- params: ["RAD_BYTECODE | RAD_HASH | RADON_ASSET"],
113
- options: {
114
- json: {
115
- hint: "Outputs data in JSON format.",
116
- },
117
- headline: {
118
- hint: "Settles output report headline.",
119
- param: ":string",
120
- },
121
- indent: {
122
- hint: "Prefixes given number of white spaces for every output line.",
123
- param: ":number",
124
- },
125
- verbose: {
126
- hint: "Outputs detailed dry-run report.",
127
- },
128
- },
129
- },
130
- init: {
131
- hint: "Initialize a Witnet Radon workspace in this project.",
132
- },
133
- },
134
- subcommands: {
135
- assets, init, check, decode, "dry-run": dryrun,
136
- },
137
- loadAssets,
138
- }
139
-
140
-
141
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
142
- /// CLI SUBMODULE COMMANDS ============================================================================================
143
-
144
- async function init () {
145
- if (!fs.existsSync("./witnet/assets/")) {
146
- fs.mkdirSync("./witnet/assets", { recursive: true })
147
- }
148
- if (!fs.existsSync(".env_witnet")) {
149
- fs.cpSync("node_modules/@witnet/sdk/.env_witnet", ".env_witnet")
150
- }
151
- if (!fs.existsSync("./witnet/assets/index.js")) {
152
- fs.cpSync("node_modules/@witnet/sdk/witnet/assets/_index.js", "./witnet/assets/index.js")
153
- }
154
- if (!fs.existsSync("./witnet/assets/requests.js")) {
155
- fs.cpSync("node_modules/@witnet/sdk/witnet/assets/_requests.js", "./witnet/assets/requests.js")
156
- }
157
- if (!fs.existsSync("./witnet/assets/sources.js")) {
158
- fs.cpSync("node_modules/@witnet/sdk/witnet/assets/_sources.js", "./witnet/assets/sources.js")
159
- }
160
- if (!fs.existsSync("./witnet/assets/templates.js")) {
161
- fs.cpSync("node_modules/@witnet/sdk/witnet/assets/_templates.js", "./witnet/assets/templates.js")
162
- }
163
- console.info(`Initialized Witnet Radon workspace at folder ${process.cwd()}/witnet/assets`)
164
- }
165
-
166
- async function assets (options = {}, [...patterns]) {
167
- helpers.traceHeader(
168
- `${options?.module ? options.module.toUpperCase() : path.basename(process.cwd()).toUpperCase()} RADON ASSETS`,
169
- helpers.colors.white
170
- )
171
- const assets = clearEmptyBranches(loadAssets(options), patterns, options?.filter)
172
- if (assets && Object.keys(assets).length > 0) {
173
- traceWitnetArtifacts(assets, patterns, " ", options?.filter)
174
- } else {
175
- console.info("> No custom Radon assets declared just yet.")
176
- }
177
- }
178
- /// -------------------------------------------------------------------------------------------------------------------
179
-
180
- async function check (options = {}) {
181
- if (!isModuleInitialized) {
182
- throw new Error(`No Witnet Radon workspace has been initialized. Please, run ${white("npx witnet radon init")} if willing to declare your own Radon assets.`)
183
- }
184
- try {
185
- const assets = loadAssets({ ...options, legacy: true })
186
- const [
187
- modals,
188
- requests,
189
- sources,
190
- templates,
191
- ] = [
192
- helpers.countLeaves(Witnet.Radon.RadonModal, assets),
193
- helpers.countLeaves(Witnet.Radon.RadonRequest, assets),
194
- helpers.countLeaves(Witnet.Radon.RadonRetrieval, assets?.sources),
195
- helpers.countLeaves(Witnet.Radon.RadonTemplate, assets),
196
- ]
197
- if (modals > 0) console.info("> Radon modals: ", modals)
198
- if (sources > 0) console.info("> Radon sources: ", sources)
199
- if (requests > 0) console.info("> Radon requests: ", requests)
200
- if (templates > 0) console.info("> Radon templates:", templates)
201
-
202
- if (modals + sources + requests + templates === 0) {
203
- console.info("-----------------------------")
204
- console.info("No Radon assets declared yet!")
205
- } else {
206
- console.info("--------------------------------------")
207
- console.info("All Radon assets checked successfully!")
208
- }
209
- } catch (e) {
210
- console.error("Radon assets verification failed:")
211
- console.info("----------------------------------")
212
- console.info(e)
213
- }
214
- }
215
- /// -------------------------------------------------------------------------------------------------------------------
216
-
217
- async function decode (options = {}, args = []) {
218
- if (args.length === 0) {
219
- throw Error("No Radon asset was specified")
220
- }
221
- const asset = args[0]
222
- if (helpers.isHexString(asset)) {
223
- try {
224
- const request = Witnet.Radon.RadonRequest.fromBytecode(asset)
225
- traceWitnetRadonRequest(request, options)
226
- } catch (err) {
227
- console.error(err)
228
- if ((asset.startsWith("0x") && asset.length === 66) || (!asset.startsWith("0x") && asset.length === 64)) {
229
- // TODO: assume it's a RAD_HASH, and try to retrieve the BYTECODE from the Witnet network
230
- }
231
- }
232
- } else {
233
- args = args.slice(1)
234
-
235
- const assets = loadAssets(options)
236
- const headline = options?.headline
237
- const crafts = flattenRadonArtifacts(assets).filter(craft => craft.key.toLowerCase().indexOf(asset.toLowerCase()) >= 0)
238
- if (crafts.length === 0) {
239
- throw Error(`No matched found for pattern "${asset}"`)
240
- }
241
- for (let { artifact, key } of crafts) {
242
- let prefix = ""
243
- if (artifact instanceof Witnet.Radon.RadonRequest) {
244
- prefix = "RadonRequest::"
245
- } else if (artifact instanceof Witnet.Radon.RadonModal) {
246
- artifact.providers = ["https://dummy"]
247
- const modalArgs = []
248
- let argIndex = 0
249
- while (modalArgs.length < artifact.argsCount) {
250
- modalArgs.push(`{:${++argIndex}}`)
251
- }
252
- artifact = artifact.buildRadonRequest(modalArgs)
253
- prefix = "RadonModal::"
254
- } else if (artifact instanceof Witnet.Radon.RadonTemplate) {
255
- const templateArgs = artifact.sources.map(({ argsCount }) =>
256
- Array.from({ length: argsCount }, (_, i) => `{:${i}}`)
257
- )
258
- artifact = artifact.buildRadonRequest(templateArgs)
259
- prefix = "RadonTemplate::"
260
- } else if (artifact instanceof Witnet.Radon.RadonRetrieval) {
261
- if (artifact.argsCount > 0) {
262
- const retrievalArgs = Array.from(
263
- { length: artifact.argsCount },
264
- (_, i) => `{:${i + 1}}`
265
- )
266
- artifact = artifact.foldArgs(retrievalArgs)
267
- }
268
- artifact = new Witnet.Radon.RadonRequest({ sources: artifact })
269
- prefix = "RadonRetrieval::"
270
- }
271
- if (!headline) {
272
- options.headline = `${prefix}${key}`
273
- }
274
- traceWitnetRadonRequest(artifact, options)
275
- if (options?.verbose && key !== crafts[crafts.length - 1].key) {
276
- console.info(`${options?.indent || ""}${"─".repeat(150)}`)
277
- }
278
- console.info()
279
- }
280
- }
281
- }
282
- /// -------------------------------------------------------------------------------------------------------------------
283
-
284
- async function dryrun (options = {}, args = []) {
285
- if (args.length === 0) {
286
- throw Error("No Radon asset was specified")
287
- }
288
- const asset = args[0]
289
- if (helpers.isHexString(asset)) {
290
- try {
291
- const request = Witnet.Radon.RadonRequest.fromBytecode(asset)
292
- await traceWitnetRadonRequestDryRun(request, options)
293
- } catch {
294
- if ((asset.startsWith("0x") && asset.length === 66) || (!asset.startsWith("0x") && asset.length === 64)) {
295
- // TODO: assume it's a RAD_HASH, and try to retrieve the BYTECODE from the Witnet network
296
- }
297
- }
298
- } else {
299
- args = args.slice(1)
300
- const assets = loadAssets(options)
301
- const headline = options?.headline
302
- const crafts = flattenRadonArtifacts(assets).filter(craft => craft.key.toLowerCase().indexOf(asset.toLowerCase()) >= 0)
303
- if (crafts.length === 0) {
304
- throw Error(`No matched found for pattern "${asset}"`)
305
- }
306
- for (let { artifact, key } of crafts) {
307
- let prefix = ""
308
- if (artifact instanceof Witnet.Radon.RadonRequest) {
309
- prefix = "RadonRequest::"
310
- } else {
311
- if (!artifact?.samples) {
312
- console.error(`${artifact.constructor.name}::${key}: cannot dry-run if no sample parameters are declared.\n`)
313
- continue
314
- }
315
- let artifactArgs = []
316
- if (options?.default) {
317
- artifactArgs = Object.values(artifact.samples)[0]
318
- } else {
319
- const prompt = inquirer.createPromptModule()
320
- const sample = await prompt([{
321
- choices: Object.keys(artifact.samples),
322
- message: `${artifact.constructor.name}::${key} args:`,
323
- name: "key",
324
- type: "list",
325
- }])
326
- artifactArgs = artifact.samples[sample.key]
327
- }
328
- if (artifact instanceof Witnet.Radon.RadonModal) {
329
- artifact.providers = artifactArgs.shift().split(";")
330
- artifact = artifact.buildRadonRequest(artifactArgs)
331
- prefix = "RadonModal::"
332
- } else if (artifact instanceof Witnet.Radon.RadonTemplate) {
333
- artifact = artifact.buildRadonRequest(artifactArgs)
334
- prefix = "RadonTemplate::"
335
- } else if (artifact instanceof Witnet.Radon.RadonRetrieval) {
336
- artifact = new Witnet.Radon.RadonRequest({ sources: artifact.foldArgs(artifactArgs) })
337
- prefix = "RadonRetrieval::"
338
- }
339
- }
340
- if (!headline) {
341
- options.headline = `${prefix}${key}`
342
- }
343
- await traceWitnetRadonRequestDryRun(artifact, options)
344
- if (options?.verbose && key !== crafts[crafts.length - 1].key) {
345
- console.info(`${options?.indent || ""}${"─".repeat(150)}`)
346
- }
347
- console.info()
348
- }
349
- }
350
- }
351
- /// -------------------------------------------------------------------------------------------------------------------
352
-
353
- /// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
354
- /// CLI SUBMODULE INTERNAL METHODS ------------------------------------------------------------------------------------
355
-
356
- const extractTypeName = (str) => str ? str.split(/(?=[A-Z])/).slice(1).join("") : "Any"
357
-
358
- const stringifyFilter = (x, c) => {
359
- const color = c || helpers.colors.mcyan
360
- return color(`${Witnet.Radon.filters.Opcodes[x.opcode]}(${x.args ? JSON.stringify(x.args) : ""})`)
361
- }
362
-
363
- const stringifyReducer = (x, c) => {
364
- const color = c || helpers.colors.mcyan
365
- return color(`${Witnet.Radon.reducers.Opcodes[x.opcode]}()`)
366
- }
367
-
368
- function loadAssets (options) {
369
- const { assets } = options?.module ? require(options.module) : (options?.legacy ? {} : require("@witnet/sdk"))
370
- return isModuleInitialized && fs.existsSync(`${WITNET_ASSETS_PATH}`) ? merge(assets, require(`${WITNET_ASSETS_PATH}`)) : assets
371
- }
372
-
373
- function flattenRadonArtifacts (tree, headers) {
374
- if (!headers) headers = []
375
- const matches = []
376
- for (const key in tree) {
377
- if (
378
- tree[key] instanceof Witnet.Radon.RadonRetrieval ||
379
- tree[key] instanceof Witnet.Radon.RadonModal ||
380
- tree[key] instanceof Witnet.Radon.RadonRequest ||
381
- tree[key] instanceof Witnet.Radon.RadonTemplate
382
- ) {
383
- matches.push({
384
- key,
385
- artifact: tree[key],
386
- })
387
- } else if (typeof tree[key] === "object") {
388
- matches.push(...flattenRadonArtifacts(
389
- tree[key],
390
- [...headers, key]
391
- ))
392
- }
393
- }
394
- return matches
395
- };
396
-
397
- function countWitnetArtifacts (assets, args, filter = false) {
398
- let counter = 0
399
- Object.entries(assets).forEach(([key, value]) => {
400
- if ((
401
- value instanceof Witnet.Radon.RadonModal ||
402
- value instanceof Witnet.Radon.RadonRequest ||
403
- value instanceof Witnet.Radon.RadonTemplate ||
404
- value instanceof Witnet.Radon.RadonRetrieval
405
- ) && (
406
- !filter ||
407
- !args ||
408
- args.length === 0 ||
409
- args.find(arg => key.toLowerCase().indexOf(arg.toLowerCase()) >= 0)
410
- )) {
411
- counter++
412
- } else if (typeof value === "object") {
413
- counter += countWitnetArtifacts(value, args)
414
- }
415
- })
416
- return counter
417
- }
418
-
419
- function clearEmptyBranches (node, args, filter) {
420
- if (node) {
421
- const assets = Object.fromEntries(
422
- Object.entries(node).map(([key, value]) => {
423
- if (
424
- (!filter || args.find(arg => key.toLowerCase().indexOf(arg.toLowerCase()) >= 0)) && (
425
- value instanceof Witnet.Radon.RadonRetrieval ||
426
- value instanceof Witnet.Radon.RadonModal ||
427
- value instanceof Witnet.Radon.RadonRequest ||
428
- value instanceof Witnet.Radon.RadonTemplate
429
- )
430
- ) {
431
- return [key, value]
432
- } else if (typeof value === "object") {
433
- if (countWitnetArtifacts(value, args, filter) > 0) {
434
- return [key, clearEmptyBranches(value, args, filter)]
435
- } else {
436
- return [key, undefined]
437
- }
438
- } else {
439
- return [key, undefined]
440
- }
441
- })
442
- .filter(([, value]) => value !== undefined)
443
- )
444
- if (Object.keys(assets).length > 0) {
445
- return assets
446
- } else {
447
- return undefined
448
- }
449
- }
450
- }
451
-
452
- function traceWitnetArtifacts (assets, args, indent = "", filter = false) {
453
- const prefix = `${indent}`
454
- Object.keys(assets).forEach((key, index) => {
455
- const isLast = index === Object.keys(assets).length - 1
456
- const found = args.find(arg => key.toLowerCase().indexOf(arg.toLowerCase()) >= 0)
457
- const color = found ? helpers.colors.mcyan : helpers.colors.cyan
458
- if (assets[key] instanceof Witnet.Radon.RadonRequest) {
459
- if (!filter || found) {
460
- console.info(`${prefix}${color(key)}`)
461
- if (isLast) {
462
- console.info(`${prefix}`)
463
- }
464
- }
465
- } else if (
466
- assets[key] instanceof Witnet.Radon.RadonTemplate ||
467
- assets[key] instanceof Witnet.Radon.RadonModal
468
- ) {
469
- const argsCount = assets[key].argsCount
470
- if (!filter || found) {
471
- console.info(`${prefix}${color(key)} ${argsCount > 0 ? helpers.colors.green(`(${argsCount} args)`) : ""}`)
472
- if (isLast) {
473
- console.info(`${prefix}`)
474
- }
475
- }
476
- } else if (assets[key] instanceof Witnet.Radon.RadonRetrieval) {
477
- const argsCount = assets[key].argsCount
478
- if (!filter || found) {
479
- console.info(`${prefix}${color(key)} ${argsCount > 0 ? helpers.colors.green(`(${argsCount} args)`) : ""}`)
480
- if (isLast) {
481
- console.info(`${prefix}`)
482
- }
483
- }
484
- } else if (typeof assets[key] === "object" && countWitnetArtifacts(assets[key], args, filter) > 0) {
485
- console.info(`${indent}${isLast ? "└─ " : "├─ "}${key}`)
486
- traceWitnetArtifacts(assets[key], args, !isLast ? `${indent}│ ` : `${indent} `, filter)
487
- }
488
- })
489
- }
490
-
491
- function traceWitnetRadonReportHeadline (request, options) {
492
- const trait = (str) => `${str}${" ".repeat(66 - str.length)}`
493
- const indent = options?.indent ? " ".repeat(options.indent) : ""
494
- const resultDataType = `Result<${extractTypeName(request.sources[0]?.script?.outputType.constructor.name)}, RadonError>`
495
- console.info(`${indent}╔══════════════════════════════════════════════════════════════════════════════╗`)
496
- console.info(`${indent}║ ${helpers.colors.white(options?.headline)}${" ".repeat(77 - options?.headline.length)}║`)
497
- console.info(`${indent}╠══════════════════════════════════════════════════════════════════════════════╣`)
498
- console.info(`${indent}║ ${helpers.colors.white("RAD hash")}: ${helpers.colors.lgreen(request.radHash)} ║`)
499
- console.info(`${indent}║ RAD size: ${helpers.colors.green(trait(helpers.commas(request.weight()) + " bytes"))} ║`)
500
- console.info(`${indent}║ RAD type: ${helpers.colors.yellow(trait(resultDataType))} ║`)
501
- // if (!options.verbose) {
502
- // console.info(`${indent}║ > Radon operators: ${white(trait(commas(request.opsCount())))} ║`)
503
- // }
504
- // console.info(`${indent}╠════════════════════════════════════════════════════════════════════════════╣`)
505
- // console.info(`${indent}║ > Times solved: ${white(trait("{ values: 123, errors: 220 }"))} ║`)
506
- // console.info(`${indent}║ > Times witnessed: ${white(trait("{ values: 2130, errors: 1326 }"))} ║`)
507
- // console.info(`${indent}║ > Total fees: ${white(trait("15,234.123 Wits"))} ║`)
508
- // console.info(`${indent}║ > Total slash: ${white(trait(" 56.123 Wits"))} ║`)
509
- // console.info(`${indent}║ > Total burn: ${white(trait(" 0.789 Wits"))} ║`)
510
- // if (verbose) {
511
- // console.info(`${indent}╚══╤═════════════════════════════════════════════════════════════════════════╝`)
512
- // } else {
513
- // console.info(`${indent}╚════════════════════════════════════════════════════════════════════════════╝`)
514
- // }
515
- }
516
-
517
- function traceWitnetRadonRequest (request, options) {
518
- const indent = options?.indent ? " ".repeat(parseInt(options.indent)) : ""
519
- if (options?.json) {
520
- console.info(JSON.stringify(request.toProtobuf(), null, options?.indent || 0))
521
- } else {
522
- if (!options.headline) options.headline = "WITNET DATA REQUEST DISASSEMBLE"
523
- traceWitnetRadonReportHeadline(request, options)
524
-
525
- console.info(`${indent}╚══╤═══════════════════════════════════════════════════════════════════════════╝`)
526
- console.info(`${indent}┌──┴─────────────────┐`)
527
- console.info(`${indent}│ ${helpers.colors.white("RETRIEVE DATA")} │`) // ├ ┤
528
- console.info(`${indent}└──┬─┬───────────────┘`)
529
- request.sources.forEach((source, sourceIndex) => {
530
- const authority = source.authority?.toUpperCase().split(".").slice(-2).join(".") || (
531
- source.method === Witnet.Radon.retrievals.Methods.RNG ? "WIT/RNG" : ""
532
- )
533
- const corner = sourceIndex === request.sources.length - 1 ? "└" : "├"
534
- const sep = sourceIndex === request.sources.length - 1 ? " " : ""
535
- console.info(
536
- `${indent} │ ${corner}─ ${helpers.colors.white("[ ")}${helpers.colors.white(`Data source #${sourceIndex + 1}`)
537
- } ${" ".repeat(3 - sourceIndex.toString().length)}${helpers.colors.white(authority)} ${helpers.colors.white("]")}`
538
- )
539
- if (source.method !== Witnet.Radon.retrievals.Methods.RNG) {
540
- console.info(
541
- `${indent} │ ${sep} > Request: ${
542
- helpers.colors.mgreen(Witnet.Radon.retrievals.Methods[source.method].split(/(?=[A-Z])/).join("-").toUpperCase())
543
- }`
544
- )
545
- console.info(`${indent} │ ${sep} > URL query: ${helpers.colors.green(source.url)}`)
546
- if (source?.headers) {
547
- console.info(`${indent} │ ${sep} > HTTP headers: ${helpers.colors.green(JSON.stringify(source.headers))}`)
548
- }
549
- if (source?.body) {
550
- console.info(`${indent} │ ${sep} > HTTP body: ${helpers.colors.green(source.body)}`)
551
- }
552
- if (source?.script) {
553
- const steps = source.script.disect()
554
- console.info(
555
- `${indent} │ ${sep} > Radon script: ${helpers.colors.lyellow("[ ")
556
- }${helpers.colors.yellow(steps[0][1])}${" ".repeat(12 - steps[0][1].length)
557
- }${helpers.colors.lyellow(" ]")
558
- } ${helpers.colors.mcyan(steps[0][2])}`
559
- )
560
- steps.slice(1).forEach(step => {
561
- console.info(
562
- `${indent} │ ${sep} ${helpers.colors.lyellow("[ ")
563
- }${helpers.colors.yellow(step[1])
564
- }${" ".repeat(12 - step[1].length)
565
- }${helpers.colors.lyellow(" ]")
566
- } ${" ".repeat(2 * step[0])}${helpers.colors.mcyan(step[2])
567
- }`
568
- )
569
- })
570
- const outputType = source.script.outputType.constructor.name || "RadonAny"
571
- console.info(
572
- `${indent} │ ${sep} ${helpers.colors.lyellow("[ ")
573
- }${helpers.colors.yellow(outputType)
574
- }${" ".repeat(12 - outputType.length)
575
- }${helpers.colors.lyellow(" ]")
576
- }`
577
- )
578
- }
579
- }
580
- if (sourceIndex < request.sources.length - 1) {
581
- console.info(`${indent} │ │`)
582
- }
583
- })
584
- console.info(`${indent}┌──┴──────────────────┐`)
585
- console.info(`${indent}│ ${helpers.colors.white("AGGREGATE SOURCES")} │`)
586
- console.info(`${indent}└──┬──────────────────┘`) // ┬
587
- request.sourcesReducer?.filters.forEach(filter => console.info(`${indent} > Radon filter: ${stringifyFilter(filter)}`))
588
- console.info(`${indent} │ > Radon reducer: ${stringifyReducer(request.sourcesReducer)}`)
589
- console.info(`${indent}┌──┴──────────────────┐`)
590
- console.info(`${indent}│ ${helpers.colors.white("WITNESSING TALLY")} │`)
591
- console.info(`${indent}└─────────────────────┘`) // ┬
592
- request.witnessReducer?.filters.forEach(filter => console.info(`${indent} > Radon filter: ${stringifyFilter(filter)}`))
593
- console.info(`${indent} > Radon reducer: ${stringifyReducer(request.witnessReducer)}`)
594
- }
595
- }
596
-
597
- async function traceWitnetRadonRequestDryRun (request, options) {
598
- const bytecode = request.toBytecode()
599
- let report = await helpers
600
- .toolkitRun(options, ["try-data-request", "--hex", bytecode.startsWith("0x") ? bytecode.slice(2) : bytecode])
601
- .catch((err) => {
602
- let errorMessage = err.message.split("\n").slice(1).join("\n").trim()
603
- const errorRegex = /.*^error: (?<message>.*)$.*/gm
604
- const matched = errorRegex.exec(err.message)
605
- if (matched) {
606
- errorMessage = matched.groups.message
607
- }
608
- throw errorMessage || err
609
- })
610
- if (!report) {
611
- throw Error("No dry-report?")
612
- } else {
613
- report = JSON.parse(report)
614
- }
615
- const result = report?.aggregate.result
616
- const resultType = Object.keys(result)[0]
617
- const resultValue = Object.values(result)[0]
618
- if (options?.json) {
619
- if (options?.verbose) {
620
- console.info(JSON.stringify(report, null, options?.indent ? " ".repeat(options.indent) : ""))
621
- } else {
622
- result[resultType] = resultValue
623
- console.info(JSON.stringify(result, null, options?.indent ? " ".repeat(options.indent) : ""))
624
- }
625
- return
626
- }
627
- if (!options.headline) options.headline = "WITNET DATA REQUEST DRY-RUN REPORT"
628
- traceWitnetRadonReportHeadline(request, options)
629
- const indent = options?.indent ? " ".repeat(options.indent) : ""
630
- console.info(`${indent}╚══╤═══════════════════════════════════════════════════════════════════════════╝`)
631
- let execTimeMs = report.retrieve?.map(retrieval =>
632
- (retrieval?.running_time.secs || 0) + (retrieval?.running_time.nanos || 0) / 1000
633
- ).reduce(
634
- (sum, secs) => sum + secs
635
- )
636
- execTimeMs = Math.round(execTimeMs) + " ms"
637
- let flexbar = "─".repeat(17)
638
- let flexspc = " ".repeat(flexbar.length + 12)
639
- console.info(`${indent}┌──┴─────────────────────────────${flexbar}──────┐`)
640
- console.info(`${indent}│ ${helpers.colors.white("Data providers")} ${flexspc} │`) // ├ ┤
641
- console.info(`${indent}├────────────────────────────────${flexbar}──────┤`)
642
- console.info(`${indent}│ Execution time: ${helpers.colors.green(execTimeMs)} ${" ".repeat(flexbar.length + 19 - execTimeMs.length)} │`)
643
- console.info(`${indent}└──┬─┬───────────────────────────${flexbar}──────┘`)
644
- request.sources.forEach((source, sourceIndex) => {
645
- const authority = source.authority?.toUpperCase().split(".").slice(-2).join(".") || (
646
- source.method === Witnet.Radon.retrievals.Methods.RNG ? "WIT/RNG" : ""
647
- )
648
- const corner = sourceIndex === request.sources.length - 1 ? "" : ""
649
- const sep = sourceIndex === request.sources.length - 1 ? " " : "│"
650
- const color = report.retrieve[sourceIndex].result?.RadonError
651
- ? (options?.verbose ? helpers.colors.lgray : helpers.colors.gray)
652
- : (options?.verbose ? helpers.colors.lgreen : helpers.colors.green)
653
- if (options?.verbose) {
654
- console.info(
655
- `${indent} │ ${corner}─ ${
656
- helpers.colors.white("[ ")
657
- }${
658
- helpers.colors.white(`Data Source #${sourceIndex + 1}`)
659
- } ${
660
- " ".repeat(3 - sourceIndex.toString().length)
661
- }${
662
- color(authority)
663
- } ${
664
- helpers.colors.white("]")
665
- }`
666
- )
667
- } else {
668
- console.info(`${indent} │ ${corner}─ [ ${color(authority)} ]`)
669
- }
670
- if (source.method !== Witnet.Radon.retrievals.Methods.RNG && options?.verbose) {
671
- // const result = report.retrieve[sourceIndex].result
672
- // const resultType = Object.keys(result)[0]
673
- // const resultValue = JSON.stringify(Object.values(result)[0])
674
- console.info(
675
- `${indent} │ ${sep} > Request: ${
676
- helpers.colors.mgreen(Witnet.Radon.retrievals.Methods[source.method].split(/(?=[A-Z])/).join("-").toUpperCase())
677
- }`
678
- )
679
- console.info(`${indent} │ ${sep} > URL query: ${helpers.colors.green(source.url)}`)
680
- if (source?.headers) {
681
- console.info(`${indent} │ ${sep} > HTTP headers: ${helpers.colors.green(JSON.stringify(source.headers))}`)
682
- }
683
- if (source?.body) {
684
- console.info(`${indent} │ ${sep} > HTTP body: ${helpers.colors.green(source.body)}`)
685
- }
686
- const printData = (headline, data, color) => {
687
- const type = Object.keys(data)[0]
688
- data = typeof data[type] === "object" || Array.isArray(data[type]) ? JSON.stringify(data[type]) : data[type]
689
- const lines = data.match(/.{1,96}/g).slice(0, 256)
690
- if (lines.length === 256) lines[255] += "..."
691
- const typeColor = (type === "RadonError") ? helpers.colors.red : helpers.colors.yellow
692
- const lineColor = (type === "RadonError") ? helpers.colors.gray : color
693
- console.info(
694
- `${indent} │ ${sep} > ${headline}${" ".repeat(15 - headline.length)} \x1b[1;m${
695
- typeColor("[ ")
696
- }\x1b[0m${typeColor(type)}${
697
- " ".repeat(12 - type.length)
698
- }\x1b[1;m${typeColor(" ]")}\x1b[0m ${
699
- lineColor(lines[0])
700
- }`)
701
- lines.slice(1).forEach(line => {
702
- console.info(`${indent} │ ${sep} ${lineColor(line)}`)
703
- })
704
- }
705
- if (report?.retrieve[sourceIndex]?.partial_results) {
706
- printData("HTTP response:", report?.retrieve[sourceIndex]?.partial_results[0], helpers.colors.cyan)
707
- }
708
- printData("Radon result:", report?.retrieve[sourceIndex]?.result, helpers.colors.mcyan)
709
- }
710
- if (options?.verbose && sourceIndex < request.sources.length - 1) {
711
- console.info(`${indent} │ │`)
712
- }
713
- })
714
- flexbar = "─".repeat(24)
715
- flexspc = " ".repeat(36)
716
- console.info(`${indent}┌──┴───────────────────────────${flexbar}─┐`)
717
- console.info(`${indent}│ ${helpers.colors.white("Aggregated result")}${flexspc} │`) // ├ ┤
718
- console.info(`${indent}├──────────────────────────────${flexbar}─┤`)
719
- if (options?.verbose) {
720
- let partial_index = 0
721
- const partial_results = report.sourcesReducer?.partial_results
722
- request.sourcesReducer?.filters.forEach(filter => {
723
- const color = (partial_results && partial_results[partial_index]?.RadonArray) ? helpers.colors.mcyan : helpers.colors.gray
724
- const items = (partial_results && partial_results[partial_index]?.RadonArray)
725
- ? ` over ${partial_results[partial_index]?.RadonArray.length} sources`
726
- : ""
727
- partial_index += 1
728
- filter = stringifyFilter(filter, color)
729
- console.info(
730
- `${indent}│ Radon filter: ${filter}${
731
- helpers.colors.cyan(items)
732
- }${
733
- " ".repeat(flexbar.length + 22 - filter.length - items.length)
734
- } │`
735
- )
736
- })
737
- const color = (partial_results && partial_results[partial_index]?.RadonArray) ? helpers.colors.mcyan : helpers.colors.gray
738
- const items = (partial_results && partial_results[partial_index]?.RadonArray)
739
- ? ` over ${partial_results[partial_index]?.RadonArray.length} sources`
740
- : ""
741
- const reducer = stringifyReducer(request.sourcesReducer, color)
742
- console.info(
743
- `${indent}│ Radon reducer: ${reducer}${
744
- helpers.colors.cyan(items)}${" ".repeat(flexbar.length + 22 - reducer.length - items.length)
745
- } │`
746
- )
747
- }
748
- console.info(`${indent}│ Result size: ${helpers.colors.cyan("xxx bytes")}${" ".repeat(flexbar.length + 13 - 9)} │`)
749
- console.info(`${indent}└────┬─────────────────────────${flexbar}─┘`)
750
- const printMapItem = (indent, width, key, value, indent2 = "") => {
751
- if (key) key = `${indent2}"${key}": `
752
- else key = `${indent2}`
753
- let type = extractTypeName(Object.keys(value)[0])
754
- value = Object.values(value)[0]
755
- if (["Map", "Array"].includes(type)) {
756
- if (key.length > width - 12) {
757
- console.info(
758
- `${indent} ${
759
- helpers.colors.myellow(`[ ${type}${" ".repeat(7 - type.length)} ]`)
760
- } ${
761
- " ".repeat(width - 15)}${helpers.colors.green("...")
762
- }`
763
- )
764
- } else {
765
- console.info(
766
- `${indent} ${
767
- helpers.colors.myellow(`[ ${type}${" ".repeat(7 - type.length)} ]`)
768
- } ${
769
- helpers.colors.green(key)
770
- }${
771
- " ".repeat(width - 12 - key.length)
772
- }`
773
- )
774
- }
775
- Object.entries(value).forEach(([key, value]) => printMapItem(indent, width, type === "Map" ? key : null, value, indent2 + " "))
776
- } else {
777
- if (key.length > width - 12) {
778
- console.info(`${indent} ${helpers.colors.yellow(type)} ${" ".repeat(width - 15)}${helpers.colors.green("...")}`)
779
- } else {
780
- if (["String", "Error"].includes(type)) {
781
- value = JSON.stringify(value)
782
- }
783
- type = `[ ${type}${" ".repeat(7 - type.length)} ]`
784
- const result = key + value
785
- // let spaces = width - 12 - result.length
786
- if (result.length > width - 15) {
787
- value = value.slice(0, width - 15 - key.length) + "..."
788
- // spaces = 0
789
- }
790
- console.info(`${indent} ${helpers.colors.yellow(type)} ${helpers.colors.green(key)}${helpers.colors.mcyan(value)}`)
791
- }
792
- }
793
- }
794
- const printResult = (indent, width, resultType, resultValue) => {
795
- resultType = extractTypeName(resultType)
796
- resultValue = typeof resultValue === "object" || Array.isArray(resultValue) ? JSON.stringify(resultValue) : resultValue
797
- if (["Map", "Array"].includes(resultType)) {
798
- console.info(`${indent} └─ ${helpers.colors.lyellow(`[ ${resultType}${" ".repeat(7 - resultType.length)} ]`)}`)
799
- const obj = JSON.parse(resultValue)
800
- Object.entries(obj).forEach(([key, value]) => printMapItem(indent, width, resultType === "Map" ? key : null, value))
801
- } else {
802
- if (resultType === "Bytes") {
803
- resultValue = JSON.parse(resultValue).map(char => ("00" + char.toString(16)).slice(-2)).join("")
804
- }
805
- const color = resultType.indexOf("Error") > -1 ? helpers.colors.gray : helpers.colors.lcyan
806
- const typeText = resultType.indexOf("Error") > -1 ? "\x1b[1;98;41m Error \x1b[0m" : helpers.colors.lyellow(`[ ${resultType} ]`)
807
- const lines = resultValue.match(/.{1,96}/g).slice(0, 256)
808
- console.info(`${indent} └─ ${typeText} ${color(lines[0])}`)
809
- lines.slice(1).forEach(line => {
810
- console.info(`${indent} ${" ".repeat(resultType.length)}${color(line)}`)
811
- })
812
- }
813
- }
814
- printResult(indent, 134, resultType, resultValue)
815
- }
1
+ const fs = require("fs")
2
+ const inquirer = require("inquirer")
3
+ const merge = require("lodash.merge")
4
+ const path = require("path")
5
+
6
+ const helpers = require("../helpers")
7
+ const { Witnet } = require("../../../dist/src")
8
+
9
+ const WITNET_ASSETS_PATH = process.env.WITNET_SDK_RADON_ASSETS_PATH || "../../../../../witnet/assets"
10
+
11
+ /// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
12
+ /// CLI SUBMODULE CONSTANTS ===========================================================================================
13
+
14
+ const isModuleInitialized = fs.existsSync("./witnet/assets/index.js")
15
+
16
+ module.exports = {
17
+ flags: {
18
+ module: {
19
+ hint: "Package where to fetch Radon assets from (supersedes --legacy).",
20
+ param: "NPM_PACKAGE",
21
+ },
22
+ },
23
+ router: isModuleInitialized
24
+ ? {
25
+ assets: {
26
+ hint: "List available Witnet Radon assets.",
27
+ params: "[RADON_ASSETS ...]",
28
+ options: {
29
+ legacy: {
30
+ hint: "List only those declared in witnet/assets folder.",
31
+ },
32
+ filter: {
33
+ hint: "Restrict output to name-matching assets.",
34
+ },
35
+ },
36
+ },
37
+ check: {
38
+ hint: "Check correctness of Witnet Radon artifacts declared in witnet/assets folder.",
39
+ params: [],
40
+ options: {},
41
+ },
42
+ decode: {
43
+ hint: "Break down specs of one or more Radon assets.",
44
+ params: ["RAD_BYTECODE | RAD_HASH | RADON_ASSET"],
45
+ options: {
46
+ json: {
47
+ hint: "Outputs data in JSON format.",
48
+ },
49
+ headline: {
50
+ hint: "Settles output report headline.",
51
+ param: ":string",
52
+ },
53
+ indent: {
54
+ hint: "Prefixes given number of white spaces for every output line.",
55
+ param: ":number",
56
+ },
57
+ },
58
+ },
59
+ "dry-run": {
60
+ hint: "Simulate resolution of one or more Radon assets, as if solved by the Wit/Oracle.",
61
+ params: ["RAD_BYTECODE | RAD_HASH | RADON_ASSET"],
62
+ options: {
63
+ default: {
64
+ hint: "Use default sample parameters on parametrized Radon assets.",
65
+ },
66
+ json: {
67
+ hint: "Outputs data in JSON format.",
68
+ },
69
+ headline: {
70
+ hint: "Settles output report headline.",
71
+ param: ":string",
72
+ },
73
+ indent: {
74
+ hint: "Prefixes given number of white spaces for every output line.",
75
+ param: ":number",
76
+ },
77
+ verbose: {
78
+ hint: "Outputs detailed dry-run report.",
79
+ },
80
+ },
81
+ },
82
+ }
83
+ : {
84
+ assets: {
85
+ hint: "List available Witnet Radon assets.",
86
+ params: "[RADON_ASSETS ...]",
87
+ options: {
88
+ filter: {
89
+ hint: "Restrict output to name-matching assets.",
90
+ },
91
+ },
92
+ },
93
+ decode: {
94
+ hint: "Break down specs of one or more Radon assets.",
95
+ params: ["RAD_BYTECODE | RAD_HASH | RADON_ASSET"],
96
+ options: {
97
+ json: {
98
+ hint: "Outputs data in JSON format.",
99
+ },
100
+ headline: {
101
+ hint: "Settles output report headline.",
102
+ param: ":string",
103
+ },
104
+ indent: {
105
+ hint: "Prefixes given number of white spaces for every output line.",
106
+ param: ":number",
107
+ },
108
+ },
109
+ },
110
+ "dry-run": {
111
+ hint: "Simulate resolution of one or more Radon assets, as if solved by the Wit/Oracle.",
112
+ params: ["RAD_BYTECODE | RAD_HASH | RADON_ASSET"],
113
+ options: {
114
+ json: {
115
+ hint: "Outputs data in JSON format.",
116
+ },
117
+ headline: {
118
+ hint: "Settles output report headline.",
119
+ param: ":string",
120
+ },
121
+ indent: {
122
+ hint: "Prefixes given number of white spaces for every output line.",
123
+ param: ":number",
124
+ },
125
+ verbose: {
126
+ hint: "Outputs detailed dry-run report.",
127
+ },
128
+ },
129
+ },
130
+ init: {
131
+ hint: "Initialize a Witnet Radon workspace in this project.",
132
+ },
133
+ },
134
+ subcommands: {
135
+ assets, init, check, decode, "dry-run": dryrun,
136
+ },
137
+ loadAssets,
138
+ }
139
+
140
+
141
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
142
+ /// CLI SUBMODULE COMMANDS ============================================================================================
143
+
144
+ async function init () {
145
+ if (!fs.existsSync("./witnet/assets/")) {
146
+ fs.mkdirSync("./witnet/assets", { recursive: true })
147
+ }
148
+ if (!fs.existsSync(".env_witnet")) {
149
+ fs.cpSync("node_modules/@witnet/sdk/.env_witnet", ".env_witnet")
150
+ }
151
+ if (!fs.existsSync("./witnet/assets/index.js")) {
152
+ fs.cpSync("node_modules/@witnet/sdk/witnet/assets/_index.js", "./witnet/assets/index.js")
153
+ }
154
+ if (!fs.existsSync("./witnet/assets/requests.js")) {
155
+ fs.cpSync("node_modules/@witnet/sdk/witnet/assets/_requests.js", "./witnet/assets/requests.js")
156
+ }
157
+ if (!fs.existsSync("./witnet/assets/sources.js")) {
158
+ fs.cpSync("node_modules/@witnet/sdk/witnet/assets/_sources.js", "./witnet/assets/sources.js")
159
+ }
160
+ if (!fs.existsSync("./witnet/assets/templates.js")) {
161
+ fs.cpSync("node_modules/@witnet/sdk/witnet/assets/_templates.js", "./witnet/assets/templates.js")
162
+ }
163
+ console.info(`Initialized Witnet Radon workspace at folder ${process.cwd()}/witnet/assets`)
164
+ }
165
+
166
+ async function assets (options = {}, [...patterns]) {
167
+ helpers.traceHeader(
168
+ `${options?.module ? options.module.toUpperCase() : path.basename(process.cwd()).toUpperCase()} RADON ASSETS`,
169
+ helpers.colors.white
170
+ )
171
+ const assets = clearEmptyBranches(loadAssets(options), patterns, options?.filter)
172
+ if (assets && Object.keys(assets).length > 0) {
173
+ traceWitnetArtifacts(assets, patterns, " ", options?.filter)
174
+ } else {
175
+ console.info("> No custom Radon assets declared just yet.")
176
+ }
177
+ }
178
+ /// -------------------------------------------------------------------------------------------------------------------
179
+
180
+ async function check (options = {}) {
181
+ if (!isModuleInitialized) {
182
+ throw new Error(`No Witnet Radon workspace has been initialized. Please, run ${white("npx witnet radon init")} if willing to declare your own Radon assets.`)
183
+ }
184
+ try {
185
+ const assets = loadAssets({ ...options, legacy: true })
186
+ const [
187
+ modals,
188
+ requests,
189
+ sources,
190
+ templates,
191
+ ] = [
192
+ helpers.countLeaves(Witnet.Radon.RadonModal, assets),
193
+ helpers.countLeaves(Witnet.Radon.RadonRequest, assets),
194
+ helpers.countLeaves(Witnet.Radon.RadonRetrieval, assets?.sources),
195
+ helpers.countLeaves(Witnet.Radon.RadonTemplate, assets),
196
+ ]
197
+ if (modals > 0) console.info("> Radon modals: ", modals)
198
+ if (sources > 0) console.info("> Radon sources: ", sources)
199
+ if (requests > 0) console.info("> Radon requests: ", requests)
200
+ if (templates > 0) console.info("> Radon templates:", templates)
201
+
202
+ if (modals + sources + requests + templates === 0) {
203
+ console.info("-----------------------------")
204
+ console.info("No Radon assets declared yet!")
205
+ } else {
206
+ console.info("--------------------------------------")
207
+ console.info("All Radon assets checked successfully!")
208
+ }
209
+ } catch (e) {
210
+ console.error("Radon assets verification failed:")
211
+ console.info("----------------------------------")
212
+ console.info(e)
213
+ }
214
+ }
215
+ /// -------------------------------------------------------------------------------------------------------------------
216
+
217
+ async function decode (options = {}, args = []) {
218
+ if (args.length === 0) {
219
+ throw Error("No Radon asset was specified")
220
+ }
221
+ const asset = args[0]
222
+ if (helpers.isHexString(asset)) {
223
+ try {
224
+ const request = Witnet.Radon.RadonRequest.fromBytecode(asset)
225
+ traceWitnetRadonRequest(request, options)
226
+ } catch (err) {
227
+ console.error(err)
228
+ if ((asset.startsWith("0x") && asset.length === 66) || (!asset.startsWith("0x") && asset.length === 64)) {
229
+ // TODO: assume it's a DR_TX_HASH
230
+ // TODO: assume it's a RAD_HASH
231
+ }
232
+ }
233
+ } else {
234
+ args = args.slice(1)
235
+
236
+ const assets = loadAssets(options)
237
+ const headline = options?.headline
238
+ const crafts = flattenRadonArtifacts(assets).filter(craft => craft.key.toLowerCase().indexOf(asset.toLowerCase()) >= 0)
239
+ if (crafts.length === 0) {
240
+ throw Error(`No matched found for pattern "${asset}"`)
241
+ }
242
+ for (let { artifact, key } of crafts) {
243
+ let prefix = ""
244
+ if (artifact instanceof Witnet.Radon.RadonRequest) {
245
+ prefix = "RadonRequest::"
246
+ } else if (artifact instanceof Witnet.Radon.RadonModal) {
247
+ artifact.providers = ["https://dummy"]
248
+ const modalArgs = []
249
+ let argIndex = 0
250
+ while (modalArgs.length < artifact.argsCount) {
251
+ modalArgs.push(`{:${++argIndex}}`)
252
+ }
253
+ artifact = artifact.buildRadonRequest(modalArgs)
254
+ prefix = "RadonModal::"
255
+ } else if (artifact instanceof Witnet.Radon.RadonTemplate) {
256
+ const templateArgs = artifact.sources.map(({ argsCount }) =>
257
+ Array.from({ length: argsCount }, (_, i) => `{:${i}}`)
258
+ )
259
+ artifact = artifact.buildRadonRequest(templateArgs)
260
+ prefix = "RadonTemplate::"
261
+ } else if (artifact instanceof Witnet.Radon.RadonRetrieval) {
262
+ if (artifact.argsCount > 0) {
263
+ const retrievalArgs = Array.from(
264
+ { length: artifact.argsCount },
265
+ (_, i) => `{:${i + 1}}`
266
+ )
267
+ artifact = artifact.foldArgs(retrievalArgs)
268
+ }
269
+ artifact = new Witnet.Radon.RadonRequest({ sources: artifact })
270
+ prefix = "RadonRetrieval::"
271
+ }
272
+ if (!headline) {
273
+ options.headline = `${prefix}${key}`
274
+ }
275
+ traceWitnetRadonRequest(artifact, options)
276
+ if (options?.verbose && key !== crafts[crafts.length - 1].key) {
277
+ console.info(`${options?.indent || ""}${"─".repeat(150)}`)
278
+ }
279
+ console.info()
280
+ }
281
+ }
282
+ }
283
+ /// -------------------------------------------------------------------------------------------------------------------
284
+
285
+ async function dryrun (options = {}, args = []) {
286
+ if (args.length === 0) {
287
+ throw Error("No Radon asset was specified")
288
+ }
289
+ const asset = args[0]
290
+ if (helpers.isHexString(asset)) {
291
+ try {
292
+ const request = Witnet.Radon.RadonRequest.fromBytecode(asset)
293
+ await traceWitnetRadonRequestDryRun(request, options)
294
+ } catch {
295
+ if ((asset.startsWith("0x") && asset.length === 66) || (!asset.startsWith("0x") && asset.length === 64)) {
296
+ // TODO: assume it's a RAD_HASH, and try to retrieve the BYTECODE from the Witnet network
297
+ }
298
+ }
299
+ } else {
300
+ args = args.slice(1)
301
+ const assets = loadAssets(options)
302
+ const headline = options?.headline
303
+ const crafts = flattenRadonArtifacts(assets).filter(craft => craft.key.toLowerCase().indexOf(asset.toLowerCase()) >= 0)
304
+ if (crafts.length === 0) {
305
+ throw Error(`No matched found for pattern "${asset}"`)
306
+ }
307
+ for (let { artifact, key } of crafts) {
308
+ let prefix = ""
309
+ if (artifact instanceof Witnet.Radon.RadonRequest) {
310
+ prefix = "RadonRequest::"
311
+ } else {
312
+ if (!artifact?.samples) {
313
+ console.error(`${artifact.constructor.name}::${key}: cannot dry-run if no sample parameters are declared.\n`)
314
+ continue
315
+ }
316
+ let artifactArgs = []
317
+ if (options?.default) {
318
+ artifactArgs = Object.values(artifact.samples)[0]
319
+ } else {
320
+ const prompt = inquirer.createPromptModule()
321
+ const sample = await prompt([{
322
+ choices: Object.keys(artifact.samples),
323
+ message: `${artifact.constructor.name}::${key} args:`,
324
+ name: "key",
325
+ type: "list",
326
+ }])
327
+ artifactArgs = artifact.samples[sample.key]
328
+ }
329
+ if (artifact instanceof Witnet.Radon.RadonModal) {
330
+ artifact.providers = artifactArgs.shift().split(";")
331
+ artifact = artifact.buildRadonRequest(artifactArgs)
332
+ prefix = "RadonModal::"
333
+ } else if (artifact instanceof Witnet.Radon.RadonTemplate) {
334
+ artifact = artifact.buildRadonRequest(artifactArgs)
335
+ prefix = "RadonTemplate::"
336
+ } else if (artifact instanceof Witnet.Radon.RadonRetrieval) {
337
+ artifact = new Witnet.Radon.RadonRequest({ sources: artifact.foldArgs(artifactArgs) })
338
+ prefix = "RadonRetrieval::"
339
+ }
340
+ }
341
+ if (!headline) {
342
+ options.headline = `${prefix}${key}`
343
+ }
344
+ await traceWitnetRadonRequestDryRun(artifact, options)
345
+ if (options?.verbose && key !== crafts[crafts.length - 1].key) {
346
+ console.info(`${options?.indent || ""}${"─".repeat(150)}`)
347
+ }
348
+ console.info()
349
+ }
350
+ }
351
+ }
352
+ /// -------------------------------------------------------------------------------------------------------------------
353
+
354
+ /// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
355
+ /// CLI SUBMODULE INTERNAL METHODS ------------------------------------------------------------------------------------
356
+
357
+ const extractTypeName = (str) => str ? str.split(/(?=[A-Z])/).slice(1).join("") : "Any"
358
+
359
+ const stringifyFilter = (x, c) => {
360
+ const color = c || helpers.colors.mcyan
361
+ return color(`${Witnet.Radon.filters.Opcodes[x.opcode]}(${x.args ? JSON.stringify(x.args) : ""})`)
362
+ }
363
+
364
+ const stringifyReducer = (x, c) => {
365
+ const color = c || helpers.colors.mcyan
366
+ return color(`${Witnet.Radon.reducers.Opcodes[x.opcode]}()`)
367
+ }
368
+
369
+ function loadAssets (options) {
370
+ const { assets } = options?.module ? require(options.module) : (options?.legacy ? {} : require("@witnet/sdk"))
371
+ return isModuleInitialized && fs.existsSync(`${WITNET_ASSETS_PATH}`) ? merge(assets, require(`${WITNET_ASSETS_PATH}`)) : assets
372
+ }
373
+
374
+ function flattenRadonArtifacts (tree, headers) {
375
+ if (!headers) headers = []
376
+ const matches = []
377
+ for (const key in tree) {
378
+ if (
379
+ tree[key] instanceof Witnet.Radon.RadonRetrieval ||
380
+ tree[key] instanceof Witnet.Radon.RadonModal ||
381
+ tree[key] instanceof Witnet.Radon.RadonRequest ||
382
+ tree[key] instanceof Witnet.Radon.RadonTemplate
383
+ ) {
384
+ matches.push({
385
+ key,
386
+ artifact: tree[key],
387
+ })
388
+ } else if (typeof tree[key] === "object") {
389
+ matches.push(...flattenRadonArtifacts(
390
+ tree[key],
391
+ [...headers, key]
392
+ ))
393
+ }
394
+ }
395
+ return matches
396
+ };
397
+
398
+ function countWitnetArtifacts (assets, args, filter = false) {
399
+ let counter = 0
400
+ Object.entries(assets).forEach(([key, value]) => {
401
+ if ((
402
+ value instanceof Witnet.Radon.RadonModal ||
403
+ value instanceof Witnet.Radon.RadonRequest ||
404
+ value instanceof Witnet.Radon.RadonTemplate ||
405
+ value instanceof Witnet.Radon.RadonRetrieval
406
+ ) && (
407
+ !filter ||
408
+ !args ||
409
+ args.length === 0 ||
410
+ args.find(arg => key.toLowerCase().indexOf(arg.toLowerCase()) >= 0)
411
+ )) {
412
+ counter++
413
+ } else if (typeof value === "object") {
414
+ counter += countWitnetArtifacts(value, args)
415
+ }
416
+ })
417
+ return counter
418
+ }
419
+
420
+ function clearEmptyBranches (node, args, filter) {
421
+ if (node) {
422
+ const assets = Object.fromEntries(
423
+ Object.entries(node).map(([key, value]) => {
424
+ if (
425
+ (!filter || args.find(arg => key.toLowerCase().indexOf(arg.toLowerCase()) >= 0)) && (
426
+ value instanceof Witnet.Radon.RadonRetrieval ||
427
+ value instanceof Witnet.Radon.RadonModal ||
428
+ value instanceof Witnet.Radon.RadonRequest ||
429
+ value instanceof Witnet.Radon.RadonTemplate
430
+ )
431
+ ) {
432
+ return [key, value]
433
+ } else if (typeof value === "object") {
434
+ if (countWitnetArtifacts(value, args, filter) > 0) {
435
+ return [key, clearEmptyBranches(value, args, filter)]
436
+ } else {
437
+ return [key, undefined]
438
+ }
439
+ } else {
440
+ return [key, undefined]
441
+ }
442
+ })
443
+ .filter(([, value]) => value !== undefined)
444
+ )
445
+ if (Object.keys(assets).length > 0) {
446
+ return assets
447
+ } else {
448
+ return undefined
449
+ }
450
+ }
451
+ }
452
+
453
+ function traceWitnetArtifacts (assets, args, indent = "", filter = false) {
454
+ const prefix = `${indent}`
455
+ Object.keys(assets).forEach((key, index) => {
456
+ const isLast = index === Object.keys(assets).length - 1
457
+ const found = args.find(arg => key.toLowerCase().indexOf(arg.toLowerCase()) >= 0)
458
+ const color = found ? helpers.colors.mcyan : helpers.colors.cyan
459
+ if (assets[key] instanceof Witnet.Radon.RadonRequest) {
460
+ if (!filter || found) {
461
+ console.info(`${prefix}${color(key)}`)
462
+ if (isLast) {
463
+ console.info(`${prefix}`)
464
+ }
465
+ }
466
+ } else if (
467
+ assets[key] instanceof Witnet.Radon.RadonTemplate ||
468
+ assets[key] instanceof Witnet.Radon.RadonModal
469
+ ) {
470
+ const argsCount = assets[key].argsCount
471
+ if (!filter || found) {
472
+ console.info(`${prefix}${color(key)} ${argsCount > 0 ? helpers.colors.green(`(${argsCount} args)`) : ""}`)
473
+ if (isLast) {
474
+ console.info(`${prefix}`)
475
+ }
476
+ }
477
+ } else if (assets[key] instanceof Witnet.Radon.RadonRetrieval) {
478
+ const argsCount = assets[key].argsCount
479
+ if (!filter || found) {
480
+ console.info(`${prefix}${color(key)} ${argsCount > 0 ? helpers.colors.green(`(${argsCount} args)`) : ""}`)
481
+ if (isLast) {
482
+ console.info(`${prefix}`)
483
+ }
484
+ }
485
+ } else if (typeof assets[key] === "object" && countWitnetArtifacts(assets[key], args, filter) > 0) {
486
+ console.info(`${indent}${isLast ? "└─ " : "├─ "}${key}`)
487
+ traceWitnetArtifacts(assets[key], args, !isLast ? `${indent}│ ` : `${indent} `, filter)
488
+ }
489
+ })
490
+ }
491
+
492
+ function traceWitnetRadonReportHeadline (request, options) {
493
+ const trait = (str) => `${str}${" ".repeat(66 - str.length)}`
494
+ const indent = options?.indent ? " ".repeat(options.indent) : ""
495
+ const resultDataType = `Result<${extractTypeName(request.sources[0]?.script?.outputType.constructor.name)}, RadonError>`
496
+ console.info(`${indent}╔══════════════════════════════════════════════════════════════════════════════╗`)
497
+ console.info(`${indent}║ ${helpers.colors.white(options?.headline)}${" ".repeat(77 - options?.headline.length)}║`)
498
+ console.info(`${indent}╠══════════════════════════════════════════════════════════════════════════════╣`)
499
+ console.info(`${indent}║ ${helpers.colors.white("RAD hash")}: ${helpers.colors.lgreen(request.radHash)} ║`)
500
+ console.info(`${indent}║ RAD size: ${helpers.colors.green(trait(helpers.commas(request.weight()) + " bytes"))} ║`)
501
+ console.info(`${indent}║ RAD type: ${helpers.colors.yellow(trait(resultDataType))} ║`)
502
+ // if (!options.verbose) {
503
+ // console.info(`${indent}║ > Radon operators: ${white(trait(commas(request.opsCount())))} ║`)
504
+ // }
505
+ // console.info(`${indent}╠════════════════════════════════════════════════════════════════════════════╣`)
506
+ // console.info(`${indent}║ > Times solved: ${white(trait("{ values: 123, errors: 220 }"))} ║`)
507
+ // console.info(`${indent}║ > Times witnessed: ${white(trait("{ values: 2130, errors: 1326 }"))} ║`)
508
+ // console.info(`${indent}║ > Total fees: ${white(trait("15,234.123 Wits"))} ║`)
509
+ // console.info(`${indent}║ > Total slash: ${white(trait(" 56.123 Wits"))} ║`)
510
+ // console.info(`${indent}║ > Total burn: ${white(trait(" 0.789 Wits"))} ║`)
511
+ // if (verbose) {
512
+ // console.info(`${indent}╚══╤═════════════════════════════════════════════════════════════════════════╝`)
513
+ // } else {
514
+ // console.info(`${indent}╚════════════════════════════════════════════════════════════════════════════╝`)
515
+ // }
516
+ }
517
+
518
+ function traceWitnetRadonRequest (request, options) {
519
+ const indent = options?.indent ? " ".repeat(parseInt(options.indent)) : ""
520
+ if (options?.json) {
521
+ console.info(JSON.stringify(request.toProtobuf(), null, options?.indent || 0))
522
+ } else {
523
+ if (!options.headline) options.headline = "WITNET DATA REQUEST DISASSEMBLE"
524
+ traceWitnetRadonReportHeadline(request, options)
525
+
526
+ console.info(`${indent}╚══╤═══════════════════════════════════════════════════════════════════════════╝`)
527
+ console.info(`${indent}┌──┴─────────────────┐`)
528
+ console.info(`${indent}│ ${helpers.colors.white("RETRIEVE DATA")} │`) // ├ ┤
529
+ console.info(`${indent}└──┬─┬───────────────┘`)
530
+ request.sources.forEach((source, sourceIndex) => {
531
+ const authority = source.authority?.toUpperCase().split(".").slice(-2).join(".") || (
532
+ source.method === Witnet.Radon.retrievals.Methods.RNG ? "WIT/RNG" : ""
533
+ )
534
+ const corner = sourceIndex === request.sources.length - 1 ? "" : ""
535
+ const sep = sourceIndex === request.sources.length - 1 ? " " : "│"
536
+ console.info(
537
+ `${indent}${corner}─ ${helpers.colors.white("[ ")}${helpers.colors.white(`Data source #${sourceIndex + 1}`)
538
+ } ${" ".repeat(3 - sourceIndex.toString().length)}${helpers.colors.white(authority)} ${helpers.colors.white("]")}`
539
+ )
540
+ if (source.method !== Witnet.Radon.retrievals.Methods.RNG) {
541
+ console.info(
542
+ `${indent} │ ${sep} > Request: ${
543
+ helpers.colors.mgreen(Witnet.Radon.retrievals.Methods[source.method].split(/(?=[A-Z])/).join("-").toUpperCase())
544
+ }`
545
+ )
546
+ console.info(`${indent} │ ${sep} > URL query: ${helpers.colors.green(source.url)}`)
547
+ if (source?.headers) {
548
+ console.info(`${indent} │ ${sep} > HTTP headers: ${helpers.colors.green(JSON.stringify(source.headers))}`)
549
+ }
550
+ if (source?.body) {
551
+ console.info(`${indent} │ ${sep} > HTTP body: ${helpers.colors.green(source.body)}`)
552
+ }
553
+ if (source?.script) {
554
+ console.log(source.script.toBytecode())
555
+ const steps = source.script.disect()
556
+ console.info(
557
+ `${indent}${sep} > Radon script: ${helpers.colors.lyellow("[ ")
558
+ }${helpers.colors.yellow(steps[0][1])}${" ".repeat(12 - steps[0][1].length)
559
+ }${helpers.colors.lyellow(" ]")
560
+ } ${helpers.colors.mcyan(steps[0][2])}`
561
+ )
562
+ steps.slice(1).forEach(step => {
563
+ console.info(
564
+ `${indent}${sep} ${helpers.colors.lyellow("[ ")
565
+ }${helpers.colors.yellow(step[1])
566
+ }${" ".repeat(12 - step[1].length)
567
+ }${helpers.colors.lyellow(" ]")
568
+ } ${" ".repeat(2 * step[0])}${helpers.colors.mcyan(step[2])
569
+ }`
570
+ )
571
+ })
572
+ const outputType = source.script.outputType.constructor.name || "RadonAny"
573
+ console.info(
574
+ `${indent}${sep} ${helpers.colors.lyellow("[ ")
575
+ }${helpers.colors.yellow(outputType)
576
+ }${" ".repeat(12 - outputType.length)
577
+ }${helpers.colors.lyellow(" ]")
578
+ }`
579
+ )
580
+ }
581
+ }
582
+ if (sourceIndex < request.sources.length - 1) {
583
+ console.info(`${indent} │ │`)
584
+ }
585
+ })
586
+ console.info(`${indent}┌──┴──────────────────┐`)
587
+ console.info(`${indent}│ ${helpers.colors.white("AGGREGATE SOURCES")} │`)
588
+ console.info(`${indent}└──┬──────────────────┘`) //
589
+ request.sourcesReducer?.filters.forEach(filter => console.info(`${indent} │ > Radon filter: ${stringifyFilter(filter)}`))
590
+ console.info(`${indent} > Radon reducer: ${stringifyReducer(request.sourcesReducer)}`)
591
+ console.info(`${indent}┌──┴──────────────────┐`)
592
+ console.info(`${indent}${helpers.colors.white("WITNESSING TALLY")} │`)
593
+ console.info(`${indent}└─────────────────────┘`) //
594
+ request.witnessReducer?.filters.forEach(filter => console.info(`${indent} > Radon filter: ${stringifyFilter(filter)}`))
595
+ console.info(`${indent} > Radon reducer: ${stringifyReducer(request.witnessReducer)}`)
596
+ }
597
+ }
598
+
599
+ async function traceWitnetRadonRequestDryRun (request, options) {
600
+ const bytecode = request.toBytecode()
601
+ let report = await helpers
602
+ .toolkitRun(options, ["try-data-request", "--hex", bytecode.startsWith("0x") ? bytecode.slice(2) : bytecode])
603
+ .catch((err) => {
604
+ let errorMessage = err.message.split("\n").slice(1).join("\n").trim()
605
+ const errorRegex = /.*^error: (?<message>.*)$.*/gm
606
+ const matched = errorRegex.exec(err.message)
607
+ if (matched) {
608
+ errorMessage = matched.groups.message
609
+ }
610
+ throw errorMessage || err
611
+ })
612
+ if (!report) {
613
+ throw Error("No dry-report?")
614
+ } else {
615
+ report = JSON.parse(report)
616
+ }
617
+ const result = report?.aggregate.result
618
+ const resultType = Object.keys(result)[0]
619
+ const resultValue = Object.values(result)[0]
620
+ if (options?.json) {
621
+ if (options?.verbose) {
622
+ console.info(JSON.stringify(report, null, options?.indent ? " ".repeat(options.indent) : ""))
623
+ } else {
624
+ result[resultType] = resultValue
625
+ console.info(JSON.stringify(result, null, options?.indent ? " ".repeat(options.indent) : ""))
626
+ }
627
+ return
628
+ }
629
+ if (!options.headline) options.headline = "WITNET DATA REQUEST DRY-RUN REPORT"
630
+ traceWitnetRadonReportHeadline(request, options)
631
+ const indent = options?.indent ? " ".repeat(options.indent) : ""
632
+ console.info(`${indent}╚══╤═══════════════════════════════════════════════════════════════════════════╝`)
633
+ let execTimeMs = report.retrieve?.map(retrieval =>
634
+ (retrieval?.running_time.secs || 0) + (retrieval?.running_time.nanos || 0) / 1000
635
+ ).reduce(
636
+ (sum, secs) => sum + secs
637
+ )
638
+ execTimeMs = Math.round(execTimeMs) + " ms"
639
+ let flexbar = "─".repeat(17)
640
+ let flexspc = " ".repeat(flexbar.length + 12)
641
+ console.info(`${indent}┌──┴─────────────────────────────${flexbar}──────┐`)
642
+ console.info(`${indent}│ ${helpers.colors.white("Data providers")} ${flexspc} │`) //
643
+ console.info(`${indent}├────────────────────────────────${flexbar}──────┤`)
644
+ console.info(`${indent}│ Execution time: ${helpers.colors.green(execTimeMs)} ${" ".repeat(flexbar.length + 19 - execTimeMs.length)} │`)
645
+ console.info(`${indent}└──┬─┬───────────────────────────${flexbar}──────┘`)
646
+ request.sources.forEach((source, sourceIndex) => {
647
+ const authority = source.authority?.toUpperCase().split(".").slice(-2).join(".") || (
648
+ source.method === Witnet.Radon.retrievals.Methods.RNG ? "WIT/RNG" : ""
649
+ )
650
+ const corner = sourceIndex === request.sources.length - 1 ? "└" : "├"
651
+ const sep = sourceIndex === request.sources.length - 1 ? " " : "│"
652
+ const color = report.retrieve[sourceIndex].result?.RadonError
653
+ ? (options?.verbose ? helpers.colors.lgray : helpers.colors.gray)
654
+ : (options?.verbose ? helpers.colors.lgreen : helpers.colors.green)
655
+ if (options?.verbose) {
656
+ console.info(
657
+ `${indent}${corner}─ ${
658
+ helpers.colors.white("[ ")
659
+ }${
660
+ helpers.colors.white(`Data Source #${sourceIndex + 1}`)
661
+ } ${
662
+ " ".repeat(3 - sourceIndex.toString().length)
663
+ }${
664
+ color(authority)
665
+ } ${
666
+ helpers.colors.white("]")
667
+ }`
668
+ )
669
+ } else {
670
+ console.info(`${indent} │ ${corner}─ [ ${color(authority)} ]`)
671
+ }
672
+ if (source.method !== Witnet.Radon.retrievals.Methods.RNG && options?.verbose) {
673
+ // const result = report.retrieve[sourceIndex].result
674
+ // const resultType = Object.keys(result)[0]
675
+ // const resultValue = JSON.stringify(Object.values(result)[0])
676
+ console.info(
677
+ `${indent} │ ${sep} > Request: ${
678
+ helpers.colors.mgreen(Witnet.Radon.retrievals.Methods[source.method].split(/(?=[A-Z])/).join("-").toUpperCase())
679
+ }`
680
+ )
681
+ console.info(`${indent} │ ${sep} > URL query: ${helpers.colors.green(source.url)}`)
682
+ if (source?.headers) {
683
+ console.info(`${indent} │ ${sep} > HTTP headers: ${helpers.colors.green(JSON.stringify(source.headers))}`)
684
+ }
685
+ if (source?.body) {
686
+ console.info(`${indent} │ ${sep} > HTTP body: ${helpers.colors.green(source.body)}`)
687
+ }
688
+ const printData = (headline, data, color) => {
689
+ const type = Object.keys(data)[0]
690
+ data = typeof data[type] === "object" || Array.isArray(data[type]) ? JSON.stringify(data[type]) : data[type]
691
+ const lines = data.match(/.{1,96}/g).slice(0, 256)
692
+ if (lines.length === 256) lines[255] += "..."
693
+ const typeColor = (type === "RadonError") ? helpers.colors.red : helpers.colors.yellow
694
+ const lineColor = (type === "RadonError") ? helpers.colors.gray : color
695
+ console.info(
696
+ `${indent}${sep} > ${headline}${" ".repeat(15 - headline.length)} \x1b[1;m${
697
+ typeColor("[ ")
698
+ }\x1b[0m${typeColor(type)}${
699
+ " ".repeat(12 - type.length)
700
+ }\x1b[1;m${typeColor(" ]")}\x1b[0m ${
701
+ lineColor(lines[0])
702
+ }`)
703
+ lines.slice(1).forEach(line => {
704
+ console.info(`${indent} │ ${sep} ${lineColor(line)}`)
705
+ })
706
+ }
707
+ if (report?.retrieve[sourceIndex]?.partial_results) {
708
+ printData("HTTP response:", report?.retrieve[sourceIndex]?.partial_results[0], helpers.colors.cyan)
709
+ }
710
+ printData("Radon result:", report?.retrieve[sourceIndex]?.result, helpers.colors.mcyan)
711
+ }
712
+ if (options?.verbose && sourceIndex < request.sources.length - 1) {
713
+ console.info(`${indent} │ │`)
714
+ }
715
+ })
716
+ flexbar = "─".repeat(24)
717
+ flexspc = " ".repeat(36)
718
+ console.info(`${indent}┌──┴───────────────────────────${flexbar}─┐`)
719
+ console.info(`${indent}│ ${helpers.colors.white("Aggregated result")}${flexspc} │`) // ├ ┤
720
+ console.info(`${indent}├──────────────────────────────${flexbar}─┤`)
721
+ if (options?.verbose) {
722
+ let partial_index = 0
723
+ const partial_results = report.sourcesReducer?.partial_results
724
+ request.sourcesReducer?.filters.forEach(filter => {
725
+ const color = (partial_results && partial_results[partial_index]?.RadonArray) ? helpers.colors.mcyan : helpers.colors.gray
726
+ const items = (partial_results && partial_results[partial_index]?.RadonArray)
727
+ ? ` over ${partial_results[partial_index]?.RadonArray.length} sources`
728
+ : ""
729
+ partial_index += 1
730
+ filter = stringifyFilter(filter, color)
731
+ console.info(
732
+ `${indent}│ Radon filter: ${filter}${
733
+ helpers.colors.cyan(items)
734
+ }${
735
+ " ".repeat(flexbar.length + 22 - filter.length - items.length)
736
+ } │`
737
+ )
738
+ })
739
+ const color = (partial_results && partial_results[partial_index]?.RadonArray) ? helpers.colors.mcyan : helpers.colors.gray
740
+ const items = (partial_results && partial_results[partial_index]?.RadonArray)
741
+ ? ` over ${partial_results[partial_index]?.RadonArray.length} sources`
742
+ : ""
743
+ const reducer = stringifyReducer(request.sourcesReducer, color)
744
+ console.info(
745
+ `${indent} Radon reducer: ${reducer}${
746
+ helpers.colors.cyan(items)}${" ".repeat(flexbar.length + 22 - reducer.length - items.length)
747
+ } │`
748
+ )
749
+ }
750
+ console.info(`${indent}│ Result size: ${helpers.colors.cyan("xxx bytes")}${" ".repeat(flexbar.length + 13 - 9)} │`)
751
+ console.info(`${indent}└────┬─────────────────────────${flexbar}─┘`)
752
+ const printMapItem = (indent, width, key, value, indent2 = "") => {
753
+ if (key) key = `${indent2}"${key}": `
754
+ else key = `${indent2}`
755
+ let type = extractTypeName(Object.keys(value)[0])
756
+ value = Object.values(value)[0]
757
+ if (["Map", "Array"].includes(type)) {
758
+ if (key.length > width - 12) {
759
+ console.info(
760
+ `${indent} ${
761
+ helpers.colors.myellow(`[ ${type}${" ".repeat(7 - type.length)} ]`)
762
+ } ${
763
+ " ".repeat(width - 15)}${helpers.colors.green("...")
764
+ }`
765
+ )
766
+ } else {
767
+ console.info(
768
+ `${indent} ${
769
+ helpers.colors.myellow(`[ ${type}${" ".repeat(7 - type.length)} ]`)
770
+ } ${
771
+ helpers.colors.green(key)
772
+ }${
773
+ " ".repeat(width - 12 - key.length)
774
+ }`
775
+ )
776
+ }
777
+ Object.entries(value).forEach(([key, value]) => printMapItem(indent, width, type === "Map" ? key : null, value, indent2 + " "))
778
+ } else {
779
+ if (key.length > width - 12) {
780
+ console.info(`${indent} ${helpers.colors.yellow(type)} ${" ".repeat(width - 15)}${helpers.colors.green("...")}`)
781
+ } else {
782
+ if (["String", "Error"].includes(type)) {
783
+ value = JSON.stringify(value)
784
+ }
785
+ type = `[ ${type}${" ".repeat(7 - type.length)} ]`
786
+ const result = key + value
787
+ // let spaces = width - 12 - result.length
788
+ if (result.length > width - 15) {
789
+ value = value.slice(0, width - 15 - key.length) + "..."
790
+ // spaces = 0
791
+ }
792
+ console.info(`${indent} ${helpers.colors.yellow(type)} ${helpers.colors.green(key)}${helpers.colors.mcyan(value)}`)
793
+ }
794
+ }
795
+ }
796
+ const printResult = (indent, width, resultType, resultValue) => {
797
+ resultType = extractTypeName(resultType)
798
+ resultValue = typeof resultValue === "object" || Array.isArray(resultValue) ? JSON.stringify(resultValue) : resultValue
799
+ if (["Map", "Array"].includes(resultType)) {
800
+ console.info(`${indent} └─ ${helpers.colors.lyellow(`[ ${resultType}${" ".repeat(7 - resultType.length)} ]`)}`)
801
+ const obj = JSON.parse(resultValue)
802
+ Object.entries(obj).forEach(([key, value]) => printMapItem(indent, width, resultType === "Map" ? key : null, value))
803
+ } else {
804
+ if (resultType === "Bytes") {
805
+ resultValue = JSON.parse(resultValue).map(char => ("00" + char.toString(16)).slice(-2)).join("")
806
+ }
807
+ const color = resultType.indexOf("Error") > -1 ? helpers.colors.gray : helpers.colors.lcyan
808
+ const typeText = resultType.indexOf("Error") > -1 ? "\x1b[1;98;41m Error \x1b[0m" : helpers.colors.lyellow(`[ ${resultType} ]`)
809
+ const lines = resultValue.match(/.{1,96}/g).slice(0, 256)
810
+ console.info(`${indent} └─ ${typeText} ${color(lines[0])}`)
811
+ lines.slice(1).forEach(line => {
812
+ console.info(`${indent} ${" ".repeat(resultType.length)}${color(line)}`)
813
+ })
814
+ }
815
+ }
816
+ printResult(indent, 134, resultType, resultValue)
817
+ }