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