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 fees");
2139 test::jtx::Env env(*this);
2140 auto const baseFee =
2141 static_cast<int>(env.current()->fees().base.drops());
2142 auto ledger = env.current();
2143 auto const& feeTrack = env.app().getFeeTrack();
2144
2145 {
2146 Json::Value req;
2148 "{ \"fee_mult_max\" : 1, \"tx_json\" : { } } ", req);
2149 Json::Value result = checkFee(
2150 req,
2152 true,
2153 env.app().config(),
2154 feeTrack,
2155 env.app().getTxQ(),
2156 env.app());
2157
2158 BEAST_EXPECT(!RPC::contains_error(result));
2159 BEAST_EXPECT(
2160 req[jss::tx_json].isMember(jss::Fee) &&
2161 req[jss::tx_json][jss::Fee] == baseFee);
2162 }
2163
2164 {
2165 Json::Value req;
2167 "{ \"fee_mult_max\" : 3, \"fee_div_max\" : 2, "
2168 "\"tx_json\" : { } } ",
2169 req);
2170 Json::Value result = checkFee(
2171 req,
2173 true,
2174 env.app().config(),
2175 feeTrack,
2176 env.app().getTxQ(),
2177 env.app());
2178
2179 BEAST_EXPECT(!RPC::contains_error(result));
2180 BEAST_EXPECT(
2181 req[jss::tx_json].isMember(jss::Fee) &&
2182 req[jss::tx_json][jss::Fee] == baseFee);
2183 }
2184
2185 {
2186 Json::Value req;
2188 "{ \"fee_mult_max\" : 0, \"tx_json\" : { } } ", req);
2189 Json::Value result = checkFee(
2190 req,
2192 true,
2193 env.app().config(),
2194 feeTrack,
2195 env.app().getTxQ(),
2196 env.app());
2197
2198 BEAST_EXPECT(RPC::contains_error(result));
2199 BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee));
2200 }
2201
2202 {
2203 // 3/6 = 1/2, but use the bigger number make sure
2204 // we're dividing.
2205 Json::Value req;
2207 "{ \"fee_mult_max\" : 3, \"fee_div_max\" : 6, "
2208 "\"tx_json\" : { } } ",
2209 req);
2210 Json::Value result = checkFee(
2211 req,
2213 true,
2214 env.app().config(),
2215 feeTrack,
2216 env.app().getTxQ(),
2217 env.app());
2218
2219 BEAST_EXPECT(RPC::contains_error(result));
2220 BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee));
2221 }
2222
2223 {
2224 Json::Value req;
2226 "{ \"fee_mult_max\" : 0, \"fee_div_max\" : 2, "
2227 "\"tx_json\" : { } } ",
2228 req);
2229 Json::Value result = checkFee(
2230 req,
2232 true,
2233 env.app().config(),
2234 feeTrack,
2235 env.app().getTxQ(),
2236 env.app());
2237
2238 BEAST_EXPECT(RPC::contains_error(result));
2239 BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee));
2240 }
2241
2242 {
2243 Json::Value req;
2245 "{ \"fee_mult_max\" : 10, \"fee_div_max\" : 0, "
2246 "\"tx_json\" : { } } ",
2247 req);
2248 Json::Value result = checkFee(
2249 req,
2251 true,
2252 env.app().config(),
2253 feeTrack,
2254 env.app().getTxQ(),
2255 env.app());
2256
2257 BEAST_EXPECT(RPC::contains_error(result));
2258 BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee));
2259 }
2260
2261 {
2262 // transaction with a higher base fee
2263 Json::Value req;
2264 test::jtx::Account const alice("alice");
2265 req[jss::tx_json] =
2266 test::jtx::acctdelete(env.master.human(), alice.human());
2267 Json::Value result = checkFee(
2268 req,
2270 true,
2271 env.app().config(),
2272 feeTrack,
2273 env.app().getTxQ(),
2274 env.app());
2275
2276 BEAST_EXPECT(result.size() == 0);
2277 BEAST_EXPECT(
2278 req[jss::tx_json].isMember(jss::Fee) &&
2279 req[jss::tx_json][jss::Fee] ==
2280 env.current()->fees().increment.jsonClipped());
2281 }
2282 }
2283
2284 void
2286 {
2287 testcase("autofill escalated fees");
2288 using namespace test::jtx;
2289 Env env{*this, envconfig([](std::unique_ptr<Config> cfg) {
2290 cfg->loadFromString("[" SECTION_SIGNING_SUPPORT "]\ntrue");
2291 cfg->section("transaction_queue")
2292 .set("minimum_txn_in_ledger_standalone", "3");
2293 return cfg;
2294 })};
2295 LoadFeeTrack const& feeTrackOuter = env.app().getFeeTrack();
2296
2297 {
2298 // high mult, no tx
2299 Json::Value req;
2301 R"({
2302 "fee_mult_max" : 1000,
2303 "tx_json" : { }
2304 })",
2305 req);
2306 Json::Value result = checkFee(
2307 req,
2309 true,
2310 env.app().config(),
2311 feeTrackOuter,
2312 env.app().getTxQ(),
2313 env.app());
2314
2315 BEAST_EXPECT(!RPC::contains_error(result));
2316 BEAST_EXPECT(
2317 req[jss::tx_json].isMember(jss::Fee) &&
2318 req[jss::tx_json][jss::Fee] == 10);
2319 }
2320
2321 {
2322 // low mult, no tx
2323 Json::Value req;
2325 R"({
2326 "fee_mult_max" : 5,
2327 "tx_json" : { }
2328 })",
2329 req);
2330 Json::Value result = checkFee(
2331 req,
2333 true,
2334 env.app().config(),
2335 feeTrackOuter,
2336 env.app().getTxQ(),
2337 env.app());
2338
2339 BEAST_EXPECT(!RPC::contains_error(result));
2340 BEAST_EXPECT(
2341 req[jss::tx_json].isMember(jss::Fee) &&
2342 req[jss::tx_json][jss::Fee] == 10);
2343 }
2344
2345 // put 4 transactions into the open ledger
2346 for (auto i = 0; i < 4; ++i)
2347 {
2348 env(noop(env.master));
2349 }
2350
2351 {
2352 // high mult, 4 txs
2353 Json::Value req;
2355 R"({
2356 "fee_mult_max" : 1000,
2357 "tx_json" : { }
2358 })",
2359 req);
2360 Json::Value result = checkFee(
2361 req,
2363 true,
2364 env.app().config(),
2365 feeTrackOuter,
2366 env.app().getTxQ(),
2367 env.app());
2368
2369 BEAST_EXPECT(!RPC::contains_error(result));
2370 BEAST_EXPECT(
2371 req[jss::tx_json].isMember(jss::Fee) &&
2372 req[jss::tx_json][jss::Fee] == 8889);
2373 }
2374
2375 {
2376 // low mult, 4 tx
2377 Json::Value req;
2379 R"({
2380 "fee_mult_max" : 5,
2381 "tx_json" : { }
2382 })",
2383 req);
2384 Json::Value result = checkFee(
2385 req,
2387 true,
2388 env.app().config(),
2389 feeTrackOuter,
2390 env.app().getTxQ(),
2391 env.app());
2392
2393 BEAST_EXPECT(RPC::contains_error(result));
2394 BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee));
2395 }
2396
2397 {
2398 // different low mult, 4 tx
2399 Json::Value req;
2401 R"({
2402 "fee_mult_max" : 1000,
2403 "fee_div_max" : 3,
2404 "tx_json" : { }
2405 })",
2406 req);
2407 Json::Value result = checkFee(
2408 req,
2410 true,
2411 env.app().config(),
2412 feeTrackOuter,
2413 env.app().getTxQ(),
2414 env.app());
2415
2416 BEAST_EXPECT(RPC::contains_error(result));
2417 BEAST_EXPECT(!req[jss::tx_json].isMember(jss::Fee));
2418 }
2419
2420 {
2421 // high mult, 4 tx
2422 Json::Value req;
2424 R"({
2425 "fee_mult_max" : 8000,
2426 "fee_div_max" : 3,
2427 "tx_json" : { }
2428 })",
2429 req);
2430 Json::Value result = checkFee(
2431 req,
2433 true,
2434 env.app().config(),
2435 feeTrackOuter,
2436 env.app().getTxQ(),
2437 env.app());
2438
2439 BEAST_EXPECT(!RPC::contains_error(result));
2440 BEAST_EXPECT(
2441 req[jss::tx_json].isMember(jss::Fee) &&
2442 req[jss::tx_json][jss::Fee] == 8889);
2443 }
2444
2445 {
2446 // negative mult
2447 Json::Value req;
2449 R"({
2450 "fee_mult_max" : -5,
2451 "tx_json" : { }
2452 })",
2453 req);
2454 Json::Value result = checkFee(
2455 req,
2457 true,
2458 env.app().config(),
2459 feeTrackOuter,
2460 env.app().getTxQ(),
2461 env.app());
2462
2463 BEAST_EXPECT(RPC::contains_error(result));
2464 }
2465
2466 {
2467 // negative div
2468 Json::Value req;
2470 R"({
2471 "fee_div_max" : -2,
2472 "tx_json" : { }
2473 })",
2474 req);
2475 Json::Value result = checkFee(
2476 req,
2478 true,
2479 env.app().config(),
2480 feeTrackOuter,
2481 env.app().getTxQ(),
2482 env.app());
2483
2484 BEAST_EXPECT(RPC::contains_error(result));
2485 }
2486
2487 {
2488 // negative mult & div
2489 Json::Value req;
2491 R"({
2492 "fee_mult_max" : -2,
2493 "fee_div_max" : -3,
2494 "tx_json" : { }
2495 })",
2496 req);
2497 Json::Value result = checkFee(
2498 req,
2500 true,
2501 env.app().config(),
2502 feeTrackOuter,
2503 env.app().getTxQ(),
2504 env.app());
2505
2506 BEAST_EXPECT(RPC::contains_error(result));
2507 }
2508
2509 env.close();
2510
2511 {
2512 // Call "sign" with nothing in the open ledger
2513 Json::Value toSign;
2514 toSign[jss::tx_json] = noop(env.master);
2515 toSign[jss::secret] = "masterpassphrase";
2516 auto rpcResult = env.rpc("json", "sign", to_string(toSign));
2517 auto result = rpcResult[jss::result];
2518
2519 BEAST_EXPECT(!RPC::contains_error(result));
2520 BEAST_EXPECT(
2521 result[jss::tx_json].isMember(jss::Fee) &&
2522 result[jss::tx_json][jss::Fee] == "10");
2523 BEAST_EXPECT(
2524 result[jss::tx_json].isMember(jss::Sequence) &&
2525 result[jss::tx_json][jss::Sequence].isConvertibleTo(
2527 }
2528
2529 {
2530 // Call "sign" with enough transactions in the open ledger
2531 // to escalate the fee.
2532 for (;;)
2533 {
2534 auto metrics = env.app().getTxQ().getMetrics(*env.current());
2535 if (metrics.openLedgerFeeLevel > metrics.minProcessingFeeLevel)
2536 break;
2537 env(noop(env.master));
2538 }
2539
2540 Json::Value toSign;
2541 toSign[jss::tx_json] = noop(env.master);
2542 toSign[jss::secret] = "masterpassphrase";
2543 toSign[jss::fee_mult_max] = 900;
2544 auto rpcResult = env.rpc("json", "sign", to_string(toSign));
2545 auto result = rpcResult[jss::result];
2546
2547 BEAST_EXPECT(!RPC::contains_error(result));
2548 BEAST_EXPECT(
2549 result[jss::tx_json].isMember(jss::Fee) &&
2550 result[jss::tx_json][jss::Fee] == "7813");
2551 BEAST_EXPECT(
2552 result[jss::tx_json].isMember(jss::Sequence) &&
2553 result[jss::tx_json][jss::Sequence].isConvertibleTo(
2555
2556 env.close();
2557 }
2558
2559 {
2560 // Call "sign" with higher server load
2561 {
2562 auto& feeTrack = env.app().getFeeTrack();
2563 BEAST_EXPECT(feeTrack.getLoadFactor() == 256);
2564 for (int i = 0; i < 8; ++i)
2565 feeTrack.raiseLocalFee();
2566 BEAST_EXPECT(feeTrack.getLoadFactor() == 1220);
2567 }
2568
2569 Json::Value toSign;
2570 toSign[jss::tx_json] = noop(env.master);
2571 toSign[jss::secret] = "masterpassphrase";
2572 auto rpcResult = env.rpc("json", "sign", to_string(toSign));
2573 auto result = rpcResult[jss::result];
2574
2575 BEAST_EXPECT(!RPC::contains_error(result));
2576 BEAST_EXPECT(
2577 result[jss::tx_json].isMember(jss::Fee) &&
2578 result[jss::tx_json][jss::Fee] == "47");
2579 BEAST_EXPECT(
2580 result[jss::tx_json].isMember(jss::Sequence) &&
2581 result[jss::tx_json][jss::Sequence].isConvertibleTo(
2583 }
2584
2585 {
2586 // Call "sign" with higher server load and
2587 // enough transactions to escalate the fee
2588 BEAST_EXPECT(feeTrackOuter.getLoadFactor() == 1220);
2589
2590 for (;;)
2591 {
2592 auto metrics = env.app().getTxQ().getMetrics(*env.current());
2593 if (metrics.openLedgerFeeLevel > metrics.minProcessingFeeLevel)
2594 break;
2595 env(noop(env.master), fee(47));
2596 }
2597
2598 Env_ss envs(env);
2599
2600 Json::Value toSign;
2601 toSign[jss::tx_json] = noop(env.master);
2602 toSign[jss::secret] = "masterpassphrase";
2603 // Max fee = 7000 drops
2604 toSign[jss::fee_mult_max] = 700;
2605 auto rpcResult = env.rpc("json", "sign", to_string(toSign));
2606 auto result = rpcResult[jss::result];
2607
2608 BEAST_EXPECT(!RPC::contains_error(result));
2609 BEAST_EXPECT(
2610 result[jss::tx_json].isMember(jss::Fee) &&
2611 result[jss::tx_json][jss::Fee] == "6806");
2612 BEAST_EXPECT(
2613 result[jss::tx_json].isMember(jss::Sequence) &&
2614 result[jss::tx_json][jss::Sequence].isConvertibleTo(
2616 }
2618
2619 void
2621 {
2622 testcase("autofill NetworkID");
2623 using namespace test::jtx;
2624 Env env{*this, envconfig([&](std::unique_ptr<Config> cfg) {
2625 cfg->NETWORK_ID = 1025;
2626 return cfg;
2627 })};
2628
2629 {
2630 Json::Value toSign;
2631 toSign[jss::tx_json] = noop(env.master);
2632
2633 BEAST_EXPECT(!toSign[jss::tx_json].isMember(jss::NetworkID));
2634 toSign[jss::secret] = "masterpassphrase";
2635 auto rpcResult = env.rpc("json", "sign", to_string(toSign));
2636 auto result = rpcResult[jss::result];
2637
2638 BEAST_EXPECT(!RPC::contains_error(result));
2639 BEAST_EXPECT(
2640 result[jss::tx_json].isMember(jss::NetworkID) &&
2641 result[jss::tx_json][jss::NetworkID] == 1025);
2642 }
2643 }
2644
2645 // A function that can be called as though it would process a transaction.
2646 static void
2649 bool,
2650 bool,
2652 {
2653 ;
2654 }
2655
2656 void
2658 {
2659 testcase("sign/submit RPCs");
2660 using namespace std::chrono_literals;
2661 using namespace test::jtx;
2662 // Use jtx to set up a ledger so the tests will do the right thing.
2663 Account const a{"a"}; // rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA
2664 Account const g{"g"}; // rLPwWB1itaUGMV8kbMLLysjGkEpTM2Soy4
2665 auto const USD = g["USD"];
2666
2667 // Account: rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi
2668 // seed: sh1yJfwoi98zCygwijUzuHmJDeVKd
2669 Account const ed{"ed", KeyType::ed25519};
2670 // master is rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh.
2671 // "b" (not in the ledger) is rDg53Haik2475DJx8bjMDSDPj4VX7htaMd.
2672 // "c" (phantom signer) is rPcNzota6B8YBokhYtcTNqQVCngtbnWfux.
2673
2674 Env env(*this, envconfig([](std::unique_ptr<Config> cfg) {
2675 cfg->FEES.reference_fee = 10;
2676 return cfg;
2677 }));
2678 env.fund(XRP(100000), a, ed, g);
2679 env.close();
2680
2681 env(trust(a, USD(1000)));
2682 env(trust(env.master, USD(1000)));
2683 env(pay(g, a, USD(50)));
2684 env(pay(g, env.master, USD(50)));
2685 env.close();
2686
2688
2689 // A list of all the functions we want to test.
2690 using signFunc = Json::Value (*)(
2691 Json::Value params,
2692 unsigned int apiVersion,
2693 NetworkOPs::FailHard failType,
2694 Role role,
2695 std::chrono::seconds validatedLedgerAge,
2696 Application& app);
2697
2698 using submitFunc = Json::Value (*)(
2699 Json::Value params,
2700 unsigned int apiVersion,
2701 NetworkOPs::FailHard failType,
2702 Role role,
2703 std::chrono::seconds validatedLedgerAge,
2704 Application& app,
2705 ProcessTransactionFn const& processTransaction);
2706
2707 using TestStuff =
2709
2710 static TestStuff const testFuncs[] = {
2711 TestStuff{transactionSign, nullptr, "sign", 0},
2712 TestStuff{nullptr, transactionSubmit, "submit", 1},
2713 TestStuff{transactionSignFor, nullptr, "sign_for", 2},
2714 TestStuff{
2715 nullptr,
2717 "submit_multisigned",
2718 3}};
2719
2720 for (auto testFunc : testFuncs)
2721 {
2722 // For each JSON test.
2723 for (auto const& txnTest : txnTestArray)
2724 {
2725 Json::Value req;
2726 Json::Reader().parse(txnTest.json, req);
2727 if (RPC::contains_error(req))
2728 Throw<std::runtime_error>(
2729 "Internal JSONRPC_test error. Bad test JSON.");
2730
2731 static Role const testedRoles[] = {
2733
2734 for (Role testRole : testedRoles)
2735 {
2736 Json::Value result;
2737 auto const signFn = get<0>(testFunc);
2738 if (signFn != nullptr)
2739 {
2740 assert(get<1>(testFunc) == nullptr);
2741 result = signFn(
2742 req,
2743 1,
2745 testRole,
2746 1s,
2747 env.app());
2748 }
2749 else
2750 {
2751 auto const submitFn = get<1>(testFunc);
2752 assert(submitFn != nullptr);
2753 result = submitFn(
2754 req,
2757 testRole,
2758 1s,
2759 env.app(),
2760 processTxn);
2761 }
2762
2763 std::string errStr;
2764 if (RPC::contains_error(result))
2765 errStr = result["error_message"].asString();
2766
2767 if (errStr == txnTest.expMsg[get<3>(testFunc)])
2768 {
2769 pass();
2770 }
2771 else
2772 {
2773 std::ostringstream description;
2774 description << txnTest.description << " Called "
2775 << get<2>(testFunc) << "(). Got \'"
2776 << errStr << "\'";
2777 fail(description.str(), __FILE__, txnTest.line);
2778 }
2779 }
2780 }
2781 }
2782 }
2783
2784 void
2785 run() override
2786 {
2792 }
2793};
2794
2795BEAST_DEFINE_TESTSUITE(JSONRPC, ripple_app, ripple);
2796
2797} // namespace RPC
2798} // 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: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: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