rippled
Loading...
Searching...
No Matches
JSONRPC_test.cpp
1#include <test/jtx.h>
2#include <test/jtx/envconfig.h>
3
4#include <xrpld/app/misc/TxQ.h>
5#include <xrpld/core/ConfigSections.h>
6#include <xrpld/rpc/detail/TransactionSign.h>
7
8#include <xrpl/basics/contract.h>
9#include <xrpl/beast/unit_test.h>
10#include <xrpl/json/json_reader.h>
11#include <xrpl/protocol/ErrorCodes.h>
12#include <xrpl/server/LoadFeeTrack.h>
13
14namespace xrpl {
15
16namespace RPC {
17
19{
20 char const* const description;
21 int const line;
22 char const* const json;
23 // The JSON is applied to four different interfaces:
24 // 1. sign,
25 // 2. submit,
26 // 3. sign_for, and
27 // 4. submit_multisigned.
28 // The JSON is not valid for all of these interfaces, but it should
29 // crash none of them, and should provide reliable error messages.
30 //
31 // The expMsg array contains the expected error string for the above cases.
33
34 constexpr TxnTestData(
35 char const* description_,
36 int line_,
37 char const* json_,
39 : description(description_), line(line_), json(json_), expMsg{expMsg_}
40 {
41 }
42
43 TxnTestData() = delete;
44 TxnTestData(TxnTestData const&) = delete;
47 operator=(TxnTestData const&) = delete;
50};
51
52static constexpr TxnTestData txnTestArray[] = {
53
54 {"Minimal payment, no Amount only DeliverMax",
55 __LINE__,
56 R"({
57 "command": "dummy_command",
58 "secret": "masterpassphrase",
59 "tx_json": {
60 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
61 "DeliverMax": "1000000000",
62 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
63 "TransactionType": "Payment"
64 }
65})",
66 {{"", "", "Missing field 'account'.", "Missing field 'tx_json.Sequence'."}}},
67
68 {"Pass in Fee with minimal payment, both Amount and DeliverMax.",
69 __LINE__,
70 R"({
71 "command": "dummy_command",
72 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
73 "secret": "masterpassphrase",
74 "tx_json": {
75 "Fee": 10,
76 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
77 "Amount": "1000000000",
78 "DeliverMax": "1000000000",
79 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
80 "TransactionType": "Payment"
81 }
82})",
83 {{"", "", "Missing field 'tx_json.Sequence'.", "Missing field 'tx_json.Sequence'."}}},
84
85 {"Pass in Sequence, no Amount only DeliverMax",
86 __LINE__,
87 R"({
88 "command": "dummy_command",
89 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
90 "secret": "masterpassphrase",
91 "tx_json": {
92 "Sequence": 0,
93 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
94 "DeliverMax": "1000000000",
95 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
96 "TransactionType": "Payment"
97 }
98})",
99 {{"", "", "Missing field 'tx_json.Fee'.", "Missing field 'tx_json.SigningPubKey'."}}},
100
101 {"Pass in Sequence and Fee with minimal payment, both Amount and "
102 "DeliverMax.",
103 __LINE__,
104 R"({
105 "command": "dummy_command",
106 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
107 "secret": "masterpassphrase",
108 "tx_json": {
109 "Sequence": 0,
110 "Fee": 10,
111 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
112 "Amount": "1000000000",
113 "DeliverMax": "1000000000",
114 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
115 "TransactionType": "Payment"
116 }
117})",
118 {{"",
119 "",
120 "A Signer may not be the transaction's Account "
121 "(rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh).",
122 "Missing field 'tx_json.SigningPubKey'."}}},
123
124 {"Add 'fee_mult_max' field.",
125 __LINE__,
126 R"({
127 "command": "dummy_command",
128 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
129 "secret": "masterpassphrase",
130 "fee_mult_max": 7,
131 "tx_json": {
132 "Sequence": 0,
133 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
134 "Amount": "1000000000",
135 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
136 "TransactionType": "Payment"
137 }
138})",
139 {{"", "", "Missing field 'tx_json.Fee'.", "Missing field 'tx_json.SigningPubKey'."}}},
140
141 {"Add 'fee_mult_max' and 'fee_div_max' field.",
142 __LINE__,
143 R"({
144 "command": "dummy_command",
145 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
146 "secret": "masterpassphrase",
147 "fee_mult_max": 7,
148 "fee_div_max": 4,
149 "tx_json": {
150 "Sequence": 0,
151 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
152 "Amount": "1000000000",
153 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
154 "TransactionType": "Payment"
155 }
156})",
157 {{"", "", "Missing field 'tx_json.Fee'.", "Missing field 'tx_json.SigningPubKey'."}}},
158
159 {"fee_mult_max is ignored if 'Fee' is present.",
160 __LINE__,
161 R"({
162 "command": "dummy_command",
163 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
164 "secret": "masterpassphrase",
165 "fee_mult_max": 0,
166 "tx_json": {
167 "Sequence": 0,
168 "Fee": 10,
169 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
170 "Amount": "1000000000",
171 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
172 "TransactionType": "Payment"
173 }
174})",
175 {{"",
176 "",
177 "A Signer may not be the transaction's Account "
178 "(rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh).",
179 "Missing field 'tx_json.SigningPubKey'."}}},
180
181 {"fee_div_max is ignored if 'Fee' is present.",
182 __LINE__,
183 R"({
184 "command": "dummy_command",
185 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
186 "secret": "masterpassphrase",
187 "fee_mult_max": 100,
188 "fee_div_max": 1000,
189 "tx_json": {
190 "Sequence": 0,
191 "Fee": 10,
192 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
193 "Amount": "1000000000",
194 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
195 "TransactionType": "Payment"
196 }
197})",
198 {{"",
199 "",
200 "A Signer may not be the transaction's Account "
201 "(rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh).",
202 "Missing field 'tx_json.SigningPubKey'."}}},
203
204 {"Invalid 'fee_mult_max' field.",
205 __LINE__,
206 R"({
207 "command": "dummy_command",
208 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
209 "secret": "masterpassphrase",
210 "fee_mult_max": "NotAFeeMultiplier",
211 "tx_json": {
212 "Sequence": 0,
213 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
214 "Amount": "1000000000",
215 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
216 "TransactionType": "Payment"
217 }
218})",
219 {{"Invalid field 'fee_mult_max', not a positive integer.",
220 "Invalid field 'fee_mult_max', not a positive integer.",
221 "Missing field 'tx_json.Fee'.",
222 "Missing field 'tx_json.SigningPubKey'."}}},
223
224 {"Invalid 'fee_div_max' field.",
225 __LINE__,
226 R"({
227 "command": "dummy_command",
228 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
229 "secret": "masterpassphrase",
230 "fee_mult_max": 5,
231 "fee_div_max": "NotAFeeMultiplier",
232 "tx_json": {
233 "Sequence": 0,
234 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
235 "Amount": "1000000000",
236 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
237 "TransactionType": "Payment"
238 }
239})",
240 {{"Invalid field 'fee_div_max', not a positive integer.",
241 "Invalid field 'fee_div_max', not a positive integer.",
242 "Missing field 'tx_json.Fee'.",
243 "Missing field 'tx_json.SigningPubKey'."}}},
244
245 {"Invalid value for 'fee_mult_max' field.",
246 __LINE__,
247 R"({
248 "command": "dummy_command",
249 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
250 "secret": "masterpassphrase",
251 "fee_mult_max": 0,
252 "tx_json": {
253 "Sequence": 0,
254 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
255 "Amount": "1000000000",
256 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
257 "TransactionType": "Payment"
258 }
259})",
260 {{"Fee of 10 exceeds the requested tx limit of 0",
261 "Fee of 10 exceeds the requested tx limit of 0",
262 "Missing field 'tx_json.Fee'.",
263 "Missing field 'tx_json.SigningPubKey'."}}},
264
265 {"Invalid value for 'fee_div_max' field.",
266 __LINE__,
267 R"({
268 "command": "dummy_command",
269 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
270 "secret": "masterpassphrase",
271 "fee_mult_max": 4,
272 "fee_div_max": 7,
273 "tx_json": {
274 "Sequence": 0,
275 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
276 "Amount": "1000000000",
277 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
278 "TransactionType": "Payment"
279 }
280})",
281 {{"Fee of 10 exceeds the requested tx limit of 5",
282 "Fee of 10 exceeds the requested tx limit of 5",
283 "Missing field 'tx_json.Fee'.",
284 "Missing field 'tx_json.SigningPubKey'."}}},
285
286 {"Invalid zero value for 'fee_div_max' field.",
287 __LINE__,
288 R"({
289 "command": "dummy_command",
290 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
291 "secret": "masterpassphrase",
292 "fee_mult_max": 4,
293 "fee_div_max": 0,
294 "tx_json": {
295 "Sequence": 0,
296 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
297 "Amount": "1000000000",
298 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
299 "TransactionType": "Payment"
300 }
301})",
302 {{"Invalid field 'fee_div_max', not a positive integer.",
303 "Invalid field 'fee_div_max', not a positive integer.",
304 "Missing field 'tx_json.Fee'.",
305 "Missing field 'tx_json.SigningPubKey'."}}},
306
307 {"Missing 'Amount'.",
308 __LINE__,
309 R"({
310 "command": "dummy_command",
311 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
312 "secret": "masterpassphrase",
313 "tx_json": {
314 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
315 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
316 "TransactionType": "Payment"
317 }
318})",
319 {{"Missing field 'tx_json.Amount'.",
320 "Missing field 'tx_json.Amount'.",
321 "Missing field 'tx_json.Sequence'.",
322 "Missing field 'tx_json.Sequence'."}}},
323
324 {"Invalid 'Amount'.",
325 __LINE__,
326 R"({
327 "command": "dummy_command",
328 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
329 "secret": "masterpassphrase",
330 "tx_json": {
331 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
332 "Amount": "NotAnAmount",
333 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
334 "TransactionType": "Payment"
335 }
336})",
337 {{"Invalid field 'tx_json.Amount'.",
338 "Invalid field 'tx_json.Amount'.",
339 "Missing field 'tx_json.Sequence'.",
340 "Missing field 'tx_json.Sequence'."}}},
341
342 {"Missing 'Destination'.",
343 __LINE__,
344 R"({
345 "command": "dummy_command",
346 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
347 "secret": "masterpassphrase",
348 "tx_json": {
349 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
350 "Amount": "1000000000",
351 "TransactionType": "Payment"
352 }
353})",
354 {{"Missing field 'tx_json.Destination'.",
355 "Missing field 'tx_json.Destination'.",
356 "Missing field 'tx_json.Sequence'.",
357 "Missing field 'tx_json.Sequence'."}}},
358
359 {"Invalid 'Destination'.",
360 __LINE__,
361 R"({
362 "command": "dummy_command",
363 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
364 "secret": "masterpassphrase",
365 "tx_json": {
366 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
367 "Amount": "1000000000",
368 "Destination": "NotADestination",
369 "TransactionType": "Payment"
370 }
371})",
372 {{"Invalid field 'tx_json.Destination'.",
373 "Invalid field 'tx_json.Destination'.",
374 "Missing field 'tx_json.Sequence'.",
375 "Missing field 'tx_json.Sequence'."}}},
376
377 {"Cannot create XRP to XRP paths.",
378 __LINE__,
379 R"({
380 "command": "dummy_command",
381 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
382 "secret": "masterpassphrase",
383 "build_path": 1,
384 "tx_json": {
385 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
386 "Amount": "1000000000",
387 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
388 "TransactionType": "Payment"
389 }
390})",
391 {{"Cannot build XRP to XRP paths.",
392 "Cannot build XRP to XRP paths.",
393 "Missing field 'tx_json.Sequence'.",
394 "Missing field 'tx_json.Sequence'."}}},
395
396 {"Successful 'build_path'.",
397 __LINE__,
398 R"({
399 "command": "dummy_command",
400 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
401 "secret": "masterpassphrase",
402 "build_path": 1,
403 "tx_json": {
404 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
405 "Amount": {
406 "value": "10",
407 "currency": "USD",
408 "issuer": "rLPwWB1itaUGMV8kbMLLysjGkEpTM2Soy4"
409 },
410 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
411 "TransactionType": "Payment"
412 }
413})",
414 {{"", "", "Missing field 'tx_json.Sequence'.", "Missing field 'tx_json.Sequence'."}}},
415
416 {"Not valid to include both 'Paths' and 'build_path'.",
417 __LINE__,
418 R"({
419 "command": "dummy_command",
420 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
421 "secret": "masterpassphrase",
422 "build_path": 1,
423 "tx_json": {
424 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
425 "Amount": {
426 "value": "10",
427 "currency": "USD",
428 "issuer": "rLPwWB1itaUGMV8kbMLLysjGkEpTM2Soy4"
429 },
430 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
431 "Paths": "",
432 "TransactionType": "Payment"
433 }
434})",
435 {{"Cannot specify both 'tx_json.Paths' and 'build_path'",
436 "Cannot specify both 'tx_json.Paths' and 'build_path'",
437 "Missing field 'tx_json.Sequence'.",
438 "Missing field 'tx_json.Sequence'."}}},
439
440 {"Successful 'SendMax'.",
441 __LINE__,
442 R"({
443 "command": "dummy_command",
444 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
445 "secret": "masterpassphrase",
446 "build_path": 1,
447 "tx_json": {
448 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
449 "Amount": {
450 "value": "10",
451 "currency": "USD",
452 "issuer": "rLPwWB1itaUGMV8kbMLLysjGkEpTM2Soy4"
453 },
454 "SendMax": {
455 "value": "5",
456 "currency": "USD",
457 "issuer": "rLPwWB1itaUGMV8kbMLLysjGkEpTM2Soy4"
458 },
459 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
460 "TransactionType": "Payment"
461 }
462})",
463 {{"", "", "Missing field 'tx_json.Sequence'.", "Missing field 'tx_json.Sequence'."}}},
464
465 {"'Amount' may not be XRP for pathfinding, but 'SendMax' may be XRP.",
466 __LINE__,
467 R"({
468 "command": "dummy_command",
469 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
470 "secret": "masterpassphrase",
471 "build_path": 1,
472 "tx_json": {
473 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
474 "Amount": {
475 "value": "10",
476 "currency": "USD",
477 "issuer": "rLPwWB1itaUGMV8kbMLLysjGkEpTM2Soy4"
478 },
479 "SendMax": 10000,
480 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
481 "TransactionType": "Payment"
482 }
483})",
484 {{"", "", "Missing field 'tx_json.Sequence'.", "Missing field 'tx_json.Sequence'."}}},
485
486 {"'secret' must be present.",
487 __LINE__,
488 R"({
489 "command": "dummy_command",
490 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
491 "tx_json": {
492 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
493 "Amount": "1000000000",
494 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
495 "TransactionType": "Payment"
496 }
497})",
498 {{"Missing field 'secret'.",
499 "Missing field 'secret'.",
500 "Missing field 'tx_json.Sequence'.",
501 "Missing field 'tx_json.Sequence'."}}},
502
503 {"'secret' must be non-empty.",
504 __LINE__,
505 R"({
506 "command": "dummy_command",
507 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
508 "secret": "",
509 "tx_json": {
510 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
511 "Amount": "1000000000",
512 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
513 "TransactionType": "Payment"
514 }
515})",
516 {{"Invalid field 'secret'.",
517 "Invalid field 'secret'.",
518 "Missing field 'tx_json.Sequence'.",
519 "Missing field 'tx_json.Sequence'."}}},
520
521 {"Use 'seed' instead of 'secret'.",
522 __LINE__,
523 R"({
524 "command": "dummy_command",
525 "account": "rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi",
526 "key_type": "ed25519",
527 "seed": "sh1yJfwoi98zCygwijUzuHmJDeVKd",
528 "tx_json": {
529 "Account": "rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi",
530 "Amount": "1000000000",
531 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
532 "TransactionType": "Payment"
533 }
534})",
535 {{"", "", "Missing field 'tx_json.Sequence'.", "Missing field 'tx_json.Sequence'."}}},
536
537 {"Malformed 'seed'.",
538 __LINE__,
539 R"({
540 "command": "dummy_command",
541 "account": "rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi",
542 "key_type": "ed25519",
543 "seed": "not a seed",
544 "tx_json": {
545 "Account": "rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi",
546 "Amount": "1000000000",
547 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
548 "TransactionType": "Payment"
549 }
550})",
551 {{"Disallowed seed.",
552 "Disallowed seed.",
553 "Missing field 'tx_json.Sequence'.",
554 "Missing field 'tx_json.Sequence'."}}},
555
556 {"'tx_json' must be present.",
557 __LINE__,
558 R"({
559 "command": "dummy_command",
560 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
561 "secret": "masterpassphrase",
562 "rx_json": {
563 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
564 "Amount": "1000000000",
565 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
566 "TransactionType": "Payment"
567 }
568})",
569 {{"Missing field 'tx_json'.",
570 "Missing field 'tx_json'.",
571 "Missing field 'tx_json'.",
572 "Missing field 'tx_json'."}}},
573
574 {"'TransactionType' must be present.",
575 __LINE__,
576 R"({
577 "command": "dummy_command",
578 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
579 "secret": "masterpassphrase",
580 "tx_json": {
581 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
582 "Amount": "1000000000",
583 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
584 }
585})",
586 {{"Missing field 'tx_json.TransactionType'.",
587 "Missing field 'tx_json.TransactionType'.",
588 "Missing field 'tx_json.Sequence'.",
589 "Missing field 'tx_json.Sequence'."}}},
590
591 {"The 'TransactionType' must be a pre-established transaction type.",
592 __LINE__,
593 R"({
594 "command": "dummy_command",
595 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
596 "secret": "masterpassphrase",
597 "tx_json": {
598 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
599 "Amount": "1000000000",
600 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
601 "TransactionType": "tt"
602 }
603})",
604 {{"Field 'tx_json.TransactionType' has invalid data.",
605 "Field 'tx_json.TransactionType' has invalid data.",
606 "Missing field 'tx_json.Sequence'.",
607 "Missing field 'tx_json.Sequence'."}}},
608
609 {"The 'TransactionType' may be represented with an integer.",
610 __LINE__,
611 R"({
612 "command": "dummy_command",
613 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
614 "secret": "masterpassphrase",
615 "tx_json": {
616 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
617 "Amount": "1000000000",
618 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
619 "TransactionType": 0
620 }
621})",
622 {{"", "", "Missing field 'tx_json.Sequence'.", "Missing field 'tx_json.Sequence'."}}},
623
624 {"'Account' must be present.",
625 __LINE__,
626 R"({
627 "command": "dummy_command",
628 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
629 "secret": "masterpassphrase",
630 "tx_json": {
631 "Amount": "1000000000",
632 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
633 "TransactionType": "Payment"
634 }
635})",
636 {{"Missing field 'tx_json.Account'.",
637 "Missing field 'tx_json.Account'.",
638 "Missing field 'tx_json.Sequence'.",
639 "Missing field 'tx_json.Sequence'."}}},
640
641 {"'Account' must be well formed.",
642 __LINE__,
643 R"({
644 "command": "dummy_command",
645 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
646 "secret": "masterpassphrase",
647 "tx_json": {
648 "Account": "NotAnAccount",
649 "Amount": "1000000000",
650 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
651 "TransactionType": "Payment"
652 }
653})",
654 {{"Invalid field 'tx_json.Account'.",
655 "Invalid field 'tx_json.Account'.",
656 "Missing field 'tx_json.Sequence'.",
657 "Missing field 'tx_json.Sequence'."}}},
658
659 {"The 'offline' tag may be added to the transaction.",
660 __LINE__,
661 R"({
662 "command": "dummy_command",
663 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
664 "secret": "masterpassphrase",
665 "offline": 0,
666 "tx_json": {
667 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
668 "Amount": "1000000000",
669 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
670 "TransactionType": "Payment"
671 }
672})",
673 {{"", "", "Missing field 'tx_json.Sequence'.", "Missing field 'tx_json.Sequence'."}}},
674
675 {"If 'offline' is true then a 'Sequence' field must be supplied.",
676 __LINE__,
677 R"({
678 "command": "dummy_command",
679 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
680 "secret": "masterpassphrase",
681 "offline": 1,
682 "tx_json": {
683 "Fee": 10,
684 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
685 "Amount": "1000000000",
686 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
687 "TransactionType": "Payment"
688 }
689})",
690 {{"Missing field 'tx_json.Sequence'.",
691 "Missing field 'tx_json.Sequence'.",
692 "Missing field 'tx_json.Sequence'.",
693 "Missing field 'tx_json.Sequence'."}}},
694
695 {"If 'offline' is true then a 'Fee' field must be supplied.",
696 __LINE__,
697 R"({
698 "command": "dummy_command",
699 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
700 "secret": "masterpassphrase",
701 "offline": 1,
702 "tx_json": {
703 "Sequence": 0,
704 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
705 "Amount": "1000000000",
706 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
707 "TransactionType": "Payment"
708 }
709})",
710 {{"Missing field 'tx_json.Fee'.",
711 "Missing field 'tx_json.Fee'.",
712 "Missing field 'tx_json.Fee'.",
713 "Missing field 'tx_json.SigningPubKey'."}}},
714
715 {"Valid transaction if 'offline' is true.",
716 __LINE__,
717 R"({
718 "command": "dummy_command",
719 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
720 "secret": "masterpassphrase",
721 "offline": 1,
722 "tx_json": {
723 "Sequence": 0,
724 "Fee": 10,
725 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
726 "Amount": "1000000000",
727 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
728 "TransactionType": "Payment"
729 }
730})",
731 {{"",
732 "",
733 "A Signer may not be the transaction's Account "
734 "(rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh).",
735 "Missing field 'tx_json.SigningPubKey'."}}},
736
737 {"'offline' and 'build_path' are mutually exclusive.",
738 __LINE__,
739 R"({
740 "command": "dummy_command",
741 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
742 "secret": "masterpassphrase",
743 "offline": 1,
744 "build_path": 1,
745 "tx_json": {
746 "Sequence": 0,
747 "Fee": 10,
748 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
749 "Amount": "1000000000",
750 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
751 "TransactionType": "Payment"
752 }
753})",
754 {{"Field 'build_path' not allowed in this context.",
755 "Field 'build_path' not allowed in this context.",
756 "Field 'build_path' not allowed in this context.",
757 "Missing field 'tx_json.SigningPubKey'."}}},
758
759 {"A 'Flags' field may be specified.",
760 __LINE__,
761 R"({
762 "command": "dummy_command",
763 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
764 "secret": "masterpassphrase",
765 "tx_json": {
766 "Flags": 0,
767 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
768 "Amount": "1000000000",
769 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
770 "TransactionType": "Payment"
771 }
772})",
773 {{"", "", "Missing field 'tx_json.Sequence'.", "Missing field 'tx_json.Sequence'."}}},
774
775 {"The 'Flags' field must be numeric.",
776 __LINE__,
777 R"({
778 "command": "dummy_command",
779 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
780 "secret": "masterpassphrase",
781 "tx_json": {
782 "Flags": "NotGoodFlags",
783 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
784 "Amount": "1000000000",
785 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
786 "TransactionType": "Payment"
787 }
788})",
789 {{"Field 'tx_json.Flags' has invalid data.",
790 "Field 'tx_json.Flags' has invalid data.",
791 "Missing field 'tx_json.Sequence'.",
792 "Missing field 'tx_json.Sequence'."}}},
793
794 {"It's okay to add a 'debug_signing' field.",
795 __LINE__,
796 R"({
797 "command": "dummy_command",
798 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
799 "secret": "masterpassphrase",
800 "debug_signing": 0,
801 "tx_json": {
802 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
803 "Amount": "1000000000",
804 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
805 "TransactionType": "Payment"
806 }
807})",
808 {{"", "", "Missing field 'tx_json.Sequence'.", "Missing field 'tx_json.Sequence'."}}},
809
810 {"Single-sign a multisigned transaction.",
811 __LINE__,
812 R"({
813 "command": "dummy_command",
814 "account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
815 "secret": "a",
816 "tx_json": {
817 "Account" : "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
818 "Amount" : "1000000000",
819 "Destination" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
820 "Fee" : "50",
821 "Sequence" : 0,
822 "Signers" : [
823 {
824 "Signer" : {
825 "Account" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
826 "SigningPubKey" : "0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020",
827 "TxnSignature" : "304502210080EB23E78A841DDC5E3A4F10DE6EAF052207D6B519BF8954467ADB221B3F349002202CA458E8D4E4DE7176D27A91628545E7B295A5DFC8ADF0B5CD3E279B6FA02998"
828 }
829 }
830 ],
831 "SigningPubKey" : "",
832 "TransactionType" : "Payment"
833 }
834})",
835 {{"Already multisigned.", "Already multisigned.", "Secret does not match account.", ""}}},
836
837 {"Minimal sign_for.",
838 __LINE__,
839 R"({
840 "command": "dummy_command",
841 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
842 "secret": "masterpassphrase",
843 "tx_json": {
844 "Account": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
845 "Amount": "1000000000",
846 "Destination": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
847 "Fee": 50,
848 "Sequence": 0,
849 "SigningPubKey": "",
850 "TransactionType": "Payment"
851 }
852})",
853 {{"Secret does not match account.",
854 "Secret does not match account.",
855 "",
856 "Missing field 'tx_json.Signers'."}}},
857
858 {"Minimal offline sign_for.",
859 __LINE__,
860 R"({
861 "command": "dummy_command",
862 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
863 "secret": "masterpassphrase",
864 "offline": 1,
865 "tx_json": {
866 "Account": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
867 "Amount": "1000000000",
868 "Destination": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
869 "Fee": 50,
870 "Sequence": 0,
871 "SigningPubKey": "",
872 "TransactionType": "Payment"
873 }
874})",
875 {{"", "", "", "Missing field 'tx_json.Signers'."}}},
876
877 {"Offline sign_for using 'seed' instead of 'secret'.",
878 __LINE__,
879 R"({
880 "command": "dummy_command",
881 "account": "rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi",
882 "key_type": "ed25519",
883 "seed": "sh1yJfwoi98zCygwijUzuHmJDeVKd",
884 "offline": 1,
885 "tx_json": {
886 "Account": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
887 "Amount": "1000000000",
888 "Destination": "rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi",
889 "Fee": 50,
890 "Sequence": 0,
891 "SigningPubKey": "",
892 "TransactionType": "Payment"
893 }
894})",
895 {{"", "", "", "Missing field 'tx_json.Signers'."}}},
896
897 {"Malformed seed in sign_for.",
898 __LINE__,
899 R"({
900 "command": "dummy_command",
901 "account": "rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi",
902 "key_type": "ed25519",
903 "seed": "sh1yJfwoi98zCygwjUzuHmJDeVKd",
904 "offline": 1,
905 "tx_json": {
906 "Account": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
907 "Amount": "1000000000",
908 "Destination": "rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi",
909 "Fee": 50,
910 "Sequence": 0,
911 "SigningPubKey": "",
912 "TransactionType": "Payment"
913 }
914})",
915 {{"Disallowed seed.",
916 "Disallowed seed.",
917 "Disallowed seed.",
918 "Missing field 'tx_json.Signers'."}}},
919
920 {"Missing 'Account' in sign_for.",
921 __LINE__,
922 R"({
923 "command": "dummy_command",
924 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
925 "secret": "masterpassphrase",
926 "tx_json": {
927 "Amount": "1000000000",
928 "Destination": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
929 "Fee": 50,
930 "Sequence": 0,
931 "SigningPubKey": "",
932 "TransactionType": "Payment"
933 }
934})",
935 {{"Missing field 'tx_json.Account'.",
936 "Missing field 'tx_json.Account'.",
937 "Missing field 'tx_json.Account'.",
938 "Missing field 'tx_json.Account'."}}},
939
940 {"Missing 'Amount' in sign_for.",
941 __LINE__,
942 R"({
943 "command": "dummy_command",
944 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
945 "secret": "masterpassphrase",
946 "tx_json": {
947 "Account": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
948 "Destination": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
949 "Fee": 50,
950 "Sequence": 0,
951 "SigningPubKey": "",
952 "TransactionType": "Payment"
953 }
954})",
955 {{"Missing field 'tx_json.Amount'.",
956 "Missing field 'tx_json.Amount'.",
957 "Missing field 'tx_json.Amount'.",
958 "Missing field 'tx_json.Amount'."}}},
959
960 {"Missing 'Destination' in sign_for.",
961 __LINE__,
962 R"({
963 "command": "dummy_command",
964 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
965 "secret": "masterpassphrase",
966 "tx_json": {
967 "Account": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
968 "Amount": "1000000000",
969 "Fee": 50,
970 "Sequence": 0,
971 "SigningPubKey": "",
972 "TransactionType": "Payment"
973 }
974})",
975 {{"Missing field 'tx_json.Destination'.",
976 "Missing field 'tx_json.Destination'.",
977 "Missing field 'tx_json.Destination'.",
978 "Missing field 'tx_json.Destination'."}}},
979
980 {"Missing 'Destination' in sign_for, use DeliverMax",
981 __LINE__,
982 R"({
983 "command": "dummy_command",
984 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
985 "secret": "masterpassphrase",
986 "tx_json": {
987 "Account": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
988 "DeliverMax": "1000000000",
989 "Fee": 50,
990 "Sequence": 0,
991 "SigningPubKey": "",
992 "TransactionType": "Payment"
993 }
994})",
995 {{"Missing field 'tx_json.Destination'.",
996 "Missing field 'tx_json.Destination'.",
997 "Missing field 'tx_json.Destination'.",
998 "Missing field 'tx_json.Destination'."}}},
999
1000 {"Missing 'Fee' in sign_for.",
1001 __LINE__,
1002 R"({
1003 "command": "dummy_command",
1004 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1005 "secret": "masterpassphrase",
1006 "tx_json": {
1007 "Account": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1008 "Amount": "1000000000",
1009 "Destination": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1010 "Sequence": 0,
1011 "SigningPubKey": "",
1012 "TransactionType": "Payment"
1013 }
1014})",
1015 {{"Secret does not match account.",
1016 "Secret does not match account.",
1017 "Missing field 'tx_json.Fee'.",
1018 "Missing field 'tx_json.Fee'."}}},
1019
1020 {"Missing 'Sequence' in sign_for.",
1021 __LINE__,
1022 R"({
1023 "command": "dummy_command",
1024 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1025 "secret": "masterpassphrase",
1026 "tx_json": {
1027 "Account": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1028 "Amount": "1000000000",
1029 "Destination": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1030 "Fee": 50,
1031 "SigningPubKey": "",
1032 "TransactionType": "Payment"
1033 }
1034})",
1035 {{"Secret does not match account.",
1036 "Secret does not match account.",
1037 "Missing field 'tx_json.Sequence'.",
1038 "Missing field 'tx_json.Sequence'."}}},
1039
1040 {"Missing 'SigningPubKey' in sign_for is automatically filled in.",
1041 __LINE__,
1042 R"({
1043 "command": "dummy_command",
1044 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1045 "secret": "masterpassphrase",
1046 "tx_json": {
1047 "Account": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1048 "Amount": "1000000000",
1049 "Destination": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1050 "Fee": 50,
1051 "Sequence": 0,
1052 "TransactionType": "Payment"
1053 }
1054})",
1055 {{"Secret does not match account.",
1056 "Secret does not match account.",
1057 "",
1058 "Missing field 'tx_json.SigningPubKey'."}}},
1059
1060 {"In sign_for, an account may not sign for itself.",
1061 __LINE__,
1062 R"({
1063 "command": "dummy_command",
1064 "account": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1065 "secret": "a",
1066 "tx_json": {
1067 "Account": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1068 "Amount": "1000000000",
1069 "Destination": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1070 "Fee": 50,
1071 "Sequence": 0,
1072 "TransactionType": "Payment"
1073 }
1074})",
1075 {{"",
1076 "",
1077 "A Signer may not be the transaction's Account "
1078 "(rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA).",
1079 "Missing field 'tx_json.SigningPubKey'."}}},
1080
1081 {"Cannot put duplicate accounts in Signers array",
1082 __LINE__,
1083 R"({
1084 "command": "dummy_command",
1085 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1086 "secret": "masterpassphrase",
1087 "tx_json": {
1088 "Account" : "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1089 "Amount" : "1000000000",
1090 "Destination" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1091 "Fee" : "50",
1092 "Sequence" : 0,
1093 "Signers" : [
1094 {
1095 "Signer" : {
1096 "Account" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1097 "SigningPubKey" : "0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020",
1098 "TxnSignature" : "304502210080EB23E78A841DDC5E3A4F10DE6EAF052207D6B519BF8954467ADB221B3F349002202CA458E8D4E4DE7176D27A91628545E7B295A5DFC8ADF0B5CD3E279B6FA02998"
1099 }
1100 }
1101 ],
1102 "SigningPubKey" : "",
1103 "TransactionType" : "Payment"
1104 }
1105})",
1106 {{"Already multisigned.",
1107 "Already multisigned.",
1108 "Duplicate Signers:Signer:Account entries "
1109 "(rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh) are not allowed.",
1110 ""}}},
1111
1112 {"Correctly append to pre-established Signers array",
1113 __LINE__,
1114 R"({
1115 "command": "dummy_command",
1116 "account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1117 "secret": "c",
1118 "tx_json": {
1119 "Account" : "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1120 "Amount" : "1000000000",
1121 "Destination" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1122 "Fee" : "50",
1123 "Sequence" : 0,
1124 "Signers" : [
1125 {
1126 "Signer" : {
1127 "Account" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1128 "SigningPubKey" : "0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020",
1129 "TxnSignature" : "304502210080EB23E78A841DDC5E3A4F10DE6EAF052207D6B519BF8954467ADB221B3F349002202CA458E8D4E4DE7176D27A91628545E7B295A5DFC8ADF0B5CD3E279B6FA02998"
1130 }
1131 }
1132 ],
1133 "SigningPubKey" : "",
1134 "TransactionType" : "Payment"
1135 }
1136})",
1137 {{"Already multisigned.", "Already multisigned.", "", ""}}},
1138
1139 {"Append to pre-established Signers array with bad signature",
1140 __LINE__,
1141 R"({
1142 "command": "dummy_command",
1143 "account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1144 "secret": "c",
1145 "tx_json": {
1146 "Account" : "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1147 "Amount" : "1000000000",
1148 "Destination" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1149 "Fee" : "50",
1150 "Sequence" : 0,
1151 "Signers" : [
1152 {
1153 "Signer" : {
1154 "Account" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1155 "SigningPubKey" : "0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020",
1156 "TxnSignature" : "304502210080EB23E78A841DDC5E3A4F10DE6EAF052207D6B519BF8954467ACB221B3F349002202CA458E8D4E4DE7176D27A91628545E7B295A5DFC8ADF0B5CD3E279B6FA02998"
1157 }
1158 }
1159 ],
1160 "SigningPubKey" : "",
1161 "TransactionType" : "Payment"
1162 }
1163})",
1164 {{"Already multisigned.",
1165 "Already multisigned.",
1166 "Invalid signature.",
1167 "Invalid signature."}}},
1168
1169 {"Non-empty 'SigningPubKey' in sign_for.",
1170 __LINE__,
1171 R"({
1172 "command": "dummy_command",
1173 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1174 "secret": "masterpassphrase",
1175 "tx_json": {
1176 "Account": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1177 "Amount": "1000000000",
1178 "Destination": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1179 "Fee": 50,
1180 "Sequence": 0,
1181 "SigningPubKey": "1",
1182 "TransactionType": "Payment"
1183 }
1184})",
1185 {{"Secret does not match account.",
1186 "Secret does not match account.",
1187 "When multi-signing 'tx_json.SigningPubKey' must be empty.",
1188 "When multi-signing 'tx_json.SigningPubKey' must be empty."}}},
1189
1190 {"Missing 'TransactionType' in sign_for.",
1191 __LINE__,
1192 R"({
1193 "command": "dummy_command",
1194 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1195 "secret": "masterpassphrase",
1196 "tx_json": {
1197 "Account": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1198 "Amount": "1000000000",
1199 "Destination": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1200 "Fee": 50,
1201 "Sequence": 0,
1202 "SigningPubKey": "",
1203 }
1204})",
1205 {{"Missing field 'tx_json.TransactionType'.",
1206 "Missing field 'tx_json.TransactionType'.",
1207 "Missing field 'tx_json.TransactionType'.",
1208 "Missing field 'tx_json.TransactionType'."}}},
1209
1210 {"TxnSignature in sign_for.",
1211 __LINE__,
1212 R"({
1213 "command": "dummy_command",
1214 "account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1215 "secret": "c",
1216 "tx_json": {
1217 "Account" : "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1218 "Amount" : "1000000000",
1219 "Destination" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1220 "Fee" : "50",
1221 "Sequence" : 0,
1222 "Signers" : [
1223 {
1224 "Signer" : {
1225 "Account" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1226 "SigningPubKey" : "0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020",
1227 "TxnSignature" : "304502210080EB23E78A841DDC5E3A4F10DE6EAF052207D6B519BF8954467ADB221B3F349002202CA458E8D4E4DE7176D27A91628545E7B295A5DFC8ADF0B5CD3E279B6FA02998"
1228 }
1229 }
1230 ],
1231 "SigningPubKey" : "",
1232 "TxnSignature" : "304502210080EB23E78A841DDC5E3A4F10DE6EAF052207D6B519BF8954467ADB221B3F349002202CA458E8D4E4DE7176D27A91628545E7B295A5DFC8ADF0B5CD3E279B6FA02998",
1233 "TransactionType" : "Payment"
1234 }
1235})",
1236 {{"Already multisigned.",
1237 "Already multisigned.",
1238 "Already single-signed.",
1239 "Signing of transaction is malformed."}}},
1240
1241 {"Invalid field 'tx_json': string instead of object",
1242 __LINE__,
1243 R"({
1244 "command": "dummy_command",
1245 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1246 "secret": "masterpassphrase",
1247 "tx_json": ""
1248})",
1249 {{"Invalid field 'tx_json', not object.",
1250 "Invalid field 'tx_json', not object.",
1251 "Invalid field 'tx_json', not object.",
1252 "Invalid field 'tx_json', not object."}}},
1253
1254 {"Invalid field 'tx_json': integer instead of object",
1255 __LINE__,
1256 R"({
1257 "command": "dummy_command",
1258 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1259 "secret": "masterpassphrase",
1260 "tx_json": 20160331
1261})",
1262 {{"Invalid field 'tx_json', not object.",
1263 "Invalid field 'tx_json', not object.",
1264 "Invalid field 'tx_json', not object.",
1265 "Invalid field 'tx_json', not object."}}},
1266
1267 {"Invalid field 'tx_json': array instead of object",
1268 __LINE__,
1269 R"({
1270 "command": "dummy_command",
1271 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1272 "secret": "masterpassphrase",
1273 "tx_json": [ "hello", "world" ]
1274})",
1275 {{"Invalid field 'tx_json', not object.",
1276 "Invalid field 'tx_json', not object.",
1277 "Invalid field 'tx_json', not object.",
1278 "Invalid field 'tx_json', not object."}}},
1279
1280 {"Pass in Fee with minimal payment, both Amount and DeliverMax.",
1281 __LINE__,
1282 R"({
1283 "command": "dummy_command",
1284 "account": "r9zN9x52FiCFAcicCLMQKbj1nxYhxJbbSy",
1285 "secret": "ssgN6zTvtM1q9XV8DvJpWm8LBYWiY",
1286 "tx_json": {
1287 "Fee": 10,
1288 "Account": "r9zN9x52FiCFAcicCLMQKbj1nxYhxJbbSy",
1289 "Amount": "1000000000",
1290 "DeliverMax": "1000000000",
1291 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1292 "TransactionType": "Payment"
1293 }
1294})",
1295 {{"Source account not found.",
1296 "Source account not found.",
1297 "Missing field 'tx_json.Sequence'.",
1298 "Missing field 'tx_json.Sequence'."}}},
1299
1300 {"Minimal submit_multisigned.",
1301 __LINE__,
1302 R"({
1303 "command": "submit_multisigned",
1304 "tx_json": {
1305 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1306 "Amount": "1000000000",
1307 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1308 "Fee": 50,
1309 "Sequence": 0,
1310 "Signers" : [
1311 {
1312 "Signer" : {
1313 "Account" : "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1314 "SigningPubKey" : "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8",
1315 "TxnSignature" : "3045022100909D01399AFFAD1E30D250CE61F93975B7F61E47B5244D78C3E86D9806535D95022012E389E0ACB016334052B7FE07FA6CEFDC8BE82CB410FA841D5049641C89DC8F"
1316 }
1317 }
1318 ],
1319 "SigningPubKey": "",
1320 "TransactionType": "Payment"
1321 }
1322})",
1323 {{"Missing field 'secret'.", "Missing field 'secret'.", "Missing field 'account'.", ""}}},
1324
1325 {"Minimal submit_multisigned with bad signature.",
1326 __LINE__,
1327 R"({
1328 "command": "submit_multisigned",
1329 "tx_json": {
1330 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1331 "Amount": "1000000000",
1332 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1333 "Fee": 50,
1334 "Sequence": 0,
1335 "Signers": [
1336 {
1337 "Signer": {
1338 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1339 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1340 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1341 }
1342 }
1343 ],
1344 "SigningPubKey": "",
1345 "TransactionType": "Payment"
1346 }
1347})",
1348 {{"Missing field 'secret'.",
1349 "Missing field 'secret'.",
1350 "Missing field 'account'.",
1351 "Invalid signature."}}},
1352
1353 {"Missing tx_json in submit_multisigned.",
1354 __LINE__,
1355 R"({
1356 "command": "submit_multisigned",
1357 "Signers": [
1358 {
1359 "Signer": {
1360 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1361 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1362 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1363 }
1364 }
1365 ]
1366})",
1367 {{"Missing field 'secret'.",
1368 "Missing field 'secret'.",
1369 "Missing field 'account'.",
1370 "Missing field 'tx_json'."}}},
1371
1372 {"Missing sequence in submit_multisigned.",
1373 __LINE__,
1374 R"({
1375 "command": "submit_multisigned",
1376 "tx_json": {
1377 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1378 "Amount": "1000000000",
1379 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1380 "Fee": 50,
1381 "Signers": [
1382 {
1383 "Signer": {
1384 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1385 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1386 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1387 }
1388 }
1389 ],
1390 "SigningPubKey": "",
1391 "TransactionType": "Payment"
1392 }
1393})",
1394 {{"Missing field 'secret'.",
1395 "Missing field 'secret'.",
1396 "Missing field 'account'.",
1397 "Missing field 'tx_json.Sequence'."}}},
1398
1399 {"Missing SigningPubKey in submit_multisigned.",
1400 __LINE__,
1401 R"({
1402 "command": "submit_multisigned",
1403 "tx_json": {
1404 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1405 "Amount": "1000000000",
1406 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1407 "Fee": 50,
1408 "Signers": [
1409 {
1410 "Signer": {
1411 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1412 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1413 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1414 }
1415 }
1416 ],
1417 "Sequence": 0,
1418 "TransactionType": "Payment"
1419 }
1420})",
1421 {{"Missing field 'secret'.",
1422 "Missing field 'secret'.",
1423 "Missing field 'account'.",
1424 "Missing field 'tx_json.SigningPubKey'."}}},
1425
1426 {"Non-empty SigningPubKey in submit_multisigned.",
1427 __LINE__,
1428 R"({
1429 "command": "submit_multisigned",
1430 "tx_json": {
1431 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1432 "Amount": "1000000000",
1433 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1434 "Fee": 50,
1435 "Sequence": 0,
1436 "Signers": [
1437 {
1438 "Signer": {
1439 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1440 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1441 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1442 }
1443 }
1444 ],
1445 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8",
1446 "TransactionType": "Payment"
1447 }
1448})",
1449 {{"Missing field 'secret'.",
1450 "Missing field 'secret'.",
1451 "Missing field 'account'.",
1452 "When multi-signing 'tx_json.SigningPubKey' must be empty."}}},
1453
1454 {"Missing TransactionType in submit_multisigned.",
1455 __LINE__,
1456 R"({
1457 "command": "submit_multisigned",
1458 "tx_json": {
1459 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1460 "Amount": "1000000000",
1461 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1462 "Fee": 50,
1463 "Signers": [
1464 {
1465 "Signer": {
1466 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1467 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1468 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1469 }
1470 }
1471 ],
1472 "Sequence": 0,
1473 "SigningPubKey": "",
1474 }
1475})",
1476 {{"Missing field 'secret'.",
1477 "Missing field 'secret'.",
1478 "Missing field 'account'.",
1479 "Missing field 'tx_json.TransactionType'."}}},
1480
1481 {"Missing Account in submit_multisigned.",
1482 __LINE__,
1483 R"({
1484 "command": "submit_multisigned",
1485 "tx_json": {
1486 "Amount": "1000000000",
1487 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1488 "Fee": 50,
1489 "Sequence": 0,
1490 "Signers": [
1491 {
1492 "Signer": {
1493 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1494 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1495 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1496 }
1497 }
1498 ],
1499 "SigningPubKey": "",
1500 "TransactionType": "Payment"
1501 }
1502})",
1503 {{"Missing field 'secret'.",
1504 "Missing field 'secret'.",
1505 "Missing field 'account'.",
1506 "Missing field 'tx_json.Account'."}}},
1507
1508 {"Malformed Account in submit_multisigned.",
1509 __LINE__,
1510 R"({
1511 "command": "submit_multisigned",
1512 "tx_json": {
1513 "Account": "NotAnAccount",
1514 "Amount": "1000000000",
1515 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1516 "Fee": 50,
1517 "Sequence": 0,
1518 "Signers": [
1519 {
1520 "Signer": {
1521 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1522 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1523 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1524 }
1525 }
1526 ],
1527 "SigningPubKey": "",
1528 "TransactionType": "Payment"
1529 }
1530})",
1531 {{"Missing field 'secret'.",
1532 "Missing field 'secret'.",
1533 "Missing field 'account'.",
1534 "Invalid field 'tx_json.Account'."}}},
1535
1536 {"Account not in ledger in submit_multisigned.",
1537 __LINE__,
1538 R"({
1539 "command": "submit_multisigned",
1540 "tx_json": {
1541 "Account": "rDg53Haik2475DJx8bjMDSDPj4VX7htaMd",
1542 "Amount": "1000000000",
1543 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1544 "Fee": 50,
1545 "Sequence": 0,
1546 "Signers": [
1547 {
1548 "Signer": {
1549 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1550 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1551 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1552 }
1553 }
1554 ],
1555 "SigningPubKey": "",
1556 "TransactionType": "Payment"
1557 }
1558})",
1559 {{"Missing field 'secret'.",
1560 "Missing field 'secret'.",
1561 "Missing field 'account'.",
1562 "Source account not found."}}},
1563
1564 {"Missing Fee in submit_multisigned.",
1565 __LINE__,
1566 R"({
1567 "command": "submit_multisigned",
1568 "tx_json": {
1569 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1570 "Amount": "1000000000",
1571 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1572 "Sequence": 0,
1573 "Signers": [
1574 {
1575 "Signer": {
1576 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1577 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1578 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1579 }
1580 }
1581 ],
1582 "SigningPubKey": "",
1583 "TransactionType": "Payment"
1584 }
1585})",
1586 {{"Missing field 'secret'.",
1587 "Missing field 'secret'.",
1588 "Missing field 'account'.",
1589 "Missing field 'tx_json.Fee'."}}},
1590
1591 {"Non-numeric Fee in submit_multisigned.",
1592 __LINE__,
1593 R"({
1594 "command": "submit_multisigned",
1595 "tx_json": {
1596 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1597 "Amount": "1000000000",
1598 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1599 "Fee": 50.1,
1600 "Sequence": 0,
1601 "Signers": [
1602 {
1603 "Signer": {
1604 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1605 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1606 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1607 }
1608 }
1609 ],
1610 "SigningPubKey": "",
1611 "TransactionType": "Payment"
1612 }
1613})",
1614 {{"Missing field 'secret'.",
1615 "Missing field 'secret'.",
1616 "Missing field 'account'.",
1617 "Field 'tx_json.Fee' has invalid data."}}},
1618
1619 {"Missing Amount in submit_multisigned Payment.",
1620 __LINE__,
1621 R"({
1622 "command": "submit_multisigned",
1623 "tx_json": {
1624 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1625 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1626 "Fee": 50000000,
1627 "Sequence": 0,
1628 "Signers": [
1629 {
1630 "Signer": {
1631 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1632 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1633 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1634 }
1635 }
1636 ],
1637 "SigningPubKey": "",
1638 "TransactionType": "Payment"
1639 }
1640})",
1641 {{"Missing field 'secret'.",
1642 "Missing field 'secret'.",
1643 "Missing field 'account'.",
1644 "Missing field 'tx_json.Amount'."}}},
1645
1646 {"Invalid Amount in submit_multisigned Payment.",
1647 __LINE__,
1648 R"({
1649 "command": "submit_multisigned",
1650 "tx_json": {
1651 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1652 "Amount": "NotANumber",
1653 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1654 "Fee": 50,
1655 "Sequence": 0,
1656 "Signers": [
1657 {
1658 "Signer": {
1659 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1660 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1661 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1662 }
1663 }
1664 ],
1665 "SigningPubKey": "",
1666 "TransactionType": "Payment"
1667 }
1668})",
1669 {{"Missing field 'secret'.",
1670 "Missing field 'secret'.",
1671 "Missing field 'account'.",
1672 "Invalid field 'tx_json.Amount'."}}},
1673
1674 {"Invalid DeliverMax in submit_multisigned Payment.",
1675 __LINE__,
1676 R"({
1677 "command": "submit_multisigned",
1678 "tx_json": {
1679 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1680 "DeliverMax": "NotANumber",
1681 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1682 "Fee": 50,
1683 "Sequence": 0,
1684 "Signers": [
1685 {
1686 "Signer": {
1687 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1688 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1689 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1690 }
1691 }
1692 ],
1693 "SigningPubKey": "",
1694 "TransactionType": "Payment"
1695 }
1696})",
1697 {{"Missing field 'secret'.",
1698 "Missing field 'secret'.",
1699 "Missing field 'account'.",
1700 "Invalid field 'tx_json.Amount'."}}},
1701
1702 {"No build_path in submit_multisigned.",
1703 __LINE__,
1704 R"({
1705 "command": "submit_multisigned",
1706 "build_path": 1,
1707 "tx_json": {
1708 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1709 "Amount": "1000000000",
1710 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1711 "Fee": 50,
1712 "Sequence": 0,
1713 "Signers": [
1714 {
1715 "Signer": {
1716 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1717 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1718 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1719 }
1720 }
1721 ],
1722 "SigningPubKey": "",
1723 "TransactionType": "Payment"
1724 }
1725})",
1726 {{"Missing field 'secret'.",
1727 "Missing field 'secret'.",
1728 "Missing field 'account'.",
1729 "Field 'build_path' not allowed in this context."}}},
1730
1731 {"Missing Destination in submit_multisigned Payment.",
1732 __LINE__,
1733 R"({
1734 "command": "submit_multisigned",
1735 "tx_json": {
1736 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1737 "Amount": "1000000000",
1738 "Fee": 50,
1739 "Sequence": 0,
1740 "Signers": [
1741 {
1742 "Signer": {
1743 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1744 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1745 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1746 }
1747 }
1748 ],
1749 "SigningPubKey": "",
1750 "TransactionType": "Payment"
1751 }
1752})",
1753 {{"Missing field 'secret'.",
1754 "Missing field 'secret'.",
1755 "Missing field 'account'.",
1756 "Missing field 'tx_json.Destination'."}}},
1757
1758 {"Malformed Destination in submit_multisigned Payment.",
1759 __LINE__,
1760 R"({
1761 "command": "submit_multisigned",
1762 "tx_json": {
1763 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1764 "Amount": "1000000000",
1765 "Destination": "NotADestination",
1766 "Fee": 50,
1767 "Sequence": 0,
1768 "Signers": [
1769 {
1770 "Signer": {
1771 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1772 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1773 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1774 }
1775 }
1776 ],
1777 "SigningPubKey": "",
1778 "TransactionType": "Payment"
1779 }
1780})",
1781 {{"Missing field 'secret'.",
1782 "Missing field 'secret'.",
1783 "Missing field 'account'.",
1784 "Invalid field 'tx_json.Destination'."}}},
1785
1786 {"Missing Signers field in submit_multisigned.",
1787 __LINE__,
1788 R"({
1789 "command": "submit_multisigned",
1790 "tx_json": {
1791 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1792 "Amount": "1000000000",
1793 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1794 "Fee": 50,
1795 "Sequence": 0,
1796 "SigningPubKey": "",
1797 "TransactionType": "Payment"
1798 }
1799})",
1800 {{"Missing field 'secret'.",
1801 "Missing field 'secret'.",
1802 "Missing field 'account'.",
1803 "Missing field 'tx_json.Signers'."}}},
1804
1805 {"Signers not an array in submit_multisigned.",
1806 __LINE__,
1807 R"({
1808 "command": "submit_multisigned",
1809 "tx_json": {
1810 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1811 "Amount": "1000000000",
1812 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1813 "Fee": 50,
1814 "Sequence": 0,
1815 "Signers": {
1816 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1817 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1818 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1819 },
1820 "SigningPubKey": "",
1821 "TransactionType": "Payment"
1822 }
1823})",
1824 {{"Missing field 'secret'.",
1825 "Missing field 'secret'.",
1826 "Missing field 'account'.",
1827 "Field 'tx_json.Signers' is not a JSON array."}}},
1828
1829 {"Empty Signers array in submit_multisigned.",
1830 __LINE__,
1831 R"({
1832 "command": "submit_multisigned",
1833 "tx_json": {
1834 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1835 "Amount": "1000000000",
1836 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1837 "Fee": 50,
1838 "Sequence": 0,
1839 "Signers": [
1840 ],
1841 "SigningPubKey": "",
1842 "TransactionType": "Payment"
1843 }
1844})",
1845 {{"Missing field 'secret'.",
1846 "Missing field 'secret'.",
1847 "Missing field 'account'.",
1848 "tx_json.Signers array may not be empty."}}},
1849
1850 {"Duplicate Signer in submit_multisigned.",
1851 __LINE__,
1852 R"({
1853 "command": "submit_multisigned",
1854 "tx_json": {
1855 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1856 "Amount": "1000000000",
1857 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1858 "Fee": 50,
1859 "Sequence": 0,
1860 "Signers": [
1861 {
1862 "Signer": {
1863 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1864 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1865 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1866 }
1867 },
1868 {
1869 "Signer": {
1870 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1871 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1872 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1873 }
1874 }
1875 ],
1876 "SigningPubKey": "",
1877 "TransactionType": "Payment"
1878 }
1879})",
1880 {{"Missing field 'secret'.",
1881 "Missing field 'secret'.",
1882 "Missing field 'account'.",
1883 "Duplicate Signers:Signer:Account entries "
1884 "(rPcNzota6B8YBokhYtcTNqQVCngtbnWfux) are not allowed."}}},
1885
1886 {"Signer is tx_json Account in submit_multisigned.",
1887 __LINE__,
1888 R"({
1889 "command": "submit_multisigned",
1890 "tx_json": {
1891 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1892 "Amount": "1000000000",
1893 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1894 "Fee": 50,
1895 "Sequence": 0,
1896 "Signers": [
1897 {
1898 "Signer": {
1899 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1900 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1901 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1902 }
1903 }
1904 ],
1905 "SigningPubKey": "",
1906 "TransactionType": "Payment"
1907 }
1908})",
1909 {{"Missing field 'secret'.",
1910 "Missing field 'secret'.",
1911 "Missing field 'account'.",
1912 "A Signer may not be the transaction's Account "
1913 "(rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh)."}}},
1914
1915 {"Empty Signers array in submit_multisigned, use DeliverMax",
1916 __LINE__,
1917 R"({
1918 "command": "submit_multisigned",
1919 "tx_json": {
1920 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1921 "DeliverMax": "10000000",
1922 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1923 "Fee": 50,
1924 "Sequence": 0,
1925 "Signers": [
1926 ],
1927 "SigningPubKey": "",
1928 "TransactionType": "Payment"
1929 }
1930})",
1931 {{"Missing field 'secret'.",
1932 "Missing field 'secret'.",
1933 "Missing field 'account'.",
1934 "tx_json.Signers array may not be empty."}}},
1935
1936 {"Empty Signers array in submit_multisigned, use DeliverMax and Amount",
1937 __LINE__,
1938 R"({
1939 "command": "submit_multisigned",
1940 "tx_json": {
1941 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1942 "Amount": "10000000",
1943 "DeliverMax": "10000000",
1944 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1945 "Fee": 50,
1946 "Sequence": 0,
1947 "Signers": [
1948 ],
1949 "SigningPubKey": "",
1950 "TransactionType": "Payment"
1951 }
1952})",
1953 {{"Missing field 'secret'.",
1954 "Missing field 'secret'.",
1955 "Missing field 'account'.",
1956 "tx_json.Signers array may not be empty."}}},
1957
1958 {"Payment cannot specify different DeliverMax and Amount.",
1959 __LINE__,
1960 R"({
1961 "command": "dummy_command",
1962 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1963 "secret": "masterpassphrase",
1964 "debug_signing": 0,
1965 "tx_json": {
1966 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1967 "Amount": "1000000000",
1968 "DeliverMax": "1000000020",
1969 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1970 "Fee": 50,
1971 "Sequence": 0,
1972 "SigningPubKey": "",
1973 "TransactionType": "Payment"
1974 }
1975})",
1976 {{"Cannot specify differing 'Amount' and 'DeliverMax'",
1977 "Cannot specify differing 'Amount' and 'DeliverMax'",
1978 "Cannot specify differing 'Amount' and 'DeliverMax'",
1979 "Cannot specify differing 'Amount' and 'DeliverMax'"}}},
1980 {"Payment cannot specify bad DomainID.",
1981 __LINE__,
1982 R"({
1983 "command": "dummy_command",
1984 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1985 "secret": "masterpassphrase",
1986 "debug_signing": 0,
1987 "tx_json": {
1988 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1989 "Amount": "1000000000",
1990 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1991 "Fee": 50,
1992 "Sequence": 0,
1993 "SigningPubKey": "",
1994 "TransactionType": "Payment",
1995 "DomainID": "invalid",
1996 }
1997})",
1998 {{"Unable to parse 'DomainID'.",
1999 "Unable to parse 'DomainID'.",
2000 "Unable to parse 'DomainID'.",
2001 "Unable to parse 'DomainID'."}}},
2002
2003 {"Minimal delegated transaction.",
2004 __LINE__,
2005 R"({
2006 "command": "dummy_command",
2007 "secret": "a",
2008 "tx_json": {
2009 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
2010 "Amount": "1000000000",
2011 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
2012 "TransactionType": "Payment",
2013 "Delegate": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA"
2014 }
2015})",
2016 {{"", "", "Missing field 'account'.", "Missing field 'tx_json.Sequence'."}}},
2017
2018 {"Delegate not well formed.",
2019 __LINE__,
2020 R"({
2021 "command": "dummy_command",
2022 "secret": "a",
2023 "tx_json": {
2024 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
2025 "Amount": "1000000000",
2026 "Destination": "rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi",
2027 "TransactionType": "Payment",
2028 "Delegate": "NotAnAccount"
2029 }
2030})",
2031 {{"Invalid field 'tx_json.Delegate'.",
2032 "Invalid field 'tx_json.Delegate'.",
2033 "Missing field 'account'.",
2034 "Missing field 'tx_json.Sequence'."}}},
2035
2036 {"Delegate not in ledger.",
2037 __LINE__,
2038 R"({
2039 "command": "dummy_command",
2040 "secret": "a",
2041 "tx_json": {
2042 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
2043 "Amount": "1000000000",
2044 "Destination": "rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi",
2045 "TransactionType": "Payment",
2046 "Delegate": "rDg53Haik2475DJx8bjMDSDPj4VX7htaMd"
2047 }
2048})",
2049 {{"Delegate account not found.",
2050 "Delegate account not found.",
2051 "Missing field 'account'.",
2052 "Missing field 'tx_json.Sequence'."}}},
2053
2054 {"Delegate and secret not match.",
2055 __LINE__,
2056 R"({
2057 "command": "dummy_command",
2058 "secret": "aa",
2059 "tx_json": {
2060 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
2061 "Amount": "1000000000",
2062 "Destination": "rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi",
2063 "TransactionType": "Payment",
2064 "Delegate": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA"
2065 }
2066})",
2067 {{"Secret does not match account.",
2068 "Secret does not match account.",
2069 "Missing field 'account'.",
2070 "Missing field 'tx_json.Sequence'."}}},
2071
2072};
2073
2075{
2076public:
2077 void
2079 {
2080 testcase("bad RPC command");
2081 test::jtx::Env env(*this);
2082 Json::Value const result{env.rpc("bad_command", R"({"MakingThisUp": 0})")};
2083
2084 BEAST_EXPECT(result[jss::result][jss::error] == "unknownCmd");
2085 BEAST_EXPECT(result[jss::result][jss::request][jss::command] == "bad_command");
2086 }
2087
2088 void
2090 {
2091 testcase("autofill fails");
2092 using namespace test::jtx;
2093
2094 // test batch raw transactions max size
2095 {
2096 Env env(*this);
2097 auto ledger = env.current();
2098 auto const& feeTrack = env.app().getFeeTrack();
2099 Json::Value req;
2100 Account const alice("alice");
2101 Account const bob("bob");
2102 env.fund(XRP(100000), alice);
2103 env.close();
2104
2105 auto const batchFee = batch::calcBatchFee(env, 0, 2);
2106 auto const seq = env.seq(alice);
2107 auto jt = env.jtnofill(
2108 batch::outer(alice, env.seq(alice), batchFee, tfAllOrNothing),
2109 batch::inner(pay(alice, bob, XRP(1)), seq + 1),
2110 batch::inner(pay(alice, bob, XRP(2)), seq + 2),
2111 batch::inner(pay(alice, bob, XRP(3)), seq + 3),
2112 batch::inner(pay(alice, bob, XRP(4)), seq + 4),
2113 batch::inner(pay(alice, bob, XRP(5)), seq + 5),
2114 batch::inner(pay(alice, bob, XRP(6)), seq + 6),
2115 batch::inner(pay(alice, bob, XRP(7)), seq + 7),
2116 batch::inner(pay(alice, bob, XRP(8)), seq + 8),
2117 batch::inner(pay(alice, bob, XRP(9)), seq + 9));
2118
2119 jt.jv.removeMember(jss::Fee);
2120 jt.jv.removeMember(jss::TxnSignature);
2121 req[jss::tx_json] = jt.jv;
2122 Json::Value const result = checkFee(
2123 req,
2125 true,
2126 env.app().config(),
2127 feeTrack,
2128 env.app().getTxQ(),
2129 env.app());
2130 BEAST_EXPECT(result.size() == 0);
2131 BEAST_EXPECT(
2132 req[jss::tx_json].isMember(jss::Fee) &&
2133 req[jss::tx_json][jss::Fee] == env.current()->fees().base.jsonClipped());
2134 }
2135
2136 // test signers max size
2137 {
2138 Env env(*this);
2139 auto ledger = env.current();
2140 auto const& feeTrack = env.app().getFeeTrack();
2141 Json::Value req;
2142 Account const alice("alice");
2143 Account const bob("bob");
2144 env.fund(XRP(100000), alice, bob);
2145 env.close();
2146
2147 auto jt = env.jtnofill(
2148 noop(alice),
2149 msig(
2150 alice,
2151 alice,
2152 alice,
2153 alice,
2154 alice,
2155 alice,
2156 alice,
2157 alice,
2158 alice,
2159 alice,
2160 alice,
2161 alice,
2162 alice,
2163 alice,
2164 alice,
2165 alice,
2166 alice,
2167 alice,
2168 alice,
2169 alice,
2170 alice,
2171 alice,
2172 alice,
2173 alice,
2174 alice,
2175 alice,
2176 alice,
2177 alice,
2178 alice,
2179 alice,
2180 alice,
2181 alice,
2182 alice,
2183 alice,
2184 alice,
2185 alice,
2186 alice,
2187 alice,
2188 alice,
2189 alice));
2190
2191 req[jss::tx_json] = jt.jv;
2192 Json::Value const result = checkFee(
2193 req,
2195 true,
2196 env.app().config(),
2197 feeTrack,
2198 env.app().getTxQ(),
2199 env.app());
2200 BEAST_EXPECT(result.size() == 0);
2201 BEAST_EXPECT(
2202 req[jss::tx_json].isMember(jss::Fee) &&
2203 req[jss::tx_json][jss::Fee] == env.current()->fees().base.jsonClipped());
2204 }
2205 }
2206
2207 void
2209 {
2210 testcase("autofill fees");
2211 test::jtx::Env env(*this);
2212 auto const baseFee = static_cast<int>(env.current()->fees().base.drops());
2213 auto ledger = env.current();
2214 auto const& feeTrack = env.app().getFeeTrack();
2215
2216 {
2217 Json::Value req;
2218 Json::Reader().parse("{ \"fee_mult_max\" : 1, \"tx_json\" : { } } ", req);
2219 Json::Value const result = checkFee(
2220 req,
2222 true,
2223 env.app().config(),
2224 feeTrack,
2225 env.app().getTxQ(),
2226 env.app());
2227
2228 BEAST_EXPECT(!RPC::contains_error(result));
2229 BEAST_EXPECT(
2230 req[jss::tx_json].isMember(jss::Fee) && req[jss::tx_json][jss::Fee] == baseFee);
2231 }
2232
2233 {
2234 Json::Value req;
2236 "{ \"fee_mult_max\" : 3, \"fee_div_max\" : 2, "
2237 "\"tx_json\" : { } } ",
2238 req);
2239 Json::Value const result = checkFee(
2240 req,
2242 true,
2243 env.app().config(),
2244 feeTrack,
2245 env.app().getTxQ(),
2246 env.app());
2247
2248 BEAST_EXPECT(!RPC::contains_error(result));
2249 BEAST_EXPECT(
2250 req[jss::tx_json].isMember(jss::Fee) && req[jss::tx_json][jss::Fee] == baseFee);
2251 }
2252
2253 {
2254 Json::Value req;
2255 Json::Reader().parse("{ \"fee_mult_max\" : 0, \"tx_json\" : { } } ", req);
2256 Json::Value const result = checkFee(
2257 req,
2259 true,
2260 env.app().config(),
2261 feeTrack,
2262 env.app().getTxQ(),
2263 env.app());
2264
2265 BEAST_EXPECT(RPC::contains_error(result));
2266 BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee));
2267 }
2268
2269 {
2270 // 3/6 = 1/2, but use the bigger number make sure
2271 // we're dividing.
2272 Json::Value req;
2274 "{ \"fee_mult_max\" : 3, \"fee_div_max\" : 6, "
2275 "\"tx_json\" : { } } ",
2276 req);
2277 Json::Value const result = checkFee(
2278 req,
2280 true,
2281 env.app().config(),
2282 feeTrack,
2283 env.app().getTxQ(),
2284 env.app());
2285
2286 BEAST_EXPECT(RPC::contains_error(result));
2287 BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee));
2288 }
2289
2290 {
2291 Json::Value req;
2293 "{ \"fee_mult_max\" : 0, \"fee_div_max\" : 2, "
2294 "\"tx_json\" : { } } ",
2295 req);
2296 Json::Value const result = checkFee(
2297 req,
2299 true,
2300 env.app().config(),
2301 feeTrack,
2302 env.app().getTxQ(),
2303 env.app());
2304
2305 BEAST_EXPECT(RPC::contains_error(result));
2306 BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee));
2307 }
2308
2309 {
2310 Json::Value req;
2312 "{ \"fee_mult_max\" : 10, \"fee_div_max\" : 0, "
2313 "\"tx_json\" : { } } ",
2314 req);
2315 Json::Value const result = checkFee(
2316 req,
2318 true,
2319 env.app().config(),
2320 feeTrack,
2321 env.app().getTxQ(),
2322 env.app());
2323
2324 BEAST_EXPECT(RPC::contains_error(result));
2325 BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee));
2326 }
2327
2328 {
2329 // transaction with a higher base fee
2330 Json::Value req;
2331 test::jtx::Account const alice("alice");
2332 req[jss::tx_json] = test::jtx::acctdelete(env.master.human(), alice.human());
2333 Json::Value const result = checkFee(
2334 req,
2336 true,
2337 env.app().config(),
2338 feeTrack,
2339 env.app().getTxQ(),
2340 env.app());
2341
2342 BEAST_EXPECT(result.size() == 0);
2343 BEAST_EXPECT(
2344 req[jss::tx_json].isMember(jss::Fee) &&
2345 req[jss::tx_json][jss::Fee] == env.current()->fees().increment.jsonClipped());
2346 }
2347 }
2348
2349 void
2351 {
2352 testcase("autofill escalated fees");
2353 using namespace test::jtx;
2354 Env env{*this, envconfig([](std::unique_ptr<Config> cfg) {
2355 cfg->loadFromString("[" SECTION_SIGNING_SUPPORT "]\ntrue");
2356 cfg->section("transaction_queue").set("minimum_txn_in_ledger_standalone", "3");
2357 return cfg;
2358 })};
2359 LoadFeeTrack const& feeTrackOuter = env.app().getFeeTrack();
2360
2361 {
2362 // high mult, no tx
2363 Json::Value req;
2365 R"({
2366 "fee_mult_max" : 1000,
2367 "tx_json" : { }
2368 })",
2369 req);
2370 Json::Value const result = checkFee(
2371 req,
2373 true,
2374 env.app().config(),
2375 feeTrackOuter,
2376 env.app().getTxQ(),
2377 env.app());
2378
2379 BEAST_EXPECT(!RPC::contains_error(result));
2380 BEAST_EXPECT(req[jss::tx_json].isMember(jss::Fee) && req[jss::tx_json][jss::Fee] == 10);
2381 }
2382
2383 {
2384 // low mult, no tx
2385 Json::Value req;
2387 R"({
2388 "fee_mult_max" : 5,
2389 "tx_json" : { }
2390 })",
2391 req);
2392 Json::Value const result = checkFee(
2393 req,
2395 true,
2396 env.app().config(),
2397 feeTrackOuter,
2398 env.app().getTxQ(),
2399 env.app());
2400
2401 BEAST_EXPECT(!RPC::contains_error(result));
2402 BEAST_EXPECT(req[jss::tx_json].isMember(jss::Fee) && req[jss::tx_json][jss::Fee] == 10);
2403 }
2404
2405 // put 4 transactions into the open ledger
2406 for (auto i = 0; i < 4; ++i)
2407 {
2408 env(noop(env.master));
2409 }
2410
2411 {
2412 // high mult, 4 txs
2413 Json::Value req;
2415 R"({
2416 "fee_mult_max" : 1000,
2417 "tx_json" : { }
2418 })",
2419 req);
2420 Json::Value const result = checkFee(
2421 req,
2423 true,
2424 env.app().config(),
2425 feeTrackOuter,
2426 env.app().getTxQ(),
2427 env.app());
2428
2429 BEAST_EXPECT(!RPC::contains_error(result));
2430 BEAST_EXPECT(
2431 req[jss::tx_json].isMember(jss::Fee) && req[jss::tx_json][jss::Fee] == 8889);
2432 }
2433
2434 {
2435 // low mult, 4 tx
2436 Json::Value req;
2438 R"({
2439 "fee_mult_max" : 5,
2440 "tx_json" : { }
2441 })",
2442 req);
2443 Json::Value const result = checkFee(
2444 req,
2446 true,
2447 env.app().config(),
2448 feeTrackOuter,
2449 env.app().getTxQ(),
2450 env.app());
2451
2452 BEAST_EXPECT(RPC::contains_error(result));
2453 BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee));
2454 }
2455
2456 {
2457 // different low mult, 4 tx
2458 Json::Value req;
2460 R"({
2461 "fee_mult_max" : 1000,
2462 "fee_div_max" : 3,
2463 "tx_json" : { }
2464 })",
2465 req);
2466 Json::Value const result = checkFee(
2467 req,
2469 true,
2470 env.app().config(),
2471 feeTrackOuter,
2472 env.app().getTxQ(),
2473 env.app());
2474
2475 BEAST_EXPECT(RPC::contains_error(result));
2476 BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee));
2477 }
2478
2479 {
2480 // high mult, 4 tx
2481 Json::Value req;
2483 R"({
2484 "fee_mult_max" : 8000,
2485 "fee_div_max" : 3,
2486 "tx_json" : { }
2487 })",
2488 req);
2489 Json::Value const result = checkFee(
2490 req,
2492 true,
2493 env.app().config(),
2494 feeTrackOuter,
2495 env.app().getTxQ(),
2496 env.app());
2497
2498 BEAST_EXPECT(!RPC::contains_error(result));
2499 BEAST_EXPECT(
2500 req[jss::tx_json].isMember(jss::Fee) && req[jss::tx_json][jss::Fee] == 8889);
2501 }
2502
2503 {
2504 // negative mult
2505 Json::Value req;
2507 R"({
2508 "fee_mult_max" : -5,
2509 "tx_json" : { }
2510 })",
2511 req);
2512 Json::Value const result = checkFee(
2513 req,
2515 true,
2516 env.app().config(),
2517 feeTrackOuter,
2518 env.app().getTxQ(),
2519 env.app());
2520
2521 BEAST_EXPECT(RPC::contains_error(result));
2522 }
2523
2524 {
2525 // negative div
2526 Json::Value req;
2528 R"({
2529 "fee_div_max" : -2,
2530 "tx_json" : { }
2531 })",
2532 req);
2533 Json::Value const result = checkFee(
2534 req,
2536 true,
2537 env.app().config(),
2538 feeTrackOuter,
2539 env.app().getTxQ(),
2540 env.app());
2541
2542 BEAST_EXPECT(RPC::contains_error(result));
2543 }
2544
2545 {
2546 // negative mult & div
2547 Json::Value req;
2549 R"({
2550 "fee_mult_max" : -2,
2551 "fee_div_max" : -3,
2552 "tx_json" : { }
2553 })",
2554 req);
2555 Json::Value const result = checkFee(
2556 req,
2558 true,
2559 env.app().config(),
2560 feeTrackOuter,
2561 env.app().getTxQ(),
2562 env.app());
2563
2564 BEAST_EXPECT(RPC::contains_error(result));
2565 }
2566
2567 env.close();
2568
2569 {
2570 // Call "sign" with nothing in the open ledger
2571 Json::Value toSign;
2572 toSign[jss::tx_json] = noop(env.master);
2573 toSign[jss::secret] = "masterpassphrase";
2574 auto rpcResult = env.rpc("json", "sign", to_string(toSign));
2575 auto result = rpcResult[jss::result];
2576
2577 BEAST_EXPECT(!RPC::contains_error(result));
2578 BEAST_EXPECT(
2579 result[jss::tx_json].isMember(jss::Fee) && result[jss::tx_json][jss::Fee] == "10");
2580 BEAST_EXPECT(
2581 result[jss::tx_json].isMember(jss::Sequence) &&
2582 result[jss::tx_json][jss::Sequence].isConvertibleTo(Json::ValueType::uintValue));
2583 }
2584
2585 {
2586 // Call "sign" with enough transactions in the open ledger
2587 // to escalate the fee.
2588 for (;;)
2589 {
2590 auto metrics = env.app().getTxQ().getMetrics(*env.current());
2591 if (metrics.openLedgerFeeLevel > metrics.minProcessingFeeLevel)
2592 break;
2593 env(noop(env.master));
2594 }
2595
2596 Json::Value toSign;
2597 toSign[jss::tx_json] = noop(env.master);
2598 toSign[jss::secret] = "masterpassphrase";
2599 toSign[jss::fee_mult_max] = 900;
2600 auto rpcResult = env.rpc("json", "sign", to_string(toSign));
2601 auto result = rpcResult[jss::result];
2602
2603 BEAST_EXPECT(!RPC::contains_error(result));
2604 BEAST_EXPECT(
2605 result[jss::tx_json].isMember(jss::Fee) &&
2606 result[jss::tx_json][jss::Fee] == "7813");
2607 BEAST_EXPECT(
2608 result[jss::tx_json].isMember(jss::Sequence) &&
2609 result[jss::tx_json][jss::Sequence].isConvertibleTo(Json::ValueType::uintValue));
2610
2611 env.close();
2612 }
2613
2614 {
2615 // Call "sign" with higher server load
2616 {
2617 auto& feeTrack = env.app().getFeeTrack();
2618 BEAST_EXPECT(feeTrack.getLoadFactor() == 256);
2619 for (int i = 0; i < 8; ++i)
2620 feeTrack.raiseLocalFee();
2621 BEAST_EXPECT(feeTrack.getLoadFactor() == 1220);
2622 }
2623
2624 Json::Value toSign;
2625 toSign[jss::tx_json] = noop(env.master);
2626 toSign[jss::secret] = "masterpassphrase";
2627 auto rpcResult = env.rpc("json", "sign", to_string(toSign));
2628 auto result = rpcResult[jss::result];
2629
2630 BEAST_EXPECT(!RPC::contains_error(result));
2631 BEAST_EXPECT(
2632 result[jss::tx_json].isMember(jss::Fee) && result[jss::tx_json][jss::Fee] == "47");
2633 BEAST_EXPECT(
2634 result[jss::tx_json].isMember(jss::Sequence) &&
2635 result[jss::tx_json][jss::Sequence].isConvertibleTo(Json::ValueType::uintValue));
2636 }
2637
2638 {
2639 // Call "sign" with higher server load and
2640 // enough transactions to escalate the fee
2641 BEAST_EXPECT(feeTrackOuter.getLoadFactor() == 1220);
2643 for (;;)
2644 {
2645 auto metrics = env.app().getTxQ().getMetrics(*env.current());
2646 if (metrics.openLedgerFeeLevel > metrics.minProcessingFeeLevel)
2647 break;
2648 env(noop(env.master), fee(47));
2649 }
2650
2651 Env_ss const envs(env);
2652
2653 Json::Value toSign;
2654 toSign[jss::tx_json] = noop(env.master);
2655 toSign[jss::secret] = "masterpassphrase";
2656 // Max fee = 7000 drops
2657 toSign[jss::fee_mult_max] = 700;
2658 auto rpcResult = env.rpc("json", "sign", to_string(toSign));
2659 auto result = rpcResult[jss::result];
2660
2661 BEAST_EXPECT(!RPC::contains_error(result));
2662 BEAST_EXPECT(
2663 result[jss::tx_json].isMember(jss::Fee) &&
2664 result[jss::tx_json][jss::Fee] == "6806");
2665 BEAST_EXPECT(
2666 result[jss::tx_json].isMember(jss::Sequence) &&
2667 result[jss::tx_json][jss::Sequence].isConvertibleTo(Json::ValueType::uintValue));
2668 }
2670
2671 void
2673 {
2674 testcase("autofill NetworkID");
2675 using namespace test::jtx;
2676 Env env{*this, envconfig([&](std::unique_ptr<Config> cfg) {
2677 cfg->NETWORK_ID = 1025;
2678 return cfg;
2679 })};
2680
2681 {
2682 Json::Value toSign;
2683 toSign[jss::tx_json] = noop(env.master);
2684
2685 BEAST_EXPECT(!toSign[jss::tx_json].isMember(jss::NetworkID));
2686 toSign[jss::secret] = "masterpassphrase";
2687 auto rpcResult = env.rpc("json", "sign", to_string(toSign));
2688 auto result = rpcResult[jss::result];
2689
2690 BEAST_EXPECT(!RPC::contains_error(result));
2691 BEAST_EXPECT(
2692 result[jss::tx_json].isMember(jss::NetworkID) &&
2693 result[jss::tx_json][jss::NetworkID] == 1025);
2694 }
2695 }
2696
2697 // A function that can be called as though it would process a transaction.
2698 static void
2700 {
2701 ;
2702 }
2703
2704 void
2706 {
2707 testcase("sign/submit RPCs");
2708 using namespace std::chrono_literals;
2709 using namespace test::jtx;
2710 // Use jtx to set up a ledger so the tests will do the right thing.
2711 Account const a{"a"}; // rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA
2712 Account const g{"g"}; // rLPwWB1itaUGMV8kbMLLysjGkEpTM2Soy4
2713 auto const USD = g["USD"];
2714
2715 // Account: rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi
2716 // seed: sh1yJfwoi98zCygwijUzuHmJDeVKd
2717 Account const ed{"ed", KeyType::ed25519};
2718 // master is rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh.
2719 // "b" (not in the ledger) is rDg53Haik2475DJx8bjMDSDPj4VX7htaMd.
2720 // "c" (phantom signer) is rPcNzota6B8YBokhYtcTNqQVCngtbnWfux.
2721
2722 Env env(*this, envconfig([](std::unique_ptr<Config> cfg) {
2723 cfg->FEES.reference_fee = 10;
2724 return cfg;
2725 }));
2726 env.fund(XRP(100000), a, ed, g);
2727 env.close();
2728
2729 env(trust(a, USD(1000)));
2730 env(trust(env.master, USD(1000)));
2731 env(pay(g, a, USD(50)));
2732 env(pay(g, env.master, USD(50)));
2733 env.close();
2734
2736
2737 // A list of all the functions we want to test.
2738 using signFunc = Json::Value (*)(
2739 Json::Value params,
2740 unsigned int apiVersion,
2741 NetworkOPs::FailHard failType,
2742 Role role,
2743 std::chrono::seconds validatedLedgerAge,
2744 Application& app);
2745
2746 using submitFunc = Json::Value (*)(
2747 Json::Value params,
2748 unsigned int apiVersion,
2749 NetworkOPs::FailHard failType,
2750 Role role,
2751 std::chrono::seconds validatedLedgerAge,
2752 Application& app,
2753 ProcessTransactionFn const& processTransaction);
2754
2756
2757 static TestStuff const testFuncs[] = {
2758 TestStuff{transactionSign, nullptr, "sign", 0},
2759 TestStuff{nullptr, transactionSubmit, "submit", 1},
2760 TestStuff{transactionSignFor, nullptr, "sign_for", 2},
2761 TestStuff{nullptr, transactionSubmitMultiSigned, "submit_multisigned", 3}};
2762
2763 for (auto testFunc : testFuncs)
2764 {
2765 // For each JSON test.
2766 for (auto const& txnTest : txnTestArray)
2767 {
2768 Json::Value req;
2769 Json::Reader().parse(txnTest.json, req);
2770 if (RPC::contains_error(req))
2771 Throw<std::runtime_error>("Internal JSONRPC_test error. Bad test JSON.");
2772
2773 static Role const testedRoles[] = {
2775
2776 for (Role const testRole : testedRoles)
2777 {
2778 Json::Value result;
2779 auto const signFn = get<0>(testFunc);
2780 if (signFn != nullptr)
2781 {
2782 assert(get<1>(testFunc) == nullptr);
2783 result = signFn(req, 1, NetworkOPs::FailHard::yes, testRole, 1s, env.app());
2785 else
2786 {
2787 auto const submitFn = get<1>(testFunc);
2788 assert(submitFn != nullptr);
2789 result = submitFn(
2790 req, 1, NetworkOPs::FailHard::yes, testRole, 1s, env.app(), processTxn);
2791 }
2792
2793 std::string errStr;
2794 if (RPC::contains_error(result))
2795 errStr = result["error_message"].asString();
2796
2797 if (errStr == txnTest.expMsg[get<3>(testFunc)])
2798 {
2799 pass();
2800 }
2801 else
2802 {
2803 std::ostringstream description;
2804 description << txnTest.description << " Called " << get<2>(testFunc)
2805 << "(). Got \'" << errStr << "\'";
2806 fail(description.str(), __FILE__, txnTest.line);
2807 }
2808 }
2809 }
2810 }
2811 }
2812
2813 void
2814 run() override
2815 {
2822 }
2823};
2824
2825BEAST_DEFINE_TESTSUITE(JSONRPC, rpc, xrpl);
2826
2827} // namespace RPC
2828} // namespace xrpl
Unserialize a JSON document into a Value.
Definition json_reader.h:17
bool parse(std::string const &document, Value &root)
Read a Value from a JSON document.
Represents a JSON value.
Definition json_value.h:130
UInt size() const
Number of values in array or object.
std::string asString() const
Returns the unquoted string value.
A testsuite class.
Definition suite.h:51
void pass()
Record a successful test condition.
Definition suite.h:497
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:150
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition suite.h:519
virtual Config & config()=0
Manages the current fee schedule.
std::uint32_t getLoadFactor() const
void run() override
Runs the suite.
static void fakeProcessTransaction(std::shared_ptr< Transaction > &, bool, bool, NetworkOPs::FailHard)
virtual TxQ & getTxQ()=0
virtual LoadFeeTrack & getFeeTrack()=0
Immutable cryptographic account descriptor.
Definition Account.h:19
std::string const & human() const
Returns the human readable public key.
Definition Account.h:94
A transaction testing environment.
Definition Env.h:122
Application & app()
Definition Env.h:259
Account const & master
Definition Env.h:126
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Definition Env.h:847
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition Env.h:329
@ uintValue
unsigned integer value
Definition json_value.h:21
Json::Value transactionSubmit(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app, ProcessTransactionFn const &processTransaction)
Returns a Json::objectValue.
Json::Value transactionSign(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app)
Returns a Json::objectValue.
static constexpr TxnTestData txnTestArray[]
Json::Value checkFee(Json::Value &request, Role const role, bool doAutoFill, Config const &config, LoadFeeTrack const &feeTrack, TxQ const &txQ, Application const &app)
Fill in the fee on behalf of the client.
Json::Value transactionSignFor(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app)
Returns a Json::objectValue.
static constexpr std::integral_constant< unsigned, Version > apiVersion
Definition ApiVersion.h:38
Json::Value transactionSubmitMultiSigned(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app, ProcessTransactionFn const &processTransaction)
Returns a Json::objectValue.
std::function< void(std::shared_ptr< Transaction > &transaction, bool bUnlimited, bool bLocal, NetworkOPs::FailHard failType)> ProcessTransactionFn
bool contains_error(Json::Value const &json)
Returns true if the json contains an rpc error specification.
Json::Value trust(AccountID const &account, STAmount const &amount, std::uint32_t flags=0)
Definition AMM.cpp:802
Json::Value pay(Account const &account, AccountID const &to, STAmount const &amount)
Definition AMM.cpp:814
XRP_t const XRP
Converts to XRP Issue or STAmount.
Definition amount.cpp:95
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition envconfig.h:34
Json::Value acctdelete(Account const &account, Account const &dest)
Delete account.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
bool set(T &target, std::string const &name, Section const &section)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:602
Role
Indicates the level of administrative permission to grant.
Definition Role.h:24
T str(T... args)
TxnTestData(TxnTestData const &)=delete
TxnTestData(TxnTestData &&)=delete
char const *const description
constexpr TxnTestData(char const *description_, int line_, char const *json_, std::array< char const *const, 4 > const &expMsg_)
TxnTestData & operator=(TxnTestData &&)=delete
char const *const json
TxnTestData & operator=(TxnTestData const &)=delete
std::array< char const *const, 4 > const expMsg