Electroneum
Loading...
Searching...
No Matches
tx_validation.cpp
Go to the documentation of this file.
1// Copyrights(c) 2017-2021, The Electroneum Project
2// Copyrights(c) 2014-2019, The Monero Project
3//
4// All rights reserved.
5//
6// Redistribution and use in source and binary forms, with or without modification, are
7// permitted provided that the following conditions are met:
8//
9// 1. Redistributions of source code must retain the above copyright notice, this list of
10// conditions and the following disclaimer.
11//
12// 2. Redistributions in binary form must reproduce the above copyright notice, this list
13// of conditions and the following disclaimer in the documentation and/or other
14// materials provided with the distribution.
15//
16// 3. Neither the name of the copyright holder nor the names of its contributors may be
17// used to endorse or promote products derived from this software without specific
18// prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
21// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
23// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
28// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29//
30// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
31
32#include "chaingen.h"
33#include "tx_validation.h"
34#include "device/device.hpp"
35
36using namespace epee;
37using namespace crypto;
38using namespace cryptonote;
39
40namespace
41{
42 struct tx_builder
43 {
44 void step1_init(size_t version = 1, uint64_t unlock_time = 0)
45 {
46 m_tx.vin.clear();
47 m_tx.vout.clear();
48 m_tx.signatures.clear();
49
50 m_tx.version = version;
51 m_tx.unlock_time = unlock_time;
52
53 m_tx_key = keypair::generate(hw::get_device("default"));
54 add_tx_pub_key_to_extra(m_tx, m_tx_key.pub);
55 }
56
57 void step2_fill_inputs(const account_keys& sender_account_keys, const std::vector<tx_source_entry>& sources)
58 {
59 BOOST_FOREACH(const tx_source_entry& src_entr, sources)
60 {
61 m_in_contexts.push_back(keypair());
62 keypair& in_ephemeral = m_in_contexts.back();
64 std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses;
65 subaddresses[sender_account_keys.m_account_address.m_spend_public_key] = {0,0};
66 auto& out_key = reinterpret_cast<const crypto::public_key&>(src_entr.outputs[src_entr.real_output].second.dest);
67 generate_key_image_helper(sender_account_keys, subaddresses, out_key, src_entr.real_out_tx_key, src_entr.real_out_additional_tx_keys, src_entr.real_output_in_tx_index, in_ephemeral, img, hw::get_device(("default")));
68
69 // put key image into tx input
70 txin_to_key input_to_key;
71 input_to_key.amount = src_entr.amount;
72 input_to_key.k_image = img;
73
74 // fill outputs array and use relative offsets
75 BOOST_FOREACH(const tx_source_entry::output_entry& out_entry, src_entr.outputs)
76 input_to_key.key_offsets.push_back(out_entry.first);
77
78 input_to_key.key_offsets = absolute_output_offsets_to_relative(input_to_key.key_offsets);
79 m_tx.vin.push_back(input_to_key);
80 }
81 }
82
83 void step3_fill_outputs(const std::vector<tx_destination_entry>& destinations)
84 {
85 size_t output_index = 0;
86 BOOST_FOREACH(const tx_destination_entry& dst_entr, destinations)
87 {
88 crypto::key_derivation derivation;
89 crypto::public_key out_eph_public_key;
90 crypto::generate_key_derivation(dst_entr.addr.m_view_public_key, m_tx_key.sec, derivation);
91 crypto::derive_public_key(derivation, output_index, dst_entr.addr.m_spend_public_key, out_eph_public_key);
92
93 tx_out out;
94 out.amount = dst_entr.amount;
95 txout_to_key tk;
96 tk.key = out_eph_public_key;
97 out.target = tk;
98 m_tx.vout.push_back(out);
99 output_index++;
100 }
101 }
102
103 void step4_calc_hash()
104 {
105 get_transaction_prefix_hash(m_tx, m_tx_prefix_hash);
106 }
107
108 void step5_sign(const std::vector<tx_source_entry>& sources)
109 {
110 m_tx.signatures.clear();
111
112 size_t i = 0;
113 BOOST_FOREACH(const tx_source_entry& src_entr, sources)
114 {
115 std::vector<const crypto::public_key*> keys_ptrs;
116 std::vector<crypto::public_key> keys(src_entr.outputs.size());
117 size_t j = 0;
118 BOOST_FOREACH(const tx_source_entry::output_entry& o, src_entr.outputs)
119 {
120 keys[j] = rct::rct2pk(o.second.dest);
121 keys_ptrs.push_back(&keys[j]);
122 ++j;
123 }
124
125 m_tx.signatures.push_back(std::vector<crypto::signature>());
126 std::vector<crypto::signature>& sigs = m_tx.signatures.back();
127 sigs.resize(src_entr.outputs.size());
128 generate_ring_signature(m_tx_prefix_hash, boost::get<txin_to_key>(m_tx.vin[i]).k_image, keys_ptrs, m_in_contexts[i].sec, src_entr.real_output, sigs.data());
129 i++;
130 }
131 }
132
133 transaction m_tx;
134 keypair m_tx_key;
135 std::vector<keypair> m_in_contexts;
136 crypto::hash m_tx_prefix_hash;
137 };
138
139 transaction make_simple_tx_with_unlock_time(const std::vector<test_event_entry>& events,
140 const cryptonote::block& blk_head, const cryptonote::account_base& from, const cryptonote::account_base& to,
141 uint64_t amount, uint64_t unlock_time)
142 {
143 std::vector<tx_source_entry> sources;
144 std::vector<tx_destination_entry> destinations;
145 fill_tx_sources_and_destinations(events, blk_head, from, to, amount, TESTS_DEFAULT_FEE, 0, sources, destinations);
146
147 tx_builder builder;
148 builder.step1_init(1, unlock_time);
149 builder.step2_fill_inputs(from.get_keys(), sources);
150 builder.step3_fill_outputs(destinations);
151 builder.step4_calc_hash();
152 builder.step5_sign(sources);
153 return builder.m_tx;
154 };
155
156 crypto::public_key generate_invalid_pub_key()
157 {
158 for (int i = 0; i <= 0xFF; ++i)
159 {
161 memset(&key, i, sizeof(crypto::public_key));
163 {
164 return key;
165 }
166 }
167
168 throw std::runtime_error("invalid public key wasn't found");
169 return crypto::public_key();
170 }
171
172 crypto::key_image generate_invalid_key_image()
173 {
175 // a random key image plucked from the blockchain
176 if (!epee::string_tools::hex_to_pod("6b9f5d1be7c950dc6e4e258c6ef75509412ba9ecaaf90e6886140151d1365b5e", key_image))
177 throw std::runtime_error("invalid key image wasn't found");
178 return key_image;
179 }
180}
181
182//----------------------------------------------------------------------------------------------------------------------
183// Tests
184
185bool gen_tx_big_version::generate(std::vector<test_event_entry>& events) const
186{
187 uint64_t ts_start = 1338224400;
188
189 GENERATE_ACCOUNT(miner_account);
190 MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start);
191 REWIND_BLOCKS(events, blk_0r, blk_0, miner_account);
192
193 std::vector<tx_source_entry> sources;
194 std::vector<tx_destination_entry> destinations;
195 fill_tx_sources_and_destinations(events, blk_0, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
196
197 tx_builder builder;
198 builder.step1_init(1 + 1, 0);
199 builder.step2_fill_inputs(miner_account.get_keys(), sources);
200 builder.step3_fill_outputs(destinations);
201 builder.step4_calc_hash();
202 builder.step5_sign(sources);
203
204 DO_CALLBACK(events, "mark_invalid_tx");
205 events.push_back(builder.m_tx);
206
207 return true;
208}
209
210bool gen_tx_unlock_time::generate(std::vector<test_event_entry>& events) const
211{
212 uint64_t ts_start = 1338224400;
213
214 GENERATE_ACCOUNT(miner_account);
215 MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start);
216 REWIND_BLOCKS_N(events, blk_1, blk_0, miner_account, 10);
217 REWIND_BLOCKS(events, blk_1r, blk_1, miner_account);
218
219 auto make_tx_with_unlock_time = [&](uint64_t unlock_time) -> transaction
220 {
221 return make_simple_tx_with_unlock_time(events, blk_1, miner_account, miner_account, MK_COINS(1), unlock_time);
222 };
223
224 std::list<transaction> txs_0;
225
226 txs_0.push_back(make_tx_with_unlock_time(0));
227 events.push_back(txs_0.back());
228
229 txs_0.push_back(make_tx_with_unlock_time(get_block_height(blk_1r) - 1));
230 events.push_back(txs_0.back());
231
232 txs_0.push_back(make_tx_with_unlock_time(get_block_height(blk_1r)));
233 events.push_back(txs_0.back());
234
235 txs_0.push_back(make_tx_with_unlock_time(get_block_height(blk_1r) + 1));
236 events.push_back(txs_0.back());
237
238 txs_0.push_back(make_tx_with_unlock_time(get_block_height(blk_1r) + 2));
239 events.push_back(txs_0.back());
240
241 txs_0.push_back(make_tx_with_unlock_time(ts_start - 1));
242 events.push_back(txs_0.back());
243
244 txs_0.push_back(make_tx_with_unlock_time(time(0) + 60 * 60));
245 events.push_back(txs_0.back());
246
247 MAKE_NEXT_BLOCK_TX_LIST(events, blk_2, blk_1r, miner_account, txs_0);
248
249 return true;
250}
251
252bool gen_tx_input_is_not_txin_to_key::generate(std::vector<test_event_entry>& events) const
253{
254 uint64_t ts_start = 1338224400;
255
256 GENERATE_ACCOUNT(miner_account);
257 MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start);
258 REWIND_BLOCKS(events, blk_0r, blk_0, miner_account);
259
260 MAKE_NEXT_BLOCK(events, blk_tmp, blk_0r, miner_account);
261 events.pop_back();
262
263 DO_CALLBACK(events, "mark_invalid_tx");
264 events.push_back(blk_tmp.miner_tx);
265
266 auto make_tx_with_input = [&](const txin_v& tx_input) -> transaction
267 {
268 std::vector<tx_source_entry> sources;
269 std::vector<tx_destination_entry> destinations;
270 fill_tx_sources_and_destinations(events, blk_0, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
271
272 tx_builder builder;
273 builder.step1_init();
274 builder.m_tx.vin.push_back(tx_input);
275 builder.step3_fill_outputs(destinations);
276 return builder.m_tx;
277 };
278
279 DO_CALLBACK(events, "mark_invalid_tx");
280 events.push_back(make_tx_with_input(txin_to_script()));
281
282 DO_CALLBACK(events, "mark_invalid_tx");
283 events.push_back(make_tx_with_input(txin_to_scripthash()));
284
285 return true;
286}
287
288bool gen_tx_no_inputs_no_outputs::generate(std::vector<test_event_entry>& events) const
289{
290 uint64_t ts_start = 1338224400;
291
292 GENERATE_ACCOUNT(miner_account);
293 MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start);
294
295 tx_builder builder;
296 builder.step1_init();
297
298 DO_CALLBACK(events, "mark_invalid_tx");
299 events.push_back(builder.m_tx);
300
301 return true;
302}
303
304bool gen_tx_no_inputs_has_outputs::generate(std::vector<test_event_entry>& events) const
305{
306 uint64_t ts_start = 1338224400;
307
308 GENERATE_ACCOUNT(miner_account);
309 MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start);
310
311 std::vector<tx_source_entry> sources;
312 std::vector<tx_destination_entry> destinations;
313 fill_tx_sources_and_destinations(events, blk_0, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
314
315 tx_builder builder;
316 builder.step1_init();
317 builder.step3_fill_outputs(destinations);
318
319 DO_CALLBACK(events, "mark_invalid_tx");
320 events.push_back(builder.m_tx);
321
322 return true;
323}
324
325bool gen_tx_has_inputs_no_outputs::generate(std::vector<test_event_entry>& events) const
326{
327 uint64_t ts_start = 1338224400;
328
329 GENERATE_ACCOUNT(miner_account);
330 MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start);
331 REWIND_BLOCKS(events, blk_0r, blk_0, miner_account);
332
333 std::vector<tx_source_entry> sources;
334 std::vector<tx_destination_entry> destinations;
335 fill_tx_sources_and_destinations(events, blk_0, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
336 destinations.clear();
337
338 tx_builder builder;
339 builder.step1_init();
340 builder.step2_fill_inputs(miner_account.get_keys(), sources);
341 builder.step3_fill_outputs(destinations);
342 builder.step4_calc_hash();
343 builder.step5_sign(sources);
344
345 events.push_back(builder.m_tx);
346 MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_account, builder.m_tx);
347
348 return true;
349}
350
351bool gen_tx_invalid_input_amount::generate(std::vector<test_event_entry>& events) const
352{
353 uint64_t ts_start = 1338224400;
354
355 GENERATE_ACCOUNT(miner_account);
356 MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start);
357 REWIND_BLOCKS(events, blk_0r, blk_0, miner_account);
358
359 std::vector<tx_source_entry> sources;
360 std::vector<tx_destination_entry> destinations;
361 fill_tx_sources_and_destinations(events, blk_0, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
362 sources.front().amount++;
363
364 tx_builder builder;
365 builder.step1_init();
366 builder.step2_fill_inputs(miner_account.get_keys(), sources);
367 builder.step3_fill_outputs(destinations);
368 builder.step4_calc_hash();
369 builder.step5_sign(sources);
370
371 DO_CALLBACK(events, "mark_invalid_tx");
372 events.push_back(builder.m_tx);
373
374 return true;
375}
376
377bool gen_tx_input_wo_key_offsets::generate(std::vector<test_event_entry>& events) const
378{
379 uint64_t ts_start = 1338224400;
380
381 GENERATE_ACCOUNT(miner_account);
382 MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start);
383 REWIND_BLOCKS(events, blk_0r, blk_0, miner_account);
384
385 std::vector<tx_source_entry> sources;
386 std::vector<tx_destination_entry> destinations;
387 fill_tx_sources_and_destinations(events, blk_0, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
388
389 tx_builder builder;
390 builder.step1_init();
391 builder.step2_fill_inputs(miner_account.get_keys(), sources);
392 builder.step3_fill_outputs(destinations);
393 txin_to_key& in_to_key = boost::get<txin_to_key>(builder.m_tx.vin.front());
394 uint64_t key_offset = in_to_key.key_offsets.front();
395 in_to_key.key_offsets.pop_back();
396 CHECK_AND_ASSERT_MES(in_to_key.key_offsets.empty(), false, "txin contained more than one key_offset");
397 builder.step4_calc_hash();
398 in_to_key.key_offsets.push_back(key_offset);
399 builder.step5_sign(sources);
400 in_to_key.key_offsets.pop_back();
401
402 DO_CALLBACK(events, "mark_invalid_tx");
403 events.push_back(builder.m_tx);
404
405 return true;
406}
407
408bool gen_tx_key_offest_points_to_foreign_key::generate(std::vector<test_event_entry>& events) const
409{
410 uint64_t ts_start = 1338224400;
411
412 GENERATE_ACCOUNT(miner_account);
413 MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start);
414 MAKE_NEXT_BLOCK(events, blk_1, blk_0, miner_account);
415 REWIND_BLOCKS(events, blk_1r, blk_1, miner_account);
416 MAKE_ACCOUNT(events, alice_account);
417 MAKE_ACCOUNT(events, bob_account);
418 MAKE_TX_LIST_START(events, txs_0, miner_account, bob_account, MK_COINS(15) + 1, blk_1);
419 MAKE_TX_LIST(events, txs_0, miner_account, alice_account, MK_COINS(15) + 1, blk_1);
420 MAKE_NEXT_BLOCK_TX_LIST(events, blk_2, blk_1r, miner_account, txs_0);
421
422 std::vector<tx_source_entry> sources_bob;
423 std::vector<tx_destination_entry> destinations_bob;
424 fill_tx_sources_and_destinations(events, blk_2, bob_account, miner_account, MK_COINS(15) + 1 - TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, 0, sources_bob, destinations_bob);
425
426 std::vector<tx_source_entry> sources_alice;
427 std::vector<tx_destination_entry> destinations_alice;
428 fill_tx_sources_and_destinations(events, blk_2, alice_account, miner_account, MK_COINS(15) + 1 - TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, 0, sources_alice, destinations_alice);
429
430 tx_builder builder;
431 builder.step1_init();
432 builder.step2_fill_inputs(bob_account.get_keys(), sources_bob);
433 txin_to_key& in_to_key = boost::get<txin_to_key>(builder.m_tx.vin.front());
434 in_to_key.key_offsets.front() = sources_alice.front().outputs.front().first;
435 builder.step3_fill_outputs(destinations_bob);
436 builder.step4_calc_hash();
437 builder.step5_sign(sources_bob);
438
439 DO_CALLBACK(events, "mark_invalid_tx");
440 events.push_back(builder.m_tx);
441
442 return true;
443}
444
445bool gen_tx_sender_key_offest_not_exist::generate(std::vector<test_event_entry>& events) const
446{
447 uint64_t ts_start = 1338224400;
448
449 GENERATE_ACCOUNT(miner_account);
450 MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start);
451 REWIND_BLOCKS(events, blk_0r, blk_0, miner_account);
452
453 std::vector<tx_source_entry> sources;
454 std::vector<tx_destination_entry> destinations;
455 fill_tx_sources_and_destinations(events, blk_0, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
456
457 tx_builder builder;
458 builder.step1_init();
459 builder.step2_fill_inputs(miner_account.get_keys(), sources);
460 txin_to_key& in_to_key = boost::get<txin_to_key>(builder.m_tx.vin.front());
461 in_to_key.key_offsets.front() = std::numeric_limits<uint64_t>::max();
462 builder.step3_fill_outputs(destinations);
463 builder.step4_calc_hash();
464 builder.step5_sign(sources);
465
466 DO_CALLBACK(events, "mark_invalid_tx");
467 events.push_back(builder.m_tx);
468
469 return true;
470}
471
472bool gen_tx_mixed_key_offest_not_exist::generate(std::vector<test_event_entry>& events) const
473{
474 uint64_t ts_start = 1338224400;
475
476 GENERATE_ACCOUNT(miner_account);
477 MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start);
478 MAKE_NEXT_BLOCK(events, blk_1, blk_0, miner_account);
479 REWIND_BLOCKS(events, blk_1r, blk_1, miner_account);
480 MAKE_ACCOUNT(events, alice_account);
481 MAKE_ACCOUNT(events, bob_account);
482 MAKE_TX_LIST_START(events, txs_0, miner_account, bob_account, MK_COINS(1) + TESTS_DEFAULT_FEE, blk_1);
483 MAKE_TX_LIST(events, txs_0, miner_account, alice_account, MK_COINS(1) + TESTS_DEFAULT_FEE, blk_1);
484 MAKE_NEXT_BLOCK_TX_LIST(events, blk_2, blk_1r, miner_account, txs_0);
485
486 std::vector<tx_source_entry> sources;
487 std::vector<tx_destination_entry> destinations;
488 fill_tx_sources_and_destinations(events, blk_2, bob_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 1, sources, destinations);
489
490 sources.front().outputs[(sources.front().real_output + 1) % 2].first = std::numeric_limits<uint64_t>::max();
491
492 tx_builder builder;
493 builder.step1_init();
494 builder.step2_fill_inputs(bob_account.get_keys(), sources);
495 builder.step3_fill_outputs(destinations);
496 builder.step4_calc_hash();
497 builder.step5_sign(sources);
498
499 DO_CALLBACK(events, "mark_invalid_tx");
500 events.push_back(builder.m_tx);
501
502 return true;
503}
504
505bool gen_tx_key_image_not_derive_from_tx_key::generate(std::vector<test_event_entry>& events) const
506{
507 uint64_t ts_start = 1338224400;
508
509 GENERATE_ACCOUNT(miner_account);
510 MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start);
511 REWIND_BLOCKS(events, blk_0r, blk_0, miner_account);
512
513 std::vector<tx_source_entry> sources;
514 std::vector<tx_destination_entry> destinations;
515 fill_tx_sources_and_destinations(events, blk_0, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
516
517 tx_builder builder;
518 builder.step1_init();
519 builder.step2_fill_inputs(miner_account.get_keys(), sources);
520
521 txin_to_key& in_to_key = boost::get<txin_to_key>(builder.m_tx.vin.front());
523 key_image another_ki;
524 crypto::generate_key_image(kp.pub, kp.sec, another_ki);
525 in_to_key.k_image = another_ki;
526
527 builder.step3_fill_outputs(destinations);
528 builder.step4_calc_hash();
529
530 // Tx with invalid key image can't be subscribed, so create empty signature
531 builder.m_tx.signatures.resize(1);
532 builder.m_tx.signatures[0].resize(1);
533 builder.m_tx.signatures[0][0] = boost::value_initialized<crypto::signature>();
534
535 DO_CALLBACK(events, "mark_invalid_tx");
536 events.push_back(builder.m_tx);
537
538 return true;
539}
540
541bool gen_tx_key_image_is_invalid::generate(std::vector<test_event_entry>& events) const
542{
543 uint64_t ts_start = 1338224400;
544
545 GENERATE_ACCOUNT(miner_account);
546 MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start);
547 REWIND_BLOCKS(events, blk_0r, blk_0, miner_account);
548
549 std::vector<tx_source_entry> sources;
550 std::vector<tx_destination_entry> destinations;
551 fill_tx_sources_and_destinations(events, blk_0, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
552
553 tx_builder builder;
554 builder.step1_init();
555 builder.step2_fill_inputs(miner_account.get_keys(), sources);
556
557 txin_to_key& in_to_key = boost::get<txin_to_key>(builder.m_tx.vin.front());
558 in_to_key.k_image = generate_invalid_key_image();
559
560 builder.step3_fill_outputs(destinations);
561 builder.step4_calc_hash();
562
563 // Tx with invalid key image can't be subscribed, so create empty signature
564 builder.m_tx.signatures.resize(1);
565 builder.m_tx.signatures[0].resize(1);
566 builder.m_tx.signatures[0][0] = boost::value_initialized<crypto::signature>();
567
568 DO_CALLBACK(events, "mark_invalid_tx");
569 events.push_back(builder.m_tx);
570
571 return true;
572}
573
574bool gen_tx_check_input_unlock_time::generate(std::vector<test_event_entry>& events) const
575{
576 static const size_t tests_count = 6;
577
578 uint64_t ts_start = 1338224400;
579
580 GENERATE_ACCOUNT(miner_account);
581 MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start);
582 REWIND_BLOCKS_N(events, blk_1, blk_0, miner_account, tests_count - 1);
583 REWIND_BLOCKS(events, blk_1r, blk_1, miner_account);
584
585 std::array<account_base, tests_count> accounts;
586 for (size_t i = 0; i < tests_count; ++i)
587 {
588 MAKE_ACCOUNT(events, acc);
589 accounts[i] = acc;
590 }
591
592 std::list<transaction> txs_0;
593 auto make_tx_to_acc = [&](size_t acc_idx, uint64_t unlock_time)
594 {
595 txs_0.push_back(make_simple_tx_with_unlock_time(events, blk_1, miner_account, accounts[acc_idx],
596 MK_COINS(1) + TESTS_DEFAULT_FEE, unlock_time));
597 events.push_back(txs_0.back());
598 };
599
600 uint64_t blk_3_height = get_block_height(blk_1r) + 2;
601 make_tx_to_acc(0, 0);
602 make_tx_to_acc(1, blk_3_height - 1);
603 make_tx_to_acc(2, blk_3_height);
604 make_tx_to_acc(3, blk_3_height + 1);
605 make_tx_to_acc(4, time(0) - 1);
606 make_tx_to_acc(5, time(0) + 60 * 60);
607 MAKE_NEXT_BLOCK_TX_LIST(events, blk_2, blk_1r, miner_account, txs_0);
608
609 std::list<transaction> txs_1;
610 auto make_tx_from_acc = [&](size_t acc_idx, bool invalid)
611 {
612 transaction tx = make_simple_tx_with_unlock_time(events, blk_2, accounts[acc_idx], miner_account, MK_COINS(1), 0);
613 if (invalid)
614 {
615 DO_CALLBACK(events, "mark_invalid_tx");
616 }
617 else
618 {
619 txs_1.push_back(tx);
620 }
621 events.push_back(tx);
622 };
623
624 make_tx_from_acc(0, false);
625 make_tx_from_acc(1, false);
626 make_tx_from_acc(2, false);
627 make_tx_from_acc(3, true);
628 make_tx_from_acc(4, false);
629 make_tx_from_acc(5, true);
630 MAKE_NEXT_BLOCK_TX_LIST(events, blk_3, blk_2, miner_account, txs_1);
631
632 return true;
633}
634
635bool gen_tx_txout_to_key_has_invalid_key::generate(std::vector<test_event_entry>& events) const
636{
637 uint64_t ts_start = 1338224400;
638
639 GENERATE_ACCOUNT(miner_account);
640 MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start);
641 REWIND_BLOCKS(events, blk_0r, blk_0, miner_account);
642
643 std::vector<tx_source_entry> sources;
644 std::vector<tx_destination_entry> destinations;
645 fill_tx_sources_and_destinations(events, blk_0, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
646
647 tx_builder builder;
648 builder.step1_init();
649 builder.step2_fill_inputs(miner_account.get_keys(), sources);
650 builder.step3_fill_outputs(destinations);
651
652 txout_to_key& out_to_key = boost::get<txout_to_key>(builder.m_tx.vout.front().target);
653 out_to_key.key = generate_invalid_pub_key();
654
655 builder.step4_calc_hash();
656 builder.step5_sign(sources);
657
658 DO_CALLBACK(events, "mark_invalid_tx");
659 events.push_back(builder.m_tx);
660
661 return true;
662}
663
664bool gen_tx_output_with_zero_amount::generate(std::vector<test_event_entry>& events) const
665{
666 uint64_t ts_start = 1338224400;
667
668 GENERATE_ACCOUNT(miner_account);
669 MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start);
670 REWIND_BLOCKS(events, blk_0r, blk_0, miner_account);
671
672 std::vector<tx_source_entry> sources;
673 std::vector<tx_destination_entry> destinations;
674 fill_tx_sources_and_destinations(events, blk_0, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
675
676 tx_builder builder;
677 builder.step1_init();
678 builder.step2_fill_inputs(miner_account.get_keys(), sources);
679 builder.step3_fill_outputs(destinations);
680
681 builder.m_tx.vout.front().amount = 0;
682
683 builder.step4_calc_hash();
684 builder.step5_sign(sources);
685
686 DO_CALLBACK(events, "mark_invalid_tx");
687 events.push_back(builder.m_tx);
688
689 return true;
690}
691
692bool gen_tx_output_is_not_txout_to_key::generate(std::vector<test_event_entry>& events) const
693{
694 uint64_t ts_start = 1338224400;
695
696 GENERATE_ACCOUNT(miner_account);
697 MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start);
698 REWIND_BLOCKS(events, blk_0r, blk_0, miner_account);
699
700 std::vector<tx_source_entry> sources;
701 std::vector<tx_destination_entry> destinations;
702 fill_tx_sources_and_destinations(events, blk_0, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
703
704 tx_builder builder;
705 builder.step1_init();
706 builder.step2_fill_inputs(miner_account.get_keys(), sources);
707
708 builder.m_tx.vout.push_back(tx_out());
709 builder.m_tx.vout.back().amount = 1;
710 builder.m_tx.vout.back().target = txout_to_script();
711
712 builder.step4_calc_hash();
713 builder.step5_sign(sources);
714
715 DO_CALLBACK(events, "mark_invalid_tx");
716 events.push_back(builder.m_tx);
717
718 builder.step1_init();
719 builder.step2_fill_inputs(miner_account.get_keys(), sources);
720
721 builder.m_tx.vout.push_back(tx_out());
722 builder.m_tx.vout.back().amount = 1;
723 builder.m_tx.vout.back().target = txout_to_scripthash();
724
725 builder.step4_calc_hash();
726 builder.step5_sign(sources);
727
728 DO_CALLBACK(events, "mark_invalid_tx");
729 events.push_back(builder.m_tx);
730
731 return true;
732}
733
734bool gen_tx_signatures_are_invalid::generate(std::vector<test_event_entry>& events) const
735{
736 uint64_t ts_start = 1338224400;
737
738 GENERATE_ACCOUNT(miner_account);
739 MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start);
740 MAKE_NEXT_BLOCK(events, blk_1, blk_0, miner_account);
741 REWIND_BLOCKS(events, blk_1r, blk_1, miner_account);
742 MAKE_ACCOUNT(events, alice_account);
743 MAKE_ACCOUNT(events, bob_account);
744 MAKE_TX_LIST_START(events, txs_0, miner_account, bob_account, MK_COINS(1) + TESTS_DEFAULT_FEE, blk_1);
745 MAKE_TX_LIST(events, txs_0, miner_account, alice_account, MK_COINS(1) + TESTS_DEFAULT_FEE, blk_1);
746 MAKE_NEXT_BLOCK_TX_LIST(events, blk_2, blk_1r, miner_account, txs_0);
747
748 MAKE_TX(events, tx_0, miner_account, miner_account, MK_COINS(60), blk_2);
749 events.pop_back();
750
751 MAKE_TX_MIX(events, tx_1, bob_account, miner_account, MK_COINS(1), 1, blk_2);
752 events.pop_back();
753
754 // Tx with nmix = 0 without signatures
755 DO_CALLBACK(events, "mark_invalid_tx");
757 events.push_back(serialized_transaction(sr_tx));
758
759 // Tx with nmix = 0 have a few inputs, and not enough signatures
760 DO_CALLBACK(events, "mark_invalid_tx");
761 sr_tx = t_serializable_object_to_blob(tx_0);
762 sr_tx.resize(sr_tx.size() - sizeof(crypto::signature));
763 events.push_back(serialized_transaction(sr_tx));
764
765 // Tx with nmix = 0 have a few inputs, and too many signatures
766 DO_CALLBACK(events, "mark_invalid_tx");
767 sr_tx = t_serializable_object_to_blob(tx_0);
768 sr_tx.insert(sr_tx.end(), sr_tx.end() - sizeof(crypto::signature), sr_tx.end());
769 events.push_back(serialized_transaction(sr_tx));
770
771 // Tx with nmix = 1 without signatures
772 DO_CALLBACK(events, "mark_invalid_tx");
773 sr_tx = t_serializable_object_to_blob(static_cast<transaction_prefix>(tx_1));
774 events.push_back(serialized_transaction(sr_tx));
775
776 // Tx with nmix = 1 have not enough signatures
777 DO_CALLBACK(events, "mark_invalid_tx");
778 sr_tx = t_serializable_object_to_blob(tx_1);
779 sr_tx.resize(sr_tx.size() - sizeof(crypto::signature));
780 events.push_back(serialized_transaction(sr_tx));
781
782 // Tx with nmix = 1 have too many signatures
783 DO_CALLBACK(events, "mark_invalid_tx");
784 sr_tx = t_serializable_object_to_blob(tx_1);
785 sr_tx.insert(sr_tx.end(), sr_tx.end() - sizeof(crypto::signature), sr_tx.end());
786 events.push_back(serialized_transaction(sr_tx));
787
788 return true;
789}
uint8_t version
time_t time
void fill_tx_sources_and_destinations(const std::vector< test_event_entry > &events, const block &blk_head, const cryptonote::account_base &from, const cryptonote::account_public_address &to, uint64_t amount, uint64_t fee, size_t nmix, std::vector< tx_source_entry > &sources, std::vector< tx_destination_entry > &destinations)
Definition chaingen.cpp:775
#define MAKE_NEXT_BLOCK(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC)
Definition chaingen.h:839
#define REWIND_BLOCKS(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC)
Definition chaingen.h:890
#define MAKE_TX_LIST_START(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, HEAD)
Definition chaingen.h:935
#define MAKE_GENESIS_BLOCK(VEC_EVENTS, BLK_NAME, MINER_ACC, TS)
Definition chaingen.h:833
serialized_object< cryptonote::transaction > serialized_transaction
Definition chaingen.h:108
#define MAKE_NEXT_BLOCK_TX_LIST(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC, TXLIST)
Definition chaingen.h:867
#define DO_CALLBACK(VEC_EVENTS, CB_NAME)
Definition chaingen.h:820
#define MAKE_TX_LIST(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, HEAD)
Definition chaingen.h:933
#define REWIND_BLOCKS_N(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC, COUNT)
Definition chaingen.h:889
#define MK_COINS(amount)
Definition chaingen.h:1060
#define TESTS_DEFAULT_FEE
Definition chaingen.h:1061
#define MAKE_ACCOUNT(VEC_EVENTS, account)
Definition chaingen.h:815
#define MAKE_TX(VEC_EVENTS, TX_NAME, FROM, TO, AMOUNT, HEAD)
Definition chaingen.h:903
#define GENERATE_ACCOUNT(account)
Definition chaingen.h:801
#define MAKE_TX_MIX(VEC_EVENTS, TX_NAME, FROM, TO, AMOUNT, NMIX, HEAD)
Definition chaingen.h:893
#define MAKE_NEXT_BLOCK_TX1(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC, TX1)
Definition chaingen.h:849
const account_keys & get_keys() const
Definition account.cpp:264
std::vector< std::vector< crypto::signature > > signatures
std::vector< std::string > keypair
const char * key
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
crypto namespace.
Definition crypto.cpp:58
bool check_key(const public_key &key)
Definition crypto.h:256
POD_CLASS signature
Definition crypto.h:108
POD_CLASS key_derivation
Definition crypto.h:101
unsigned __int64 uint64_t
Definition hash.h:137
bool generate_key_derivation(const public_key &key1, const secret_key &key2, key_derivation &derivation)
Definition crypto.h:272
void generate_ring_signature(const hash &prefix_hash, const key_image &image, const public_key *const *pubs, std::size_t pubs_count, const secret_key &sec, std::size_t sec_index, signature *sig)
Definition crypto.h:327
POD_CLASS public_key
Definition crypto.h:79
bool derive_public_key(const key_derivation &derivation, std::size_t output_index, const public_key &base, public_key &derived_key)
Definition crypto.h:275
POD_CLASS key_image
Definition crypto.h:105
POD_CLASS hash
Definition hash.h:50
void generate_key_image(const public_key &pub, const secret_key &sec, key_image &image)
Definition crypto.h:324
Holds cryptonote related classes and helpers.
Definition ban.cpp:40
bool generate_key_image_helper(const account_keys &ack, const std::unordered_map< crypto::public_key, subaddress_index > &subaddresses, const crypto::public_key &out_key, const crypto::public_key &tx_public_key, const std::vector< crypto::public_key > &additional_tx_public_keys, size_t real_output_index, keypair &in_ephemeral, crypto::key_image &ki, hw::device &hwdev, const uint32_t account_major_offset)
boost::variant< txin_gen, txin_to_script, txin_to_scripthash, txin_to_key, txin_to_key_public > txin_v
void get_transaction_prefix_hash(const transaction_prefix &tx, crypto::hash &h)
std::vector< uint64_t > absolute_output_offsets_to_relative(const std::vector< uint64_t > &off)
uint64_t get_block_height(const block &b)
bool add_tx_pub_key_to_extra(transaction &tx, const crypto::public_key &tx_pub_key)
std::string blobdata
bool t_serializable_object_to_blob(const t_object &to, blobdata &b_blob)
bool hex_to_pod(const std::string &hex_str, t_pod_type &s)
device & get_device(const std::string &device_descriptor)
Definition device.cpp:95
unsigned __int64 uint64_t
Definition stdint.h:136
account_public_address m_account_address
Definition account.h:43
crypto::secret_key sec
static keypair generate(hw::device &hwdev)
crypto::public_key pub
uint64_t amount
account_public_address addr
std::vector< crypto::public_key > real_out_additional_tx_keys
crypto::public_key real_out_tx_key
uint64_t amount
size_t real_output
std::vector< output_entry > outputs
std::pair< uint64_t, rct::ctkey > output_entry
size_t real_output_in_tx_index
crypto::key_image k_image
std::vector< uint64_t > key_offsets
bool generate(std::vector< test_event_entry > &events) const
bool generate(std::vector< test_event_entry > &events) const
bool generate(std::vector< test_event_entry > &events) const
bool generate(std::vector< test_event_entry > &events) const
bool generate(std::vector< test_event_entry > &events) const
bool generate(std::vector< test_event_entry > &events) const
bool generate(std::vector< test_event_entry > &events) const
bool generate(std::vector< test_event_entry > &events) const
bool generate(std::vector< test_event_entry > &events) const
bool generate(std::vector< test_event_entry > &events) const
bool generate(std::vector< test_event_entry > &events) const
bool generate(std::vector< test_event_entry > &events) const
bool generate(std::vector< test_event_entry > &events) const
bool generate(std::vector< test_event_entry > &events) const
bool generate(std::vector< test_event_entry > &events) const
bool generate(std::vector< test_event_entry > &events) const
bool generate(std::vector< test_event_entry > &events) const
bool generate(std::vector< test_event_entry > &events) const