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 {"Minimal submit_multisigned.",
1341 __LINE__,
1342 R"({
1343 "command": "submit_multisigned",
1344 "tx_json": {
1345 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1346 "Amount": "1000000000",
1347 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1348 "Fee": 50,
1349 "Sequence": 0,
1350 "Signers" : [
1351 {
1352 "Signer" : {
1353 "Account" : "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1354 "SigningPubKey" : "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8",
1355 "TxnSignature" : "3045022100909D01399AFFAD1E30D250CE61F93975B7F61E47B5244D78C3E86D9806535D95022012E389E0ACB016334052B7FE07FA6CEFDC8BE82CB410FA841D5049641C89DC8F"
1356 }
1357 }
1358 ],
1359 "SigningPubKey": "",
1360 "TransactionType": "Payment"
1361 }
1362})",
1363 {{"Missing field 'secret'.",
1364 "Missing field 'secret'.",
1365 "Missing field 'account'.",
1366 ""}}},
1367
1368 {"Minimal submit_multisigned with bad signature.",
1369 __LINE__,
1370 R"({
1371 "command": "submit_multisigned",
1372 "tx_json": {
1373 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1374 "Amount": "1000000000",
1375 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1376 "Fee": 50,
1377 "Sequence": 0,
1378 "Signers": [
1379 {
1380 "Signer": {
1381 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1382 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1383 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1384 }
1385 }
1386 ],
1387 "SigningPubKey": "",
1388 "TransactionType": "Payment"
1389 }
1390})",
1391 {{"Missing field 'secret'.",
1392 "Missing field 'secret'.",
1393 "Missing field 'account'.",
1394 "Invalid signature."}}},
1395
1396 {"Missing tx_json in submit_multisigned.",
1397 __LINE__,
1398 R"({
1399 "command": "submit_multisigned",
1400 "Signers": [
1401 {
1402 "Signer": {
1403 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1404 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1405 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1406 }
1407 }
1408 ]
1409})",
1410 {{"Missing field 'secret'.",
1411 "Missing field 'secret'.",
1412 "Missing field 'account'.",
1413 "Missing field 'tx_json'."}}},
1414
1415 {"Missing sequence in submit_multisigned.",
1416 __LINE__,
1417 R"({
1418 "command": "submit_multisigned",
1419 "tx_json": {
1420 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1421 "Amount": "1000000000",
1422 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1423 "Fee": 50,
1424 "Signers": [
1425 {
1426 "Signer": {
1427 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1428 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1429 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1430 }
1431 }
1432 ],
1433 "SigningPubKey": "",
1434 "TransactionType": "Payment"
1435 }
1436})",
1437 {{"Missing field 'secret'.",
1438 "Missing field 'secret'.",
1439 "Missing field 'account'.",
1440 "Missing field 'tx_json.Sequence'."}}},
1441
1442 {"Missing SigningPubKey in submit_multisigned.",
1443 __LINE__,
1444 R"({
1445 "command": "submit_multisigned",
1446 "tx_json": {
1447 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1448 "Amount": "1000000000",
1449 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1450 "Fee": 50,
1451 "Signers": [
1452 {
1453 "Signer": {
1454 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1455 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1456 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1457 }
1458 }
1459 ],
1460 "Sequence": 0,
1461 "TransactionType": "Payment"
1462 }
1463})",
1464 {{"Missing field 'secret'.",
1465 "Missing field 'secret'.",
1466 "Missing field 'account'.",
1467 "Missing field 'tx_json.SigningPubKey'."}}},
1468
1469 {"Non-empty SigningPubKey in submit_multisigned.",
1470 __LINE__,
1471 R"({
1472 "command": "submit_multisigned",
1473 "tx_json": {
1474 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1475 "Amount": "1000000000",
1476 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1477 "Fee": 50,
1478 "Sequence": 0,
1479 "Signers": [
1480 {
1481 "Signer": {
1482 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1483 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1484 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1485 }
1486 }
1487 ],
1488 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8",
1489 "TransactionType": "Payment"
1490 }
1491})",
1492 {{"Missing field 'secret'.",
1493 "Missing field 'secret'.",
1494 "Missing field 'account'.",
1495 "When multi-signing 'tx_json.SigningPubKey' must be empty."}}},
1496
1497 {"Missing TransactionType in submit_multisigned.",
1498 __LINE__,
1499 R"({
1500 "command": "submit_multisigned",
1501 "tx_json": {
1502 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1503 "Amount": "1000000000",
1504 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1505 "Fee": 50,
1506 "Signers": [
1507 {
1508 "Signer": {
1509 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1510 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1511 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1512 }
1513 }
1514 ],
1515 "Sequence": 0,
1516 "SigningPubKey": "",
1517 }
1518})",
1519 {{"Missing field 'secret'.",
1520 "Missing field 'secret'.",
1521 "Missing field 'account'.",
1522 "Missing field 'tx_json.TransactionType'."}}},
1523
1524 {"Missing Account in submit_multisigned.",
1525 __LINE__,
1526 R"({
1527 "command": "submit_multisigned",
1528 "tx_json": {
1529 "Amount": "1000000000",
1530 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1531 "Fee": 50,
1532 "Sequence": 0,
1533 "Signers": [
1534 {
1535 "Signer": {
1536 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1537 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1538 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1539 }
1540 }
1541 ],
1542 "SigningPubKey": "",
1543 "TransactionType": "Payment"
1544 }
1545})",
1546 {{"Missing field 'secret'.",
1547 "Missing field 'secret'.",
1548 "Missing field 'account'.",
1549 "Missing field 'tx_json.Account'."}}},
1550
1551 {"Malformed Account in submit_multisigned.",
1552 __LINE__,
1553 R"({
1554 "command": "submit_multisigned",
1555 "tx_json": {
1556 "Account": "NotAnAccount",
1557 "Amount": "1000000000",
1558 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1559 "Fee": 50,
1560 "Sequence": 0,
1561 "Signers": [
1562 {
1563 "Signer": {
1564 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1565 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1566 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1567 }
1568 }
1569 ],
1570 "SigningPubKey": "",
1571 "TransactionType": "Payment"
1572 }
1573})",
1574 {{"Missing field 'secret'.",
1575 "Missing field 'secret'.",
1576 "Missing field 'account'.",
1577 "Invalid field 'tx_json.Account'."}}},
1578
1579 {"Account not in ledger in submit_multisigned.",
1580 __LINE__,
1581 R"({
1582 "command": "submit_multisigned",
1583 "tx_json": {
1584 "Account": "rDg53Haik2475DJx8bjMDSDPj4VX7htaMd",
1585 "Amount": "1000000000",
1586 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1587 "Fee": 50,
1588 "Sequence": 0,
1589 "Signers": [
1590 {
1591 "Signer": {
1592 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1593 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1594 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1595 }
1596 }
1597 ],
1598 "SigningPubKey": "",
1599 "TransactionType": "Payment"
1600 }
1601})",
1602 {{"Missing field 'secret'.",
1603 "Missing field 'secret'.",
1604 "Missing field 'account'.",
1605 "Source account not found."}}},
1606
1607 {"Missing Fee in submit_multisigned.",
1608 __LINE__,
1609 R"({
1610 "command": "submit_multisigned",
1611 "tx_json": {
1612 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1613 "Amount": "1000000000",
1614 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1615 "Sequence": 0,
1616 "Signers": [
1617 {
1618 "Signer": {
1619 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1620 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1621 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1622 }
1623 }
1624 ],
1625 "SigningPubKey": "",
1626 "TransactionType": "Payment"
1627 }
1628})",
1629 {{"Missing field 'secret'.",
1630 "Missing field 'secret'.",
1631 "Missing field 'account'.",
1632 "Missing field 'tx_json.Fee'."}}},
1633
1634 {"Non-numeric Fee in submit_multisigned.",
1635 __LINE__,
1636 R"({
1637 "command": "submit_multisigned",
1638 "tx_json": {
1639 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1640 "Amount": "1000000000",
1641 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1642 "Fee": 50.1,
1643 "Sequence": 0,
1644 "Signers": [
1645 {
1646 "Signer": {
1647 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1648 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1649 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1650 }
1651 }
1652 ],
1653 "SigningPubKey": "",
1654 "TransactionType": "Payment"
1655 }
1656})",
1657 {{"Missing field 'secret'.",
1658 "Missing field 'secret'.",
1659 "Missing field 'account'.",
1660 "Field 'tx_json.Fee' has invalid data."}}},
1661
1662 {"Missing Amount in submit_multisigned Payment.",
1663 __LINE__,
1664 R"({
1665 "command": "submit_multisigned",
1666 "tx_json": {
1667 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1668 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1669 "Fee": 50000000,
1670 "Sequence": 0,
1671 "Signers": [
1672 {
1673 "Signer": {
1674 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1675 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1676 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1677 }
1678 }
1679 ],
1680 "SigningPubKey": "",
1681 "TransactionType": "Payment"
1682 }
1683})",
1684 {{"Missing field 'secret'.",
1685 "Missing field 'secret'.",
1686 "Missing field 'account'.",
1687 "Missing field 'tx_json.Amount'."}}},
1688
1689 {"Invalid Amount in submit_multisigned Payment.",
1690 __LINE__,
1691 R"({
1692 "command": "submit_multisigned",
1693 "tx_json": {
1694 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1695 "Amount": "NotANumber",
1696 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1697 "Fee": 50,
1698 "Sequence": 0,
1699 "Signers": [
1700 {
1701 "Signer": {
1702 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1703 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1704 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1705 }
1706 }
1707 ],
1708 "SigningPubKey": "",
1709 "TransactionType": "Payment"
1710 }
1711})",
1712 {{"Missing field 'secret'.",
1713 "Missing field 'secret'.",
1714 "Missing field 'account'.",
1715 "Invalid field 'tx_json.Amount'."}}},
1716
1717 {"Invalid DeliverMax in submit_multisigned Payment.",
1718 __LINE__,
1719 R"({
1720 "command": "submit_multisigned",
1721 "tx_json": {
1722 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1723 "DeliverMax": "NotANumber",
1724 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1725 "Fee": 50,
1726 "Sequence": 0,
1727 "Signers": [
1728 {
1729 "Signer": {
1730 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1731 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1732 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1733 }
1734 }
1735 ],
1736 "SigningPubKey": "",
1737 "TransactionType": "Payment"
1738 }
1739})",
1740 {{"Missing field 'secret'.",
1741 "Missing field 'secret'.",
1742 "Missing field 'account'.",
1743 "Invalid field 'tx_json.Amount'."}}},
1744
1745 {"No build_path in submit_multisigned.",
1746 __LINE__,
1747 R"({
1748 "command": "submit_multisigned",
1749 "build_path": 1,
1750 "tx_json": {
1751 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1752 "Amount": "1000000000",
1753 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1754 "Fee": 50,
1755 "Sequence": 0,
1756 "Signers": [
1757 {
1758 "Signer": {
1759 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1760 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1761 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1762 }
1763 }
1764 ],
1765 "SigningPubKey": "",
1766 "TransactionType": "Payment"
1767 }
1768})",
1769 {{"Missing field 'secret'.",
1770 "Missing field 'secret'.",
1771 "Missing field 'account'.",
1772 "Field 'build_path' not allowed in this context."}}},
1773
1774 {"Missing Destination in submit_multisigned Payment.",
1775 __LINE__,
1776 R"({
1777 "command": "submit_multisigned",
1778 "tx_json": {
1779 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1780 "Amount": "1000000000",
1781 "Fee": 50,
1782 "Sequence": 0,
1783 "Signers": [
1784 {
1785 "Signer": {
1786 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1787 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1788 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1789 }
1790 }
1791 ],
1792 "SigningPubKey": "",
1793 "TransactionType": "Payment"
1794 }
1795})",
1796 {{"Missing field 'secret'.",
1797 "Missing field 'secret'.",
1798 "Missing field 'account'.",
1799 "Missing field 'tx_json.Destination'."}}},
1800
1801 {"Malformed Destination in submit_multisigned Payment.",
1802 __LINE__,
1803 R"({
1804 "command": "submit_multisigned",
1805 "tx_json": {
1806 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1807 "Amount": "1000000000",
1808 "Destination": "NotADestination",
1809 "Fee": 50,
1810 "Sequence": 0,
1811 "Signers": [
1812 {
1813 "Signer": {
1814 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1815 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1816 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1817 }
1818 }
1819 ],
1820 "SigningPubKey": "",
1821 "TransactionType": "Payment"
1822 }
1823})",
1824 {{"Missing field 'secret'.",
1825 "Missing field 'secret'.",
1826 "Missing field 'account'.",
1827 "Invalid field 'tx_json.Destination'."}}},
1828
1829 {"Missing Signers field in submit_multisigned.",
1830 __LINE__,
1831 R"({
1832 "command": "submit_multisigned",
1833 "tx_json": {
1834 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1835 "Amount": "1000000000",
1836 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1837 "Fee": 50,
1838 "Sequence": 0,
1839 "SigningPubKey": "",
1840 "TransactionType": "Payment"
1841 }
1842})",
1843 {{"Missing field 'secret'.",
1844 "Missing field 'secret'.",
1845 "Missing field 'account'.",
1846 "Missing field 'tx_json.Signers'."}}},
1847
1848 {"Signers not an array in submit_multisigned.",
1849 __LINE__,
1850 R"({
1851 "command": "submit_multisigned",
1852 "tx_json": {
1853 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1854 "Amount": "1000000000",
1855 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1856 "Fee": 50,
1857 "Sequence": 0,
1858 "Signers": {
1859 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1860 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1861 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1862 },
1863 "SigningPubKey": "",
1864 "TransactionType": "Payment"
1865 }
1866})",
1867 {{"Missing field 'secret'.",
1868 "Missing field 'secret'.",
1869 "Missing field 'account'.",
1870 "Field 'tx_json.Signers' is not a JSON array."}}},
1871
1872 {"Empty Signers array in submit_multisigned.",
1873 __LINE__,
1874 R"({
1875 "command": "submit_multisigned",
1876 "tx_json": {
1877 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1878 "Amount": "1000000000",
1879 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1880 "Fee": 50,
1881 "Sequence": 0,
1882 "Signers": [
1883 ],
1884 "SigningPubKey": "",
1885 "TransactionType": "Payment"
1886 }
1887})",
1888 {{"Missing field 'secret'.",
1889 "Missing field 'secret'.",
1890 "Missing field 'account'.",
1891 "tx_json.Signers array may not be empty."}}},
1892
1893 {"Duplicate Signer in submit_multisigned.",
1894 __LINE__,
1895 R"({
1896 "command": "submit_multisigned",
1897 "tx_json": {
1898 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1899 "Amount": "1000000000",
1900 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1901 "Fee": 50,
1902 "Sequence": 0,
1903 "Signers": [
1904 {
1905 "Signer": {
1906 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1907 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1908 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1909 }
1910 },
1911 {
1912 "Signer": {
1913 "Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
1914 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1915 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1916 }
1917 }
1918 ],
1919 "SigningPubKey": "",
1920 "TransactionType": "Payment"
1921 }
1922})",
1923 {{"Missing field 'secret'.",
1924 "Missing field 'secret'.",
1925 "Missing field 'account'.",
1926 "Duplicate Signers:Signer:Account entries "
1927 "(rPcNzota6B8YBokhYtcTNqQVCngtbnWfux) are not allowed."}}},
1928
1929 {"Signer is tx_json Account in submit_multisigned.",
1930 __LINE__,
1931 R"({
1932 "command": "submit_multisigned",
1933 "tx_json": {
1934 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1935 "Amount": "1000000000",
1936 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1937 "Fee": 50,
1938 "Sequence": 0,
1939 "Signers": [
1940 {
1941 "Signer": {
1942 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1943 "TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
1944 "SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
1945 }
1946 }
1947 ],
1948 "SigningPubKey": "",
1949 "TransactionType": "Payment"
1950 }
1951})",
1952 {{"Missing field 'secret'.",
1953 "Missing field 'secret'.",
1954 "Missing field 'account'.",
1955 "A Signer may not be the transaction's Account "
1956 "(rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh)."}}},
1957
1958 {"Empty Signers array in submit_multisigned, use DeliverMax",
1959 __LINE__,
1960 R"({
1961 "command": "submit_multisigned",
1962 "tx_json": {
1963 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1964 "DeliverMax": "10000000",
1965 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1966 "Fee": 50,
1967 "Sequence": 0,
1968 "Signers": [
1969 ],
1970 "SigningPubKey": "",
1971 "TransactionType": "Payment"
1972 }
1973})",
1974 {{"Missing field 'secret'.",
1975 "Missing field 'secret'.",
1976 "Missing field 'account'.",
1977 "tx_json.Signers array may not be empty."}}},
1978
1979 {"Empty Signers array in submit_multisigned, use DeliverMax and Amount",
1980 __LINE__,
1981 R"({
1982 "command": "submit_multisigned",
1983 "tx_json": {
1984 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
1985 "Amount": "10000000",
1986 "DeliverMax": "10000000",
1987 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
1988 "Fee": 50,
1989 "Sequence": 0,
1990 "Signers": [
1991 ],
1992 "SigningPubKey": "",
1993 "TransactionType": "Payment"
1994 }
1995})",
1996 {{"Missing field 'secret'.",
1997 "Missing field 'secret'.",
1998 "Missing field 'account'.",
1999 "tx_json.Signers array may not be empty."}}},
2000
2001 {"Payment cannot specify different DeliverMax and Amount.",
2002 __LINE__,
2003 R"({
2004 "command": "doesnt_matter",
2005 "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
2006 "secret": "masterpassphrase",
2007 "debug_signing": 0,
2008 "tx_json": {
2009 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
2010 "Amount": "1000000000",
2011 "DeliverMax": "1000000020",
2012 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
2013 "Fee": 50,
2014 "Sequence": 0,
2015 "SigningPubKey": "",
2016 "TransactionType": "Payment"
2017 }
2018})",
2019 {{"Cannot specify differing 'Amount' and 'DeliverMax'",
2020 "Cannot specify differing 'Amount' and 'DeliverMax'",
2021 "Cannot specify differing 'Amount' and 'DeliverMax'",
2022 "Cannot specify differing 'Amount' and 'DeliverMax'"}}},
2023
2024};
2025
2027{
2028public:
2029 void
2031 {
2032 test::jtx::Env env(*this);
2033 Json::Value const result{
2034 env.rpc("bad_command", R"({"MakingThisUp": 0})")};
2035
2036 BEAST_EXPECT(result[jss::result][jss::error] == "unknownCmd");
2037 BEAST_EXPECT(
2038 result[jss::result][jss::request][jss::command] == "bad_command");
2039 }
2040
2041 void
2043 {
2044 test::jtx::Env env(*this);
2045 auto ledger = env.current();
2046 auto const& feeTrack = env.app().getFeeTrack();
2047
2048 {
2049 Json::Value req;
2051 "{ \"fee_mult_max\" : 1, \"tx_json\" : { } } ", req);
2052 Json::Value result = checkFee(
2053 req,
2055 true,
2056 env.app().config(),
2057 feeTrack,
2058 env.app().getTxQ(),
2059 env.app());
2060
2061 BEAST_EXPECT(!RPC::contains_error(result));
2062 BEAST_EXPECT(
2063 req[jss::tx_json].isMember(jss::Fee) &&
2064 req[jss::tx_json][jss::Fee] == 10);
2065 }
2066
2067 {
2068 Json::Value req;
2070 "{ \"fee_mult_max\" : 3, \"fee_div_max\" : 2, "
2071 "\"tx_json\" : { } } ",
2072 req);
2073 Json::Value result = checkFee(
2074 req,
2076 true,
2077 env.app().config(),
2078 feeTrack,
2079 env.app().getTxQ(),
2080 env.app());
2081
2082 BEAST_EXPECT(!RPC::contains_error(result));
2083 BEAST_EXPECT(
2084 req[jss::tx_json].isMember(jss::Fee) &&
2085 req[jss::tx_json][jss::Fee] == 10);
2086 }
2087
2088 {
2089 Json::Value req;
2091 "{ \"fee_mult_max\" : 0, \"tx_json\" : { } } ", req);
2092 Json::Value result = checkFee(
2093 req,
2095 true,
2096 env.app().config(),
2097 feeTrack,
2098 env.app().getTxQ(),
2099 env.app());
2100
2101 BEAST_EXPECT(RPC::contains_error(result));
2102 BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee));
2103 }
2104
2105 {
2106 // 3/6 = 1/2, but use the bigger number make sure
2107 // we're dividing.
2108 Json::Value req;
2110 "{ \"fee_mult_max\" : 3, \"fee_div_max\" : 6, "
2111 "\"tx_json\" : { } } ",
2112 req);
2113 Json::Value result = checkFee(
2114 req,
2116 true,
2117 env.app().config(),
2118 feeTrack,
2119 env.app().getTxQ(),
2120 env.app());
2121
2122 BEAST_EXPECT(RPC::contains_error(result));
2123 BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee));
2124 }
2125
2126 {
2127 Json::Value req;
2129 "{ \"fee_mult_max\" : 0, \"fee_div_max\" : 2, "
2130 "\"tx_json\" : { } } ",
2131 req);
2132 Json::Value result = checkFee(
2133 req,
2135 true,
2136 env.app().config(),
2137 feeTrack,
2138 env.app().getTxQ(),
2139 env.app());
2140
2141 BEAST_EXPECT(RPC::contains_error(result));
2142 BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee));
2143 }
2144
2145 {
2146 Json::Value req;
2148 "{ \"fee_mult_max\" : 10, \"fee_div_max\" : 0, "
2149 "\"tx_json\" : { } } ",
2150 req);
2151 Json::Value result = checkFee(
2152 req,
2154 true,
2155 env.app().config(),
2156 feeTrack,
2157 env.app().getTxQ(),
2158 env.app());
2159
2160 BEAST_EXPECT(RPC::contains_error(result));
2161 BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee));
2162 }
2163 }
2164
2165 void
2167 {
2168 using namespace test::jtx;
2169 Env env{*this, envconfig([](std::unique_ptr<Config> cfg) {
2170 cfg->loadFromString("[" SECTION_SIGNING_SUPPORT "]\ntrue");
2171 cfg->section("transaction_queue")
2172 .set("minimum_txn_in_ledger_standalone", "3");
2173 return cfg;
2174 })};
2175 LoadFeeTrack const& feeTrackOuter = env.app().getFeeTrack();
2176
2177 {
2178 // high mult, no tx
2179 Json::Value req;
2181 R"({
2182 "fee_mult_max" : 1000,
2183 "tx_json" : { }
2184 })",
2185 req);
2186 Json::Value result = checkFee(
2187 req,
2189 true,
2190 env.app().config(),
2191 feeTrackOuter,
2192 env.app().getTxQ(),
2193 env.app());
2194
2195 BEAST_EXPECT(!RPC::contains_error(result));
2196 BEAST_EXPECT(
2197 req[jss::tx_json].isMember(jss::Fee) &&
2198 req[jss::tx_json][jss::Fee] == 10);
2199 }
2200
2201 {
2202 // low mult, no tx
2203 Json::Value req;
2205 R"({
2206 "fee_mult_max" : 5,
2207 "tx_json" : { }
2208 })",
2209 req);
2210 Json::Value result = checkFee(
2211 req,
2213 true,
2214 env.app().config(),
2215 feeTrackOuter,
2216 env.app().getTxQ(),
2217 env.app());
2218
2219 BEAST_EXPECT(!RPC::contains_error(result));
2220 BEAST_EXPECT(
2221 req[jss::tx_json].isMember(jss::Fee) &&
2222 req[jss::tx_json][jss::Fee] == 10);
2223 }
2224
2225 // put 4 transactions into the open ledger
2226 for (auto i = 0; i < 4; ++i)
2227 {
2228 env(noop(env.master));
2229 }
2230
2231 {
2232 // high mult, 4 txs
2233 Json::Value req;
2235 R"({
2236 "fee_mult_max" : 1000,
2237 "tx_json" : { }
2238 })",
2239 req);
2240 Json::Value result = checkFee(
2241 req,
2243 true,
2244 env.app().config(),
2245 feeTrackOuter,
2246 env.app().getTxQ(),
2247 env.app());
2248
2249 BEAST_EXPECT(!RPC::contains_error(result));
2250 BEAST_EXPECT(
2251 req[jss::tx_json].isMember(jss::Fee) &&
2252 req[jss::tx_json][jss::Fee] == 8889);
2253 }
2254
2255 {
2256 // low mult, 4 tx
2257 Json::Value req;
2259 R"({
2260 "fee_mult_max" : 5,
2261 "tx_json" : { }
2262 })",
2263 req);
2264 Json::Value result = checkFee(
2265 req,
2267 true,
2268 env.app().config(),
2269 feeTrackOuter,
2270 env.app().getTxQ(),
2271 env.app());
2272
2273 BEAST_EXPECT(RPC::contains_error(result));
2274 BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee));
2275 }
2276
2277 {
2278 // different low mult, 4 tx
2279 Json::Value req;
2281 R"({
2282 "fee_mult_max" : 1000,
2283 "fee_div_max" : 3,
2284 "tx_json" : { }
2285 })",
2286 req);
2287 Json::Value result = checkFee(
2288 req,
2290 true,
2291 env.app().config(),
2292 feeTrackOuter,
2293 env.app().getTxQ(),
2294 env.app());
2295
2296 BEAST_EXPECT(RPC::contains_error(result));
2297 BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee));
2298 }
2299
2300 {
2301 // high mult, 4 tx
2302 Json::Value req;
2304 R"({
2305 "fee_mult_max" : 8000,
2306 "fee_div_max" : 3,
2307 "tx_json" : { }
2308 })",
2309 req);
2310 Json::Value result = checkFee(
2311 req,
2313 true,
2314 env.app().config(),
2315 feeTrackOuter,
2316 env.app().getTxQ(),
2317 env.app());
2318
2319 BEAST_EXPECT(!RPC::contains_error(result));
2320 BEAST_EXPECT(
2321 req[jss::tx_json].isMember(jss::Fee) &&
2322 req[jss::tx_json][jss::Fee] == 8889);
2323 }
2324
2325 {
2326 // negative mult
2327 Json::Value req;
2329 R"({
2330 "fee_mult_max" : -5,
2331 "tx_json" : { }
2332 })",
2333 req);
2334 Json::Value result = checkFee(
2335 req,
2337 true,
2338 env.app().config(),
2339 feeTrackOuter,
2340 env.app().getTxQ(),
2341 env.app());
2342
2343 BEAST_EXPECT(RPC::contains_error(result));
2344 }
2345
2346 {
2347 // negative div
2348 Json::Value req;
2350 R"({
2351 "fee_div_max" : -2,
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 }
2366
2367 {
2368 // negative mult & div
2369 Json::Value req;
2371 R"({
2372 "fee_mult_max" : -2,
2373 "fee_div_max" : -3,
2374 "tx_json" : { }
2375 })",
2376 req);
2377 Json::Value result = checkFee(
2378 req,
2380 true,
2381 env.app().config(),
2382 feeTrackOuter,
2383 env.app().getTxQ(),
2384 env.app());
2385
2386 BEAST_EXPECT(RPC::contains_error(result));
2387 }
2388
2389 env.close();
2390
2391 {
2392 // Call "sign" with nothing in the open ledger
2393 Json::Value toSign;
2394 toSign[jss::tx_json] = noop(env.master);
2395 toSign[jss::secret] = "masterpassphrase";
2396 auto rpcResult = env.rpc("json", "sign", to_string(toSign));
2397 auto result = rpcResult[jss::result];
2398
2399 BEAST_EXPECT(!RPC::contains_error(result));
2400 BEAST_EXPECT(
2401 result[jss::tx_json].isMember(jss::Fee) &&
2402 result[jss::tx_json][jss::Fee] == "10");
2403 BEAST_EXPECT(
2404 result[jss::tx_json].isMember(jss::Sequence) &&
2405 result[jss::tx_json][jss::Sequence].isConvertibleTo(
2407 }
2408
2409 {
2410 // Call "sign" with enough transactions in the open ledger
2411 // to escalate the fee.
2412 for (;;)
2413 {
2414 auto metrics = env.app().getTxQ().getMetrics(*env.current());
2415 if (metrics.openLedgerFeeLevel > metrics.minProcessingFeeLevel)
2416 break;
2417 env(noop(env.master));
2418 }
2419
2420 Json::Value toSign;
2421 toSign[jss::tx_json] = noop(env.master);
2422 toSign[jss::secret] = "masterpassphrase";
2423 toSign[jss::fee_mult_max] = 900;
2424 auto rpcResult = env.rpc("json", "sign", to_string(toSign));
2425 auto result = rpcResult[jss::result];
2426
2427 BEAST_EXPECT(!RPC::contains_error(result));
2428 BEAST_EXPECT(
2429 result[jss::tx_json].isMember(jss::Fee) &&
2430 result[jss::tx_json][jss::Fee] == "7813");
2431 BEAST_EXPECT(
2432 result[jss::tx_json].isMember(jss::Sequence) &&
2433 result[jss::tx_json][jss::Sequence].isConvertibleTo(
2435
2436 env.close();
2437 }
2438
2439 {
2440 // Call "sign" with higher server load
2441 {
2442 auto& feeTrack = env.app().getFeeTrack();
2443 BEAST_EXPECT(feeTrack.getLoadFactor() == 256);
2444 for (int i = 0; i < 8; ++i)
2445 feeTrack.raiseLocalFee();
2446 BEAST_EXPECT(feeTrack.getLoadFactor() == 1220);
2447 }
2448
2449 Json::Value toSign;
2450 toSign[jss::tx_json] = noop(env.master);
2451 toSign[jss::secret] = "masterpassphrase";
2452 auto rpcResult = env.rpc("json", "sign", to_string(toSign));
2453 auto result = rpcResult[jss::result];
2454
2455 BEAST_EXPECT(!RPC::contains_error(result));
2456 BEAST_EXPECT(
2457 result[jss::tx_json].isMember(jss::Fee) &&
2458 result[jss::tx_json][jss::Fee] == "47");
2459 BEAST_EXPECT(
2460 result[jss::tx_json].isMember(jss::Sequence) &&
2461 result[jss::tx_json][jss::Sequence].isConvertibleTo(
2463 }
2464
2465 {
2466 // Call "sign" with higher server load and
2467 // enough transactions to escalate the fee
2468 BEAST_EXPECT(feeTrackOuter.getLoadFactor() == 1220);
2469
2470 for (;;)
2472 auto metrics = env.app().getTxQ().getMetrics(*env.current());
2473 if (metrics.openLedgerFeeLevel > metrics.minProcessingFeeLevel)
2474 break;
2475 env(noop(env.master), fee(47));
2476 }
2477
2478 Env_ss envs(env);
2479
2480 Json::Value toSign;
2481 toSign[jss::tx_json] = noop(env.master);
2482 toSign[jss::secret] = "masterpassphrase";
2483 // Max fee = 7000 drops
2484 toSign[jss::fee_mult_max] = 700;
2485 auto rpcResult = env.rpc("json", "sign", to_string(toSign));
2486 auto result = rpcResult[jss::result];
2487
2488 BEAST_EXPECT(!RPC::contains_error(result));
2489 BEAST_EXPECT(
2490 result[jss::tx_json].isMember(jss::Fee) &&
2491 result[jss::tx_json][jss::Fee] == "6806");
2492 BEAST_EXPECT(
2493 result[jss::tx_json].isMember(jss::Sequence) &&
2494 result[jss::tx_json][jss::Sequence].isConvertibleTo(
2496 }
2497 }
2498
2499 // A function that can be called as though it would process a transaction.
2500 static void
2503 bool,
2504 bool,
2506 {
2507 ;
2508 }
2509
2510 void
2512 {
2513 using namespace std::chrono_literals;
2514 // Use jtx to set up a ledger so the tests will do the right thing.
2515 test::jtx::Account const a{"a"}; // rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA
2516 test::jtx::Account const g{"g"}; // rLPwWB1itaUGMV8kbMLLysjGkEpTM2Soy4
2517 auto const USD = g["USD"];
2518
2519 // Account: rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi
2520 // seed: sh1yJfwoi98zCygwijUzuHmJDeVKd
2521 test::jtx::Account const ed{"ed", KeyType::ed25519};
2522 // master is rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh.
2523 // "b" (not in the ledger) is rDg53Haik2475DJx8bjMDSDPj4VX7htaMd.
2524 // "c" (phantom signer) is rPcNzota6B8YBokhYtcTNqQVCngtbnWfux.
2525
2526 test::jtx::Env env(*this);
2527 env.fund(test::jtx::XRP(100000), a, ed, g);
2528 env.close();
2529
2530 env(trust(a, USD(1000)));
2531 env(trust(env.master, USD(1000)));
2532 env(pay(g, a, USD(50)));
2533 env(pay(g, env.master, USD(50)));
2534 env.close();
2535
2537
2538 // A list of all the functions we want to test.
2539 using signFunc = Json::Value (*)(
2540 Json::Value params,
2541 unsigned int apiVersion,
2542 NetworkOPs::FailHard failType,
2543 Role role,
2544 std::chrono::seconds validatedLedgerAge,
2545 Application& app);
2546
2547 using submitFunc = Json::Value (*)(
2548 Json::Value params,
2549 unsigned int apiVersion,
2550 NetworkOPs::FailHard failType,
2551 Role role,
2552 std::chrono::seconds validatedLedgerAge,
2553 Application& app,
2554 ProcessTransactionFn const& processTransaction);
2555
2556 using TestStuff =
2558
2559 static TestStuff const testFuncs[] = {
2560 TestStuff{transactionSign, nullptr, "sign", 0},
2561 TestStuff{nullptr, transactionSubmit, "submit", 1},
2562 TestStuff{transactionSignFor, nullptr, "sign_for", 2},
2563 TestStuff{
2564 nullptr,
2566 "submit_multisigned",
2567 3}};
2568
2569 for (auto testFunc : testFuncs)
2570 {
2571 // For each JSON test.
2572 for (auto const& txnTest : txnTestArray)
2573 {
2574 Json::Value req;
2575 Json::Reader().parse(txnTest.json, req);
2576 if (RPC::contains_error(req))
2577 Throw<std::runtime_error>(
2578 "Internal JSONRPC_test error. Bad test JSON.");
2579
2580 static Role const testedRoles[] = {
2582
2583 for (Role testRole : testedRoles)
2584 {
2585 Json::Value result;
2586 auto const signFn = get<0>(testFunc);
2587 if (signFn != nullptr)
2588 {
2589 assert(get<1>(testFunc) == nullptr);
2590 result = signFn(
2591 req,
2592 1,
2594 testRole,
2595 1s,
2596 env.app());
2597 }
2598 else
2599 {
2600 auto const submitFn = get<1>(testFunc);
2601 assert(submitFn != nullptr);
2602 result = submitFn(
2603 req,
2606 testRole,
2607 1s,
2608 env.app(),
2609 processTxn);
2610 }
2611
2612 std::string errStr;
2613 if (RPC::contains_error(result))
2614 errStr = result["error_message"].asString();
2615
2616 if (errStr == txnTest.expMsg[get<3>(testFunc)])
2617 {
2618 pass();
2619 }
2620 else
2621 {
2622 std::ostringstream description;
2623 description << txnTest.description << " Called "
2624 << get<2>(testFunc) << "(). Got \'"
2625 << errStr << "\'";
2626 fail(description.str(), __FILE__, txnTest.line);
2627 }
2628 }
2629 }
2630 }
2631 }
2632
2633 void
2634 run() override
2635 {
2640 }
2641};
2642
2643BEAST_DEFINE_TESTSUITE(JSONRPC, ripple_app, ripple);
2644
2645} // namespace RPC
2646} // 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
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.
A transaction testing environment.
Definition: Env.h:117
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition: Env.h:325
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:749
@ 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:196
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
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:313
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