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