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