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