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