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