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 testcase("bad RPC command");
2053 test::jtx::Env env(*this);
2054 Json::Value const result{
2055 env.rpc("bad_command", R"({"MakingThisUp": 0})")};
2056
2057 BEAST_EXPECT(result[jss::result][jss::error] == "unknownCmd");
2058 BEAST_EXPECT(
2059 result[jss::result][jss::request][jss::command] == "bad_command");
2060 }
2061
2062 void
2064 {
2065 testcase("autofill fees");
2066 test::jtx::Env env(*this);
2067 auto ledger = env.current();
2068 auto const& feeTrack = env.app().getFeeTrack();
2069
2070 {
2071 Json::Value req;
2073 "{ \"fee_mult_max\" : 1, \"tx_json\" : { } } ", req);
2074 Json::Value result = checkFee(
2075 req,
2077 true,
2078 env.app().config(),
2079 feeTrack,
2080 env.app().getTxQ(),
2081 env.app());
2082
2083 BEAST_EXPECT(!RPC::contains_error(result));
2084 BEAST_EXPECT(
2085 req[jss::tx_json].isMember(jss::Fee) &&
2086 req[jss::tx_json][jss::Fee] == 10);
2087 }
2088
2089 {
2090 Json::Value req;
2092 "{ \"fee_mult_max\" : 3, \"fee_div_max\" : 2, "
2093 "\"tx_json\" : { } } ",
2094 req);
2095 Json::Value result = checkFee(
2096 req,
2098 true,
2099 env.app().config(),
2100 feeTrack,
2101 env.app().getTxQ(),
2102 env.app());
2103
2104 BEAST_EXPECT(!RPC::contains_error(result));
2105 BEAST_EXPECT(
2106 req[jss::tx_json].isMember(jss::Fee) &&
2107 req[jss::tx_json][jss::Fee] == 10);
2108 }
2109
2110 {
2111 Json::Value req;
2113 "{ \"fee_mult_max\" : 0, \"tx_json\" : { } } ", req);
2114 Json::Value result = checkFee(
2115 req,
2117 true,
2118 env.app().config(),
2119 feeTrack,
2120 env.app().getTxQ(),
2121 env.app());
2122
2123 BEAST_EXPECT(RPC::contains_error(result));
2124 BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee));
2125 }
2126
2127 {
2128 // 3/6 = 1/2, but use the bigger number make sure
2129 // we're dividing.
2130 Json::Value req;
2132 "{ \"fee_mult_max\" : 3, \"fee_div_max\" : 6, "
2133 "\"tx_json\" : { } } ",
2134 req);
2135 Json::Value result = checkFee(
2136 req,
2138 true,
2139 env.app().config(),
2140 feeTrack,
2141 env.app().getTxQ(),
2142 env.app());
2143
2144 BEAST_EXPECT(RPC::contains_error(result));
2145 BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee));
2146 }
2147
2148 {
2149 Json::Value req;
2151 "{ \"fee_mult_max\" : 0, \"fee_div_max\" : 2, "
2152 "\"tx_json\" : { } } ",
2153 req);
2154 Json::Value result = checkFee(
2155 req,
2157 true,
2158 env.app().config(),
2159 feeTrack,
2160 env.app().getTxQ(),
2161 env.app());
2162
2163 BEAST_EXPECT(RPC::contains_error(result));
2164 BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee));
2165 }
2166
2167 {
2168 Json::Value req;
2170 "{ \"fee_mult_max\" : 10, \"fee_div_max\" : 0, "
2171 "\"tx_json\" : { } } ",
2172 req);
2173 Json::Value result = checkFee(
2174 req,
2176 true,
2177 env.app().config(),
2178 feeTrack,
2179 env.app().getTxQ(),
2180 env.app());
2181
2182 BEAST_EXPECT(RPC::contains_error(result));
2183 BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee));
2184 }
2185
2186 {
2187 // transaction with a higher base fee
2188 Json::Value req;
2189 test::jtx::Account const alice("alice");
2190 req[jss::tx_json] =
2191 test::jtx::acctdelete(env.master.human(), alice.human());
2192 Json::Value result = checkFee(
2193 req,
2195 true,
2196 env.app().config(),
2197 feeTrack,
2198 env.app().getTxQ(),
2199 env.app());
2200
2201 BEAST_EXPECT(result.size() == 0);
2202 BEAST_EXPECT(
2203 req[jss::tx_json].isMember(jss::Fee) &&
2204 req[jss::tx_json][jss::Fee] ==
2205 env.current()->fees().increment.jsonClipped());
2206 }
2207 }
2208
2209 void
2211 {
2212 testcase("autofill escalated fees");
2213 using namespace test::jtx;
2214 Env env{*this, envconfig([](std::unique_ptr<Config> cfg) {
2215 cfg->loadFromString("[" SECTION_SIGNING_SUPPORT "]\ntrue");
2216 cfg->section("transaction_queue")
2217 .set("minimum_txn_in_ledger_standalone", "3");
2218 return cfg;
2219 })};
2220 LoadFeeTrack const& feeTrackOuter = env.app().getFeeTrack();
2221
2222 {
2223 // high mult, no tx
2224 Json::Value req;
2226 R"({
2227 "fee_mult_max" : 1000,
2228 "tx_json" : { }
2229 })",
2230 req);
2231 Json::Value result = checkFee(
2232 req,
2234 true,
2235 env.app().config(),
2236 feeTrackOuter,
2237 env.app().getTxQ(),
2238 env.app());
2239
2240 BEAST_EXPECT(!RPC::contains_error(result));
2241 BEAST_EXPECT(
2242 req[jss::tx_json].isMember(jss::Fee) &&
2243 req[jss::tx_json][jss::Fee] == 10);
2244 }
2245
2246 {
2247 // low mult, no tx
2248 Json::Value req;
2250 R"({
2251 "fee_mult_max" : 5,
2252 "tx_json" : { }
2253 })",
2254 req);
2255 Json::Value result = checkFee(
2256 req,
2258 true,
2259 env.app().config(),
2260 feeTrackOuter,
2261 env.app().getTxQ(),
2262 env.app());
2263
2264 BEAST_EXPECT(!RPC::contains_error(result));
2265 BEAST_EXPECT(
2266 req[jss::tx_json].isMember(jss::Fee) &&
2267 req[jss::tx_json][jss::Fee] == 10);
2268 }
2269
2270 // put 4 transactions into the open ledger
2271 for (auto i = 0; i < 4; ++i)
2272 {
2273 env(noop(env.master));
2274 }
2275
2276 {
2277 // high mult, 4 txs
2278 Json::Value req;
2280 R"({
2281 "fee_mult_max" : 1000,
2282 "tx_json" : { }
2283 })",
2284 req);
2285 Json::Value result = checkFee(
2286 req,
2288 true,
2289 env.app().config(),
2290 feeTrackOuter,
2291 env.app().getTxQ(),
2292 env.app());
2293
2294 BEAST_EXPECT(!RPC::contains_error(result));
2295 BEAST_EXPECT(
2296 req[jss::tx_json].isMember(jss::Fee) &&
2297 req[jss::tx_json][jss::Fee] == 8889);
2298 }
2299
2300 {
2301 // low mult, 4 tx
2302 Json::Value req;
2304 R"({
2305 "fee_mult_max" : 5,
2306 "tx_json" : { }
2307 })",
2308 req);
2309 Json::Value result = checkFee(
2310 req,
2312 true,
2313 env.app().config(),
2314 feeTrackOuter,
2315 env.app().getTxQ(),
2316 env.app());
2317
2318 BEAST_EXPECT(RPC::contains_error(result));
2319 BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee));
2320 }
2321
2322 {
2323 // different low mult, 4 tx
2324 Json::Value req;
2326 R"({
2327 "fee_mult_max" : 1000,
2328 "fee_div_max" : 3,
2329 "tx_json" : { }
2330 })",
2331 req);
2332 Json::Value result = checkFee(
2333 req,
2335 true,
2336 env.app().config(),
2337 feeTrackOuter,
2338 env.app().getTxQ(),
2339 env.app());
2340
2341 BEAST_EXPECT(RPC::contains_error(result));
2342 BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee));
2343 }
2344
2345 {
2346 // high mult, 4 tx
2347 Json::Value req;
2349 R"({
2350 "fee_mult_max" : 8000,
2351 "fee_div_max" : 3,
2352 "tx_json" : { }
2353 })",
2354 req);
2355 Json::Value result = checkFee(
2356 req,
2358 true,
2359 env.app().config(),
2360 feeTrackOuter,
2361 env.app().getTxQ(),
2362 env.app());
2363
2364 BEAST_EXPECT(!RPC::contains_error(result));
2365 BEAST_EXPECT(
2366 req[jss::tx_json].isMember(jss::Fee) &&
2367 req[jss::tx_json][jss::Fee] == 8889);
2368 }
2369
2370 {
2371 // negative mult
2372 Json::Value req;
2374 R"({
2375 "fee_mult_max" : -5,
2376 "tx_json" : { }
2377 })",
2378 req);
2379 Json::Value result = checkFee(
2380 req,
2382 true,
2383 env.app().config(),
2384 feeTrackOuter,
2385 env.app().getTxQ(),
2386 env.app());
2387
2388 BEAST_EXPECT(RPC::contains_error(result));
2389 }
2390
2391 {
2392 // negative div
2393 Json::Value req;
2395 R"({
2396 "fee_div_max" : -2,
2397 "tx_json" : { }
2398 })",
2399 req);
2400 Json::Value result = checkFee(
2401 req,
2403 true,
2404 env.app().config(),
2405 feeTrackOuter,
2406 env.app().getTxQ(),
2407 env.app());
2408
2409 BEAST_EXPECT(RPC::contains_error(result));
2410 }
2411
2412 {
2413 // negative mult & div
2414 Json::Value req;
2416 R"({
2417 "fee_mult_max" : -2,
2418 "fee_div_max" : -3,
2419 "tx_json" : { }
2420 })",
2421 req);
2422 Json::Value result = checkFee(
2423 req,
2425 true,
2426 env.app().config(),
2427 feeTrackOuter,
2428 env.app().getTxQ(),
2429 env.app());
2430
2431 BEAST_EXPECT(RPC::contains_error(result));
2432 }
2433
2434 env.close();
2435
2436 {
2437 // Call "sign" with nothing in the open ledger
2438 Json::Value toSign;
2439 toSign[jss::tx_json] = noop(env.master);
2440 toSign[jss::secret] = "masterpassphrase";
2441 auto rpcResult = env.rpc("json", "sign", to_string(toSign));
2442 auto result = rpcResult[jss::result];
2443
2444 BEAST_EXPECT(!RPC::contains_error(result));
2445 BEAST_EXPECT(
2446 result[jss::tx_json].isMember(jss::Fee) &&
2447 result[jss::tx_json][jss::Fee] == "10");
2448 BEAST_EXPECT(
2449 result[jss::tx_json].isMember(jss::Sequence) &&
2450 result[jss::tx_json][jss::Sequence].isConvertibleTo(
2452 }
2453
2454 {
2455 // Call "sign" with enough transactions in the open ledger
2456 // to escalate the fee.
2457 for (;;)
2458 {
2459 auto metrics = env.app().getTxQ().getMetrics(*env.current());
2460 if (metrics.openLedgerFeeLevel > metrics.minProcessingFeeLevel)
2461 break;
2462 env(noop(env.master));
2463 }
2464
2465 Json::Value toSign;
2466 toSign[jss::tx_json] = noop(env.master);
2467 toSign[jss::secret] = "masterpassphrase";
2468 toSign[jss::fee_mult_max] = 900;
2469 auto rpcResult = env.rpc("json", "sign", to_string(toSign));
2470 auto result = rpcResult[jss::result];
2471
2472 BEAST_EXPECT(!RPC::contains_error(result));
2473 BEAST_EXPECT(
2474 result[jss::tx_json].isMember(jss::Fee) &&
2475 result[jss::tx_json][jss::Fee] == "7813");
2476 BEAST_EXPECT(
2477 result[jss::tx_json].isMember(jss::Sequence) &&
2478 result[jss::tx_json][jss::Sequence].isConvertibleTo(
2480
2481 env.close();
2482 }
2483
2484 {
2485 // Call "sign" with higher server load
2486 {
2487 auto& feeTrack = env.app().getFeeTrack();
2488 BEAST_EXPECT(feeTrack.getLoadFactor() == 256);
2489 for (int i = 0; i < 8; ++i)
2490 feeTrack.raiseLocalFee();
2491 BEAST_EXPECT(feeTrack.getLoadFactor() == 1220);
2492 }
2493
2494 Json::Value toSign;
2495 toSign[jss::tx_json] = noop(env.master);
2496 toSign[jss::secret] = "masterpassphrase";
2497 auto rpcResult = env.rpc("json", "sign", to_string(toSign));
2498 auto result = rpcResult[jss::result];
2499
2500 BEAST_EXPECT(!RPC::contains_error(result));
2501 BEAST_EXPECT(
2502 result[jss::tx_json].isMember(jss::Fee) &&
2503 result[jss::tx_json][jss::Fee] == "47");
2504 BEAST_EXPECT(
2505 result[jss::tx_json].isMember(jss::Sequence) &&
2506 result[jss::tx_json][jss::Sequence].isConvertibleTo(
2508 }
2509
2510 {
2511 // Call "sign" with higher server load and
2512 // enough transactions to escalate the fee
2513 BEAST_EXPECT(feeTrackOuter.getLoadFactor() == 1220);
2514
2515 for (;;)
2516 {
2517 auto metrics = env.app().getTxQ().getMetrics(*env.current());
2518 if (metrics.openLedgerFeeLevel > metrics.minProcessingFeeLevel)
2519 break;
2520 env(noop(env.master), fee(47));
2521 }
2522
2523 Env_ss envs(env);
2524
2525 Json::Value toSign;
2526 toSign[jss::tx_json] = noop(env.master);
2527 toSign[jss::secret] = "masterpassphrase";
2528 // Max fee = 7000 drops
2529 toSign[jss::fee_mult_max] = 700;
2530 auto rpcResult = env.rpc("json", "sign", to_string(toSign));
2531 auto result = rpcResult[jss::result];
2532
2533 BEAST_EXPECT(!RPC::contains_error(result));
2534 BEAST_EXPECT(
2535 result[jss::tx_json].isMember(jss::Fee) &&
2536 result[jss::tx_json][jss::Fee] == "6806");
2537 BEAST_EXPECT(
2538 result[jss::tx_json].isMember(jss::Sequence) &&
2539 result[jss::tx_json][jss::Sequence].isConvertibleTo(
2541 }
2543
2544 void
2546 {
2547 testcase("autofill NetworkID");
2548 using namespace test::jtx;
2549 Env env{*this, envconfig([&](std::unique_ptr<Config> cfg) {
2550 cfg->NETWORK_ID = 1025;
2551 return cfg;
2552 })};
2553
2554 {
2555 Json::Value toSign;
2556 toSign[jss::tx_json] = noop(env.master);
2557
2558 BEAST_EXPECT(!toSign[jss::tx_json].isMember(jss::NetworkID));
2559 toSign[jss::secret] = "masterpassphrase";
2560 auto rpcResult = env.rpc("json", "sign", to_string(toSign));
2561 auto result = rpcResult[jss::result];
2562
2563 BEAST_EXPECT(!RPC::contains_error(result));
2564 BEAST_EXPECT(
2565 result[jss::tx_json].isMember(jss::NetworkID) &&
2566 result[jss::tx_json][jss::NetworkID] == 1025);
2567 }
2568 }
2569
2570 // A function that can be called as though it would process a transaction.
2571 static void
2574 bool,
2575 bool,
2577 {
2578 ;
2579 }
2580
2581 void
2583 {
2584 testcase("sign/submit RPCs");
2585 using namespace std::chrono_literals;
2586 // Use jtx to set up a ledger so the tests will do the right thing.
2587 test::jtx::Account const a{"a"}; // rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA
2588 test::jtx::Account const g{"g"}; // rLPwWB1itaUGMV8kbMLLysjGkEpTM2Soy4
2589 auto const USD = g["USD"];
2590
2591 // Account: rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi
2592 // seed: sh1yJfwoi98zCygwijUzuHmJDeVKd
2593 test::jtx::Account const ed{"ed", KeyType::ed25519};
2594 // master is rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh.
2595 // "b" (not in the ledger) is rDg53Haik2475DJx8bjMDSDPj4VX7htaMd.
2596 // "c" (phantom signer) is rPcNzota6B8YBokhYtcTNqQVCngtbnWfux.
2597
2598 test::jtx::Env env(*this);
2599 env.fund(test::jtx::XRP(100000), a, ed, g);
2600 env.close();
2601
2602 env(trust(a, USD(1000)));
2603 env(trust(env.master, USD(1000)));
2604 env(pay(g, a, USD(50)));
2605 env(pay(g, env.master, USD(50)));
2606 env.close();
2607
2609
2610 // A list of all the functions we want to test.
2611 using signFunc = Json::Value (*)(
2612 Json::Value params,
2613 unsigned int apiVersion,
2614 NetworkOPs::FailHard failType,
2615 Role role,
2616 std::chrono::seconds validatedLedgerAge,
2617 Application& app);
2618
2619 using submitFunc = Json::Value (*)(
2620 Json::Value params,
2621 unsigned int apiVersion,
2622 NetworkOPs::FailHard failType,
2623 Role role,
2624 std::chrono::seconds validatedLedgerAge,
2625 Application& app,
2626 ProcessTransactionFn const& processTransaction);
2627
2628 using TestStuff =
2630
2631 static TestStuff const testFuncs[] = {
2632 TestStuff{transactionSign, nullptr, "sign", 0},
2633 TestStuff{nullptr, transactionSubmit, "submit", 1},
2634 TestStuff{transactionSignFor, nullptr, "sign_for", 2},
2635 TestStuff{
2636 nullptr,
2638 "submit_multisigned",
2639 3}};
2640
2641 for (auto testFunc : testFuncs)
2642 {
2643 // For each JSON test.
2644 for (auto const& txnTest : txnTestArray)
2645 {
2646 Json::Value req;
2647 Json::Reader().parse(txnTest.json, req);
2648 if (RPC::contains_error(req))
2649 Throw<std::runtime_error>(
2650 "Internal JSONRPC_test error. Bad test JSON.");
2651
2652 static Role const testedRoles[] = {
2654
2655 for (Role testRole : testedRoles)
2656 {
2657 Json::Value result;
2658 auto const signFn = get<0>(testFunc);
2659 if (signFn != nullptr)
2660 {
2661 assert(get<1>(testFunc) == nullptr);
2662 result = signFn(
2663 req,
2664 1,
2666 testRole,
2667 1s,
2668 env.app());
2669 }
2670 else
2671 {
2672 auto const submitFn = get<1>(testFunc);
2673 assert(submitFn != nullptr);
2674 result = submitFn(
2675 req,
2678 testRole,
2679 1s,
2680 env.app(),
2681 processTxn);
2682 }
2683
2684 std::string errStr;
2685 if (RPC::contains_error(result))
2686 errStr = result["error_message"].asString();
2687
2688 if (errStr == txnTest.expMsg[get<3>(testFunc)])
2689 {
2690 pass();
2691 }
2692 else
2693 {
2694 std::ostringstream description;
2695 description << txnTest.description << " Called "
2696 << get<2>(testFunc) << "(). Got \'"
2697 << errStr << "\'";
2698 fail(description.str(), __FILE__, txnTest.line);
2699 }
2700 }
2701 }
2702 }
2703 }
2704
2705 void
2706 run() override
2707 {
2713 }
2714};
2715
2716BEAST_DEFINE_TESTSUITE(JSONRPC, ripple_app, ripple);
2717
2718} // namespace RPC
2719} // 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
testcase_t testcase
Memberspace for declaring test cases.
Definition: suite.h:153
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