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 {"Minimal delegated transaction.",
2046 __LINE__,
2047 R"({
2048 "command": "doesnt_matter",
2049 "secret": "a",
2050 "tx_json": {
2051 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
2052 "Amount": "1000000000",
2053 "Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
2054 "TransactionType": "Payment",
2055 "Delegate": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA"
2056 }
2057})",
2058 {{"",
2059 "",
2060 "Missing field 'account'.",
2061 "Missing field 'tx_json.Sequence'."}}},
2062
2063 {"Delegate not well formed.",
2064 __LINE__,
2065 R"({
2066 "command": "doesnt_matter",
2067 "secret": "a",
2068 "tx_json": {
2069 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
2070 "Amount": "1000000000",
2071 "Destination": "rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi",
2072 "TransactionType": "Payment",
2073 "Delegate": "NotAnAccount"
2074 }
2075})",
2076 {{"Invalid field 'tx_json.Delegate'.",
2077 "Invalid field 'tx_json.Delegate'.",
2078 "Missing field 'account'.",
2079 "Missing field 'tx_json.Sequence'."}}},
2080
2081 {"Delegate not in ledger.",
2082 __LINE__,
2083 R"({
2084 "command": "doesnt_matter",
2085 "secret": "a",
2086 "tx_json": {
2087 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
2088 "Amount": "1000000000",
2089 "Destination": "rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi",
2090 "TransactionType": "Payment",
2091 "Delegate": "rDg53Haik2475DJx8bjMDSDPj4VX7htaMd"
2092 }
2093})",
2094 {{"Delegate account not found.",
2095 "Delegate account not found.",
2096 "Missing field 'account'.",
2097 "Missing field 'tx_json.Sequence'."}}},
2098
2099 {"Delegate and secret not match.",
2100 __LINE__,
2101 R"({
2102 "command": "doesnt_matter",
2103 "secret": "aa",
2104 "tx_json": {
2105 "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
2106 "Amount": "1000000000",
2107 "Destination": "rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi",
2108 "TransactionType": "Payment",
2109 "Delegate": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA"
2110 }
2111})",
2112 {{"Secret does not match account.",
2113 "Secret does not match account.",
2114 "Missing field 'account'.",
2115 "Missing field 'tx_json.Sequence'."}}},
2116
2117};
2118
2120{
2121public:
2122 void
2124 {
2125 testcase("bad RPC command");
2126 test::jtx::Env env(*this);
2127 Json::Value const result{
2128 env.rpc("bad_command", R"({"MakingThisUp": 0})")};
2129
2130 BEAST_EXPECT(result[jss::result][jss::error] == "unknownCmd");
2131 BEAST_EXPECT(
2132 result[jss::result][jss::request][jss::command] == "bad_command");
2133 }
2134
2135 void
2137 {
2138 testcase("autofill fails");
2139 using namespace test::jtx;
2140
2141 // test batch raw transactions max size
2142 {
2143 Env env(*this);
2144 auto ledger = env.current();
2145 auto const& feeTrack = env.app().getFeeTrack();
2146 Json::Value req;
2147 Account const alice("alice");
2148 Account const bob("bob");
2149 env.fund(XRP(100000), alice);
2150 env.close();
2151
2152 auto const batchFee = batch::calcBatchFee(env, 0, 2);
2153 auto const seq = env.seq(alice);
2154 auto jt = env.jtnofill(
2155 batch::outer(alice, env.seq(alice), batchFee, tfAllOrNothing),
2156 batch::inner(pay(alice, bob, XRP(1)), seq + 1),
2157 batch::inner(pay(alice, bob, XRP(2)), seq + 2),
2158 batch::inner(pay(alice, bob, XRP(3)), seq + 3),
2159 batch::inner(pay(alice, bob, XRP(4)), seq + 4),
2160 batch::inner(pay(alice, bob, XRP(5)), seq + 5),
2161 batch::inner(pay(alice, bob, XRP(6)), seq + 6),
2162 batch::inner(pay(alice, bob, XRP(7)), seq + 7),
2163 batch::inner(pay(alice, bob, XRP(8)), seq + 8),
2164 batch::inner(pay(alice, bob, XRP(9)), seq + 9));
2165
2166 jt.jv.removeMember(jss::Fee);
2167 jt.jv.removeMember(jss::TxnSignature);
2168 req[jss::tx_json] = jt.jv;
2169 Json::Value result = checkFee(
2170 req,
2172 true,
2173 env.app().config(),
2174 feeTrack,
2175 env.app().getTxQ(),
2176 env.app());
2177 BEAST_EXPECT(result.size() == 0);
2178 BEAST_EXPECT(
2179 req[jss::tx_json].isMember(jss::Fee) &&
2180 req[jss::tx_json][jss::Fee] ==
2181 env.current()->fees().base.jsonClipped());
2182 }
2183
2184 // test signers max size
2185 {
2186 Env env(*this);
2187 auto ledger = env.current();
2188 auto const& feeTrack = env.app().getFeeTrack();
2189 Json::Value req;
2190 Account const alice("alice");
2191 Account const bob("bob");
2192 env.fund(XRP(100000), alice, bob);
2193 env.close();
2194
2195 auto jt = env.jtnofill(
2196 noop(alice),
2197 msig(
2198 alice,
2199 alice,
2200 alice,
2201 alice,
2202 alice,
2203 alice,
2204 alice,
2205 alice,
2206 alice,
2207 alice,
2208 alice,
2209 alice,
2210 alice,
2211 alice,
2212 alice,
2213 alice,
2214 alice,
2215 alice,
2216 alice,
2217 alice,
2218 alice,
2219 alice,
2220 alice,
2221 alice,
2222 alice,
2223 alice,
2224 alice,
2225 alice,
2226 alice,
2227 alice,
2228 alice,
2229 alice,
2230 alice,
2231 alice,
2232 alice,
2233 alice,
2234 alice,
2235 alice,
2236 alice,
2237 alice));
2238
2239 req[jss::tx_json] = jt.jv;
2240 Json::Value result = checkFee(
2241 req,
2243 true,
2244 env.app().config(),
2245 feeTrack,
2246 env.app().getTxQ(),
2247 env.app());
2248 BEAST_EXPECT(result.size() == 0);
2249 BEAST_EXPECT(
2250 req[jss::tx_json].isMember(jss::Fee) &&
2251 req[jss::tx_json][jss::Fee] ==
2252 env.current()->fees().base.jsonClipped());
2253 }
2254 }
2255
2256 void
2258 {
2259 testcase("autofill fees");
2260 test::jtx::Env env(*this);
2261 auto const baseFee =
2262 static_cast<int>(env.current()->fees().base.drops());
2263 auto ledger = env.current();
2264 auto const& feeTrack = env.app().getFeeTrack();
2265
2266 {
2267 Json::Value req;
2269 "{ \"fee_mult_max\" : 1, \"tx_json\" : { } } ", req);
2270 Json::Value result = checkFee(
2271 req,
2273 true,
2274 env.app().config(),
2275 feeTrack,
2276 env.app().getTxQ(),
2277 env.app());
2278
2279 BEAST_EXPECT(!RPC::contains_error(result));
2280 BEAST_EXPECT(
2281 req[jss::tx_json].isMember(jss::Fee) &&
2282 req[jss::tx_json][jss::Fee] == baseFee);
2283 }
2284
2285 {
2286 Json::Value req;
2288 "{ \"fee_mult_max\" : 3, \"fee_div_max\" : 2, "
2289 "\"tx_json\" : { } } ",
2290 req);
2291 Json::Value result = checkFee(
2292 req,
2294 true,
2295 env.app().config(),
2296 feeTrack,
2297 env.app().getTxQ(),
2298 env.app());
2299
2300 BEAST_EXPECT(!RPC::contains_error(result));
2301 BEAST_EXPECT(
2302 req[jss::tx_json].isMember(jss::Fee) &&
2303 req[jss::tx_json][jss::Fee] == baseFee);
2304 }
2305
2306 {
2307 Json::Value req;
2309 "{ \"fee_mult_max\" : 0, \"tx_json\" : { } } ", req);
2310 Json::Value result = checkFee(
2311 req,
2313 true,
2314 env.app().config(),
2315 feeTrack,
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 // 3/6 = 1/2, but use the bigger number make sure
2325 // we're dividing.
2326 Json::Value req;
2328 "{ \"fee_mult_max\" : 3, \"fee_div_max\" : 6, "
2329 "\"tx_json\" : { } } ",
2330 req);
2331 Json::Value result = checkFee(
2332 req,
2334 true,
2335 env.app().config(),
2336 feeTrack,
2337 env.app().getTxQ(),
2338 env.app());
2339
2340 BEAST_EXPECT(RPC::contains_error(result));
2341 BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee));
2342 }
2343
2344 {
2345 Json::Value req;
2347 "{ \"fee_mult_max\" : 0, \"fee_div_max\" : 2, "
2348 "\"tx_json\" : { } } ",
2349 req);
2350 Json::Value result = checkFee(
2351 req,
2353 true,
2354 env.app().config(),
2355 feeTrack,
2356 env.app().getTxQ(),
2357 env.app());
2358
2359 BEAST_EXPECT(RPC::contains_error(result));
2360 BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee));
2361 }
2362
2363 {
2364 Json::Value req;
2366 "{ \"fee_mult_max\" : 10, \"fee_div_max\" : 0, "
2367 "\"tx_json\" : { } } ",
2368 req);
2369 Json::Value result = checkFee(
2370 req,
2372 true,
2373 env.app().config(),
2374 feeTrack,
2375 env.app().getTxQ(),
2376 env.app());
2377
2378 BEAST_EXPECT(RPC::contains_error(result));
2379 BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee));
2380 }
2381
2382 {
2383 // transaction with a higher base fee
2384 Json::Value req;
2385 test::jtx::Account const alice("alice");
2386 req[jss::tx_json] =
2387 test::jtx::acctdelete(env.master.human(), alice.human());
2388 Json::Value result = checkFee(
2389 req,
2391 true,
2392 env.app().config(),
2393 feeTrack,
2394 env.app().getTxQ(),
2395 env.app());
2396
2397 BEAST_EXPECT(result.size() == 0);
2398 BEAST_EXPECT(
2399 req[jss::tx_json].isMember(jss::Fee) &&
2400 req[jss::tx_json][jss::Fee] ==
2401 env.current()->fees().increment.jsonClipped());
2402 }
2403 }
2404
2405 void
2407 {
2408 testcase("autofill escalated fees");
2409 using namespace test::jtx;
2410 Env env{*this, envconfig([](std::unique_ptr<Config> cfg) {
2411 cfg->loadFromString("[" SECTION_SIGNING_SUPPORT "]\ntrue");
2412 cfg->section("transaction_queue")
2413 .set("minimum_txn_in_ledger_standalone", "3");
2414 return cfg;
2415 })};
2416 LoadFeeTrack const& feeTrackOuter = env.app().getFeeTrack();
2417
2418 {
2419 // high mult, no tx
2420 Json::Value req;
2422 R"({
2423 "fee_mult_max" : 1000,
2424 "tx_json" : { }
2425 })",
2426 req);
2427 Json::Value result = checkFee(
2428 req,
2430 true,
2431 env.app().config(),
2432 feeTrackOuter,
2433 env.app().getTxQ(),
2434 env.app());
2435
2436 BEAST_EXPECT(!RPC::contains_error(result));
2437 BEAST_EXPECT(
2438 req[jss::tx_json].isMember(jss::Fee) &&
2439 req[jss::tx_json][jss::Fee] == 10);
2440 }
2441
2442 {
2443 // low mult, no tx
2444 Json::Value req;
2446 R"({
2447 "fee_mult_max" : 5,
2448 "tx_json" : { }
2449 })",
2450 req);
2451 Json::Value result = checkFee(
2452 req,
2454 true,
2455 env.app().config(),
2456 feeTrackOuter,
2457 env.app().getTxQ(),
2458 env.app());
2459
2460 BEAST_EXPECT(!RPC::contains_error(result));
2461 BEAST_EXPECT(
2462 req[jss::tx_json].isMember(jss::Fee) &&
2463 req[jss::tx_json][jss::Fee] == 10);
2464 }
2465
2466 // put 4 transactions into the open ledger
2467 for (auto i = 0; i < 4; ++i)
2468 {
2469 env(noop(env.master));
2470 }
2471
2472 {
2473 // high mult, 4 txs
2474 Json::Value req;
2476 R"({
2477 "fee_mult_max" : 1000,
2478 "tx_json" : { }
2479 })",
2480 req);
2481 Json::Value result = checkFee(
2482 req,
2484 true,
2485 env.app().config(),
2486 feeTrackOuter,
2487 env.app().getTxQ(),
2488 env.app());
2489
2490 BEAST_EXPECT(!RPC::contains_error(result));
2491 BEAST_EXPECT(
2492 req[jss::tx_json].isMember(jss::Fee) &&
2493 req[jss::tx_json][jss::Fee] == 8889);
2494 }
2495
2496 {
2497 // low mult, 4 tx
2498 Json::Value req;
2500 R"({
2501 "fee_mult_max" : 5,
2502 "tx_json" : { }
2503 })",
2504 req);
2505 Json::Value result = checkFee(
2506 req,
2508 true,
2509 env.app().config(),
2510 feeTrackOuter,
2511 env.app().getTxQ(),
2512 env.app());
2513
2514 BEAST_EXPECT(RPC::contains_error(result));
2515 BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee));
2516 }
2517
2518 {
2519 // different low mult, 4 tx
2520 Json::Value req;
2522 R"({
2523 "fee_mult_max" : 1000,
2524 "fee_div_max" : 3,
2525 "tx_json" : { }
2526 })",
2527 req);
2528 Json::Value result = checkFee(
2529 req,
2531 true,
2532 env.app().config(),
2533 feeTrackOuter,
2534 env.app().getTxQ(),
2535 env.app());
2536
2537 BEAST_EXPECT(RPC::contains_error(result));
2538 BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee));
2539 }
2540
2541 {
2542 // high mult, 4 tx
2543 Json::Value req;
2545 R"({
2546 "fee_mult_max" : 8000,
2547 "fee_div_max" : 3,
2548 "tx_json" : { }
2549 })",
2550 req);
2551 Json::Value result = checkFee(
2552 req,
2554 true,
2555 env.app().config(),
2556 feeTrackOuter,
2557 env.app().getTxQ(),
2558 env.app());
2559
2560 BEAST_EXPECT(!RPC::contains_error(result));
2561 BEAST_EXPECT(
2562 req[jss::tx_json].isMember(jss::Fee) &&
2563 req[jss::tx_json][jss::Fee] == 8889);
2564 }
2565
2566 {
2567 // negative mult
2568 Json::Value req;
2570 R"({
2571 "fee_mult_max" : -5,
2572 "tx_json" : { }
2573 })",
2574 req);
2575 Json::Value result = checkFee(
2576 req,
2578 true,
2579 env.app().config(),
2580 feeTrackOuter,
2581 env.app().getTxQ(),
2582 env.app());
2583
2584 BEAST_EXPECT(RPC::contains_error(result));
2585 }
2586
2587 {
2588 // negative div
2589 Json::Value req;
2591 R"({
2592 "fee_div_max" : -2,
2593 "tx_json" : { }
2594 })",
2595 req);
2596 Json::Value result = checkFee(
2597 req,
2599 true,
2600 env.app().config(),
2601 feeTrackOuter,
2602 env.app().getTxQ(),
2603 env.app());
2604
2605 BEAST_EXPECT(RPC::contains_error(result));
2606 }
2607
2608 {
2609 // negative mult & div
2610 Json::Value req;
2612 R"({
2613 "fee_mult_max" : -2,
2614 "fee_div_max" : -3,
2615 "tx_json" : { }
2616 })",
2617 req);
2618 Json::Value result = checkFee(
2619 req,
2621 true,
2622 env.app().config(),
2623 feeTrackOuter,
2624 env.app().getTxQ(),
2625 env.app());
2626
2627 BEAST_EXPECT(RPC::contains_error(result));
2628 }
2629
2630 env.close();
2631
2632 {
2633 // Call "sign" with nothing in the open ledger
2634 Json::Value toSign;
2635 toSign[jss::tx_json] = noop(env.master);
2636 toSign[jss::secret] = "masterpassphrase";
2637 auto rpcResult = env.rpc("json", "sign", to_string(toSign));
2638 auto result = rpcResult[jss::result];
2639
2640 BEAST_EXPECT(!RPC::contains_error(result));
2641 BEAST_EXPECT(
2642 result[jss::tx_json].isMember(jss::Fee) &&
2643 result[jss::tx_json][jss::Fee] == "10");
2644 BEAST_EXPECT(
2645 result[jss::tx_json].isMember(jss::Sequence) &&
2646 result[jss::tx_json][jss::Sequence].isConvertibleTo(
2648 }
2649
2650 {
2651 // Call "sign" with enough transactions in the open ledger
2652 // to escalate the fee.
2653 for (;;)
2654 {
2655 auto metrics = env.app().getTxQ().getMetrics(*env.current());
2656 if (metrics.openLedgerFeeLevel > metrics.minProcessingFeeLevel)
2657 break;
2658 env(noop(env.master));
2659 }
2660
2661 Json::Value toSign;
2662 toSign[jss::tx_json] = noop(env.master);
2663 toSign[jss::secret] = "masterpassphrase";
2664 toSign[jss::fee_mult_max] = 900;
2665 auto rpcResult = env.rpc("json", "sign", to_string(toSign));
2666 auto result = rpcResult[jss::result];
2667
2668 BEAST_EXPECT(!RPC::contains_error(result));
2669 BEAST_EXPECT(
2670 result[jss::tx_json].isMember(jss::Fee) &&
2671 result[jss::tx_json][jss::Fee] == "7813");
2672 BEAST_EXPECT(
2673 result[jss::tx_json].isMember(jss::Sequence) &&
2674 result[jss::tx_json][jss::Sequence].isConvertibleTo(
2676
2677 env.close();
2678 }
2679
2680 {
2681 // Call "sign" with higher server load
2682 {
2683 auto& feeTrack = env.app().getFeeTrack();
2684 BEAST_EXPECT(feeTrack.getLoadFactor() == 256);
2685 for (int i = 0; i < 8; ++i)
2686 feeTrack.raiseLocalFee();
2687 BEAST_EXPECT(feeTrack.getLoadFactor() == 1220);
2688 }
2689
2690 Json::Value toSign;
2691 toSign[jss::tx_json] = noop(env.master);
2692 toSign[jss::secret] = "masterpassphrase";
2693 auto rpcResult = env.rpc("json", "sign", to_string(toSign));
2694 auto result = rpcResult[jss::result];
2695
2696 BEAST_EXPECT(!RPC::contains_error(result));
2697 BEAST_EXPECT(
2698 result[jss::tx_json].isMember(jss::Fee) &&
2699 result[jss::tx_json][jss::Fee] == "47");
2700 BEAST_EXPECT(
2701 result[jss::tx_json].isMember(jss::Sequence) &&
2702 result[jss::tx_json][jss::Sequence].isConvertibleTo(
2704 }
2705
2706 {
2707 // Call "sign" with higher server load and
2708 // enough transactions to escalate the fee
2709 BEAST_EXPECT(feeTrackOuter.getLoadFactor() == 1220);
2710
2711 for (;;)
2712 {
2713 auto metrics = env.app().getTxQ().getMetrics(*env.current());
2714 if (metrics.openLedgerFeeLevel > metrics.minProcessingFeeLevel)
2715 break;
2716 env(noop(env.master), fee(47));
2717 }
2718
2719 Env_ss envs(env);
2720
2721 Json::Value toSign;
2722 toSign[jss::tx_json] = noop(env.master);
2723 toSign[jss::secret] = "masterpassphrase";
2724 // Max fee = 7000 drops
2725 toSign[jss::fee_mult_max] = 700;
2726 auto rpcResult = env.rpc("json", "sign", to_string(toSign));
2727 auto result = rpcResult[jss::result];
2728
2729 BEAST_EXPECT(!RPC::contains_error(result));
2730 BEAST_EXPECT(
2731 result[jss::tx_json].isMember(jss::Fee) &&
2732 result[jss::tx_json][jss::Fee] == "6806");
2733 BEAST_EXPECT(
2734 result[jss::tx_json].isMember(jss::Sequence) &&
2735 result[jss::tx_json][jss::Sequence].isConvertibleTo(
2737 }
2739
2740 void
2742 {
2743 testcase("autofill NetworkID");
2744 using namespace test::jtx;
2745 Env env{*this, envconfig([&](std::unique_ptr<Config> cfg) {
2746 cfg->NETWORK_ID = 1025;
2747 return cfg;
2748 })};
2749
2750 {
2751 Json::Value toSign;
2752 toSign[jss::tx_json] = noop(env.master);
2753
2754 BEAST_EXPECT(!toSign[jss::tx_json].isMember(jss::NetworkID));
2755 toSign[jss::secret] = "masterpassphrase";
2756 auto rpcResult = env.rpc("json", "sign", to_string(toSign));
2757 auto result = rpcResult[jss::result];
2758
2759 BEAST_EXPECT(!RPC::contains_error(result));
2760 BEAST_EXPECT(
2761 result[jss::tx_json].isMember(jss::NetworkID) &&
2762 result[jss::tx_json][jss::NetworkID] == 1025);
2763 }
2764 }
2765
2766 // A function that can be called as though it would process a transaction.
2767 static void
2770 bool,
2771 bool,
2773 {
2774 ;
2775 }
2776
2777 void
2779 {
2780 testcase("sign/submit RPCs");
2781 using namespace std::chrono_literals;
2782 using namespace test::jtx;
2783 // Use jtx to set up a ledger so the tests will do the right thing.
2784 Account const a{"a"}; // rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA
2785 Account const g{"g"}; // rLPwWB1itaUGMV8kbMLLysjGkEpTM2Soy4
2786 auto const USD = g["USD"];
2787
2788 // Account: rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi
2789 // seed: sh1yJfwoi98zCygwijUzuHmJDeVKd
2790 Account const ed{"ed", KeyType::ed25519};
2791 // master is rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh.
2792 // "b" (not in the ledger) is rDg53Haik2475DJx8bjMDSDPj4VX7htaMd.
2793 // "c" (phantom signer) is rPcNzota6B8YBokhYtcTNqQVCngtbnWfux.
2794
2795 Env env(*this, envconfig([](std::unique_ptr<Config> cfg) {
2796 cfg->FEES.reference_fee = 10;
2797 return cfg;
2798 }));
2799 env.fund(XRP(100000), a, ed, g);
2800 env.close();
2801
2802 env(trust(a, USD(1000)));
2803 env(trust(env.master, USD(1000)));
2804 env(pay(g, a, USD(50)));
2805 env(pay(g, env.master, USD(50)));
2806 env.close();
2807
2809
2810 // A list of all the functions we want to test.
2811 using signFunc = Json::Value (*)(
2812 Json::Value params,
2813 unsigned int apiVersion,
2814 NetworkOPs::FailHard failType,
2815 Role role,
2816 std::chrono::seconds validatedLedgerAge,
2817 Application& app);
2818
2819 using submitFunc = Json::Value (*)(
2820 Json::Value params,
2821 unsigned int apiVersion,
2822 NetworkOPs::FailHard failType,
2823 Role role,
2824 std::chrono::seconds validatedLedgerAge,
2825 Application& app,
2826 ProcessTransactionFn const& processTransaction);
2827
2828 using TestStuff =
2830
2831 static TestStuff const testFuncs[] = {
2832 TestStuff{transactionSign, nullptr, "sign", 0},
2833 TestStuff{nullptr, transactionSubmit, "submit", 1},
2834 TestStuff{transactionSignFor, nullptr, "sign_for", 2},
2835 TestStuff{
2836 nullptr,
2838 "submit_multisigned",
2839 3}};
2840
2841 for (auto testFunc : testFuncs)
2842 {
2843 // For each JSON test.
2844 for (auto const& txnTest : txnTestArray)
2845 {
2846 Json::Value req;
2847 Json::Reader().parse(txnTest.json, req);
2848 if (RPC::contains_error(req))
2849 Throw<std::runtime_error>(
2850 "Internal JSONRPC_test error. Bad test JSON.");
2851
2852 static Role const testedRoles[] = {
2854
2855 for (Role testRole : testedRoles)
2856 {
2857 Json::Value result;
2858 auto const signFn = get<0>(testFunc);
2859 if (signFn != nullptr)
2860 {
2861 assert(get<1>(testFunc) == nullptr);
2862 result = signFn(
2863 req,
2864 1,
2866 testRole,
2867 1s,
2868 env.app());
2869 }
2870 else
2871 {
2872 auto const submitFn = get<1>(testFunc);
2873 assert(submitFn != nullptr);
2874 result = submitFn(
2875 req,
2878 testRole,
2879 1s,
2880 env.app(),
2881 processTxn);
2882 }
2883
2884 std::string errStr;
2885 if (RPC::contains_error(result))
2886 errStr = result["error_message"].asString();
2887
2888 if (errStr == txnTest.expMsg[get<3>(testFunc)])
2889 {
2890 pass();
2891 }
2892 else
2893 {
2894 std::ostringstream description;
2895 description << txnTest.description << " Called "
2896 << get<2>(testFunc) << "(). Got \'"
2897 << errStr << "\'";
2898 fail(description.str(), __FILE__, txnTest.line);
2899 }
2900 }
2901 }
2902 }
2903 }
2904
2905 void
2906 run() override
2907 {
2914 }
2915};
2916
2917BEAST_DEFINE_TESTSUITE(JSONRPC, ripple_app, ripple);
2918
2919} // namespace RPC
2920} // namespace ripple
Unserialize a JSON document into a Value.
Definition: json_reader.h:39
bool parse(std::string const &document, Value &root)
Read a Value from a JSON document.
Definition: json_reader.cpp:78
Represents a JSON value.
Definition: json_value.h:150
UInt size() const
Number of values in array or object.
Definition: json_value.cpp:719
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:482
A testsuite class.
Definition: suite.h:55
void pass()
Record a successful test condition.
Definition: suite.h:511
testcase_t testcase
Memberspace for declaring test cases.
Definition: suite.h:155
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition: suite.h:533
virtual Config & config()=0
virtual LoadFeeTrack & getFeeTrack()=0
virtual TxQ & getTxQ()=0
Manages the current fee schedule.
Definition: LoadFeeTrack.h:45
std::uint32_t getLoadFactor() const
Definition: LoadFeeTrack.h:95
static void fakeProcessTransaction(std::shared_ptr< Transaction > &, bool, bool, NetworkOPs::FailHard)
void run() override
Runs the suite.
Immutable cryptographic account descriptor.
Definition: Account.h:39
std::string const & human() const
Returns the human readable public key.
Definition: Account.h:114
A transaction testing environment.
Definition: Env.h:121
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition: Env.h:331
Account const & master
Definition: Env.h:125
Application & app()
Definition: Env.h:261
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Definition: Env.h:773
@ uintValue
unsigned integer value
Definition: json_value.h:41
Json::Value transactionSign(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app)
Returns a Json::objectValue.
std::function< void(std::shared_ptr< Transaction > &transaction, bool bUnlimited, bool bLocal, NetworkOPs::FailHard failType)> ProcessTransactionFn
bool contains_error(Json::Value const &json)
Returns true if the json contains an rpc error specification.
Definition: ErrorCodes.cpp:203
Json::Value transactionSubmitMultiSigned(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app, ProcessTransactionFn const &processTransaction)
Returns a Json::objectValue.
static constexpr std::integral_constant< unsigned, Version > apiVersion
Definition: ApiVersion.h:54
Json::Value transactionSubmit(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app, ProcessTransactionFn const &processTransaction)
Returns a Json::objectValue.
Json::Value transactionSignFor(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app)
Returns a Json::objectValue.
static constexpr TxnTestData txnTestArray[]
Json::Value checkFee(Json::Value &request, Role const role, bool doAutoFill, Config const &config, LoadFeeTrack const &feeTrack, TxQ const &txQ, Application const &app)
Fill in the fee on behalf of the client.
Json::Value trust(AccountID const &account, STAmount const &amount, std::uint32_t flags=0)
Definition: AMM.cpp:805
Json::Value pay(Account const &account, AccountID const &to, STAmount const &amount)
Definition: AMM.cpp:817
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition: envconfig.h:54
Json::Value acctdelete(Account const &account, Account const &dest)
Delete account.
Definition: acctdelete.cpp:31
XRP_t const XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:105
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
constexpr std::uint32_t tfAllOrNothing
Definition: TxFlags.h:246
bool set(T &target, std::string const &name, Section const &section)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
Definition: BasicConfig.h:315
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:630
Role
Indicates the level of administrative permission to grant.
Definition: Role.h:44
T str(T... args)
TxnTestData(TxnTestData const &)=delete
std::array< char const *const, 4 > const expMsg
TxnTestData & operator=(TxnTestData &&)=delete
TxnTestData & operator=(TxnTestData const &)=delete
constexpr TxnTestData(char const *description_, int line_, char const *json_, std::array< char const *const, 4 > const &expMsg_)
char const *const description
TxnTestData(TxnTestData &&)=delete
char const *const json