Monero
Loading...
Searching...
No Matches
double_spend.inl
Go to the documentation of this file.
1// Copyright (c) 2014-2022, The Monero Project
2//
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without modification, are
6// permitted provided that the following conditions are met:
7//
8// 1. Redistributions of source code must retain the above copyright notice, this list of
9// conditions and the following disclaimer.
10//
11// 2. Redistributions in binary form must reproduce the above copyright notice, this list
12// of conditions and the following disclaimer in the documentation and/or other
13// materials provided with the distribution.
14//
15// 3. Neither the name of the copyright holder nor the names of its contributors may be
16// used to endorse or promote products derived from this software without specific
17// prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
20// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
22// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
27// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28//
29// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
30
31#pragma once
32
33//======================================================================================================================
34
35template<class concrete_test>
45
46template<class concrete_test>
48{
49 if (m_invalid_tx_index == event_idx)
51 else
52 return !tvc.m_verifivation_failed && tx_added;
53}
54
55template<class concrete_test>
63
64template<class concrete_test>
65bool gen_double_spend_base<concrete_test>::mark_last_valid_block(cryptonote::core& c, size_t /*ev_index*/, const std::vector<test_event_entry>& /*events*/)
66{
67 std::vector<cryptonote::block> block_list;
68 bool r = c.get_blocks(c.get_current_blockchain_height() - 1, 1, block_list);
69 CHECK_AND_ASSERT_MES(r, false, "core::get_blocks failed");
70 m_last_valid_block = block_list.back();
71 return true;
72}
73
74template<class concrete_test>
75bool gen_double_spend_base<concrete_test>::mark_invalid_tx(cryptonote::core& /*c*/, size_t ev_index, const std::vector<test_event_entry>& /*events*/)
76{
77 m_invalid_tx_index = ev_index + 1;
78 return true;
79}
80
81template<class concrete_test>
82bool gen_double_spend_base<concrete_test>::mark_invalid_block(cryptonote::core& /*c*/, size_t ev_index, const std::vector<test_event_entry>& /*events*/)
83{
84 m_invalid_block_index = ev_index + 1;
85 return true;
86}
87
88template<class concrete_test>
89bool gen_double_spend_base<concrete_test>::check_double_spend(cryptonote::core& c, size_t /*ev_index*/, const std::vector<test_event_entry>& events)
90{
91 DEFINE_TESTS_ERROR_CONTEXT("gen_double_spend_base::check_double_spend");
92
93 if (concrete_test::has_invalid_tx)
94 {
96 }
98
99 std::vector<cryptonote::block> block_list;
100 bool r = c.get_blocks(0, 100 + 2 * CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, block_list);
102 CHECK_TEST_CONDITION(m_last_valid_block == block_list.back());
103
104 CHECK_EQ(concrete_test::expected_pool_txs_count, c.get_pool_transactions_count());
105
106 cryptonote::account_base bob_account = boost::get<cryptonote::account_base>(events[1]);
107 cryptonote::account_base alice_account = boost::get<cryptonote::account_base>(events[2]);
108
109 std::vector<cryptonote::block> chain;
110 map_hash2tx_t mtx;
111 std::vector<cryptonote::block> blocks(block_list.begin(), block_list.end());
112 r = find_block_chain(events, chain, mtx, get_block_hash(blocks.back()));
114 CHECK_EQ(concrete_test::expected_bob_balance, get_balance(bob_account, blocks, mtx));
115 CHECK_EQ(concrete_test::expected_alice_balance, get_balance(alice_account, blocks, mtx));
116
117 return true;
118}
119
120//======================================================================================================================
121
122template<bool txs_keeped_by_block>
123bool gen_double_spend_in_tx<txs_keeped_by_block>::generate(std::vector<test_event_entry>& events) const
124{
126 DO_CALLBACK(events, "mark_last_valid_block");
127
128 std::vector<cryptonote::tx_source_entry> sources;
130 se.amount = tx_0.vout[0].amount;
131 se.push_output(0, boost::get<cryptonote::txout_to_key>(tx_0.vout[0].target).key, se.amount);
132 se.real_output = 0;
133 se.rct = false;
134 se.real_out_tx_key = get_tx_pub_key_from_extra(tx_0);
136 sources.push_back(se);
137 // Double spend!
138 sources.push_back(se);
139
141 de.addr = alice_account.get_keys().m_account_address;
142 de.amount = 2 * se.amount - TESTS_DEFAULT_FEE;
143 std::vector<cryptonote::tx_destination_entry> destinations;
144 destinations.push_back(de);
145
147 if (!construct_tx(bob_account.get_keys(), sources, destinations, boost::none, std::vector<uint8_t>(), tx_1))
148 return false;
149
151 DO_CALLBACK(events, "mark_invalid_tx");
152 events.push_back(tx_1);
153 DO_CALLBACK(events, "mark_invalid_block");
154 MAKE_NEXT_BLOCK_TX1(events, blk_2, blk_1r, miner_account, tx_1);
155 DO_CALLBACK(events, "check_double_spend");
156
157 return true;
158}
159
160template<bool txs_keeped_by_block>
161bool gen_double_spend_in_the_same_block<txs_keeped_by_block>::generate(std::vector<test_event_entry>& events) const
162{
164
165 DO_CALLBACK(events, "mark_last_valid_block");
167
168 MAKE_TX_LIST_START(events, txs_1, bob_account, alice_account, send_amount - TESTS_DEFAULT_FEE, blk_1);
169 cryptonote::transaction tx_1 = txs_1.front();
170 auto tx_1_idx = events.size() - 1;
171 // Remove tx_1, it is being inserted back a little later
172 events.pop_back();
173
174 if (has_invalid_tx)
175 {
176 DO_CALLBACK(events, "mark_invalid_tx");
177 }
178 MAKE_TX_LIST(events, txs_1, bob_account, alice_account, send_amount - TESTS_DEFAULT_FEE, blk_1);
179 events.insert(events.begin() + tx_1_idx, tx_1);
180 DO_CALLBACK(events, "mark_invalid_block");
181 MAKE_NEXT_BLOCK_TX_LIST(events, blk_2, blk_1r, miner_account, txs_1);
182 DO_CALLBACK(events, "check_double_spend");
183
184 return true;
185}
186
187template<bool txs_keeped_by_block>
188bool gen_double_spend_in_different_blocks<txs_keeped_by_block>::generate(std::vector<test_event_entry>& events) const
189{
191
192 DO_CALLBACK(events, "mark_last_valid_block");
194
195 // Create two identical transactions, but don't push it to events list
196 MAKE_TX(events, tx_blk_2, bob_account, alice_account, send_amount - TESTS_DEFAULT_FEE, blk_1);
197 events.pop_back();
198 MAKE_TX(events, tx_blk_3, bob_account, alice_account, send_amount - TESTS_DEFAULT_FEE, blk_1);
199 events.pop_back();
200
201 events.push_back(tx_blk_2);
202 MAKE_NEXT_BLOCK_TX1(events, blk_2, blk_1r, miner_account, tx_blk_2);
203 DO_CALLBACK(events, "mark_last_valid_block");
204
205 if (has_invalid_tx)
206 {
207 DO_CALLBACK(events, "mark_invalid_tx");
208 }
209 events.push_back(tx_blk_3);
210 DO_CALLBACK(events, "mark_invalid_block");
211 MAKE_NEXT_BLOCK_TX1(events, blk_3, blk_2, miner_account, tx_blk_3);
212
213 DO_CALLBACK(events, "check_double_spend");
214
215 return true;
216}
217
218template<bool txs_keeped_by_block>
220{
222
224
225 // Main chain
226 MAKE_NEXT_BLOCK(events, blk_2, blk_1r, miner_account);
227 DO_CALLBACK(events, "mark_last_valid_block");
228
229 // Alt chain
230 MAKE_TX_LIST_START(events, txs_1, bob_account, alice_account, send_amount - TESTS_DEFAULT_FEE, blk_1);
231 cryptonote::transaction tx_1 = txs_1.front();
232 auto tx_1_idx = events.size() - 1;
233 // Remove tx_1, it is being inserted back a little later
234 events.pop_back();
235
236 if (has_invalid_tx)
237 {
238 DO_CALLBACK(events, "mark_invalid_tx");
239 }
240 MAKE_TX_LIST(events, txs_1, bob_account, alice_account, send_amount - TESTS_DEFAULT_FEE, blk_1);
241 events.insert(events.begin() + tx_1_idx, tx_1);
242 MAKE_NEXT_BLOCK_TX_LIST(events, blk_3, blk_1r, miner_account, txs_1);
243
244 // Try to switch to alternative chain
245 DO_CALLBACK(events, "mark_invalid_block");
246 MAKE_NEXT_BLOCK(events, blk_4, blk_3, miner_account);
247
248 DO_CALLBACK(events, "check_double_spend");
249
250 return true;
251}
252
253template<bool txs_keeped_by_block>
255{
257
259
260 // Main chain
261 MAKE_NEXT_BLOCK(events, blk_2, blk_1r, miner_account);
262 DO_CALLBACK(events, "mark_last_valid_block");
263
264 // Alternative chain
265 MAKE_TX(events, tx_1, bob_account, alice_account, send_amount - TESTS_DEFAULT_FEE, blk_1);
266 events.pop_back();
267 MAKE_TX(events, tx_2, bob_account, alice_account, send_amount - TESTS_DEFAULT_FEE, blk_1);
268 events.pop_back();
269
270 events.push_back(tx_1);
271 MAKE_NEXT_BLOCK_TX1(events, blk_3, blk_1r, miner_account, tx_1);
272
273 // Try to switch to alternative chain
274 if (has_invalid_tx)
275 {
276 DO_CALLBACK(events, "mark_invalid_tx");
277 }
278 events.push_back(tx_2);
279 DO_CALLBACK(events, "mark_invalid_block");
280 MAKE_NEXT_BLOCK_TX1(events, blk_4, blk_3, miner_account, tx_2);
281
282 DO_CALLBACK(events, "check_double_spend");
283
284 return true;
285}
bool find_block_chain(const std::vector< test_event_entry > &events, std::vector< cryptonote::block > &blockchain, map_hash2tx_t &mtx, const crypto::hash &head)
Definition chaingen.cpp:1248
uint64_t get_balance(const cryptonote::account_base &addr, const std::vector< cryptonote::block > &blockchain, const map_hash2tx_t &mtx)
Definition chaingen.cpp:1091
#define MAKE_NEXT_BLOCK(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC)
Definition chaingen.h:868
#define DEFINE_TESTS_ERROR_CONTEXT(text)
Definition chaingen.h:1087
std::unordered_map< crypto::hash, const cryptonote::transaction * > map_hash2tx_t
Definition chaingen.h:163
#define CHECK_NOT_EQ(v1, v2)
Definition chaingen.h:1090
#define CHECK_TEST_CONDITION(cond)
Definition chaingen.h:1088
#define MAKE_TX_LIST_START(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, HEAD)
Definition chaingen.h:964
#define MAKE_NEXT_BLOCK_TX_LIST(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC, TXLIST)
Definition chaingen.h:896
#define REGISTER_CALLBACK_METHOD(CLASS, METHOD)
Definition chaingen.h:859
#define DO_CALLBACK(VEC_EVENTS, CB_NAME)
Definition chaingen.h:849
#define MAKE_TX_LIST(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, HEAD)
Definition chaingen.h:962
#define SET_EVENT_VISITOR_SETT(VEC_EVENTS, SETT)
Definition chaingen.h:982
#define TESTS_DEFAULT_FEE
Definition chaingen.h:1092
#define MAKE_TX(VEC_EVENTS, TX_NAME, FROM, TO, AMOUNT, HEAD)
Definition chaingen.h:932
#define CHECK_EQ(v1, v2)
Definition chaingen.h:1089
#define MAKE_NEXT_BLOCK_TX1(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC, TX1)
Definition chaingen.h:878
Definition account.h:74
handles core cryptonote functionality
Definition cryptonote_core.h:87
Definition cryptonote_basic.h:205
bool mark_invalid_block(cryptonote::core &c, size_t ev_index, const std::vector< test_event_entry > &events)
Definition double_spend.inl:82
cryptonote::block m_last_valid_block
Definition double_spend.h:55
size_t m_invalid_block_index
Definition double_spend.h:57
bool mark_invalid_tx(cryptonote::core &c, size_t ev_index, const std::vector< test_event_entry > &events)
Definition double_spend.inl:75
bool check_double_spend(cryptonote::core &c, size_t ev_index, const std::vector< test_event_entry > &events)
Definition double_spend.inl:89
bool check_block_verification_context(const cryptonote::block_verification_context &bvc, size_t event_idx, const cryptonote::block &block)
Definition double_spend.inl:56
gen_double_spend_base()
Definition double_spend.inl:36
bool check_tx_verification_context(const cryptonote::tx_verification_context &tvc, bool tx_added, size_t event_idx, const cryptonote::transaction &tx)
Definition double_spend.inl:47
bool mark_last_valid_block(cryptonote::core &c, size_t ev_index, const std::vector< test_event_entry > &events)
Definition double_spend.inl:65
size_t m_invalid_tx_index
Definition double_spend.h:56
#define CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW
Definition cryptonote_config.h:44
const size_t invalid_index_value
Definition double_spend.h:34
#define INIT_DOUBLE_SPEND_TEST()
Definition double_spend.h:140
Definition blocks.cpp:13
crypto::hash get_block_hash(uint64_t height)
Definition output_distribution.cpp:95
#define blocks
Definition sha512-hash.c:11
Definition verification_context.h:66
bool m_verifivation_failed
Definition verification_context.h:68
Definition cryptonote_basic.h:475
Definition cryptonote_tx_utils.h:75
uint64_t amount
Definition cryptonote_tx_utils.h:77
account_public_address addr
Definition cryptonote_tx_utils.h:78
Definition cryptonote_tx_utils.h:43
crypto::public_key real_out_tx_key
Definition cryptonote_tx_utils.h:48
uint64_t amount
Definition cryptonote_tx_utils.h:51
bool rct
Definition cryptonote_tx_utils.h:52
uint64_t real_output
Definition cryptonote_tx_utils.h:47
uint64_t real_output_in_tx_index
Definition cryptonote_tx_utils.h:50
void push_output(uint64_t idx, const crypto::public_key &k, uint64_t amount)
Definition cryptonote_tx_utils.h:56
Definition verification_context.h:41
bool m_verifivation_failed
Definition verification_context.h:45
@ set_txs_keeped_by_block
Definition chaingen.h:116
bool generate(std::vector< test_event_entry > &events) const
Definition double_spend.inl:254
static const uint64_t send_amount
Definition double_spend.h:116
static const bool has_invalid_tx
Definition double_spend.h:117
static const bool has_invalid_tx
Definition double_spend.h:104
static const uint64_t send_amount
Definition double_spend.h:103
bool generate(std::vector< test_event_entry > &events) const
Definition double_spend.inl:219
bool generate(std::vector< test_event_entry > &events) const
Definition double_spend.inl:188
static const uint64_t send_amount
Definition double_spend.h:90
static const bool has_invalid_tx
Definition double_spend.h:91
static const bool has_invalid_tx
Definition double_spend.h:78
bool generate(std::vector< test_event_entry > &events) const
Definition double_spend.inl:161
static const uint64_t send_amount
Definition double_spend.h:77
bool generate(std::vector< test_event_entry > &events) const
Definition double_spend.inl:123