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