Electroneum
transactions_flow_test.cpp File Reference
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/uuid/random_generator.hpp>
#include <unordered_map>
#include "include_base_utils.h"
#include "wallet/wallet2.h"
Include dependency graph for transactions_flow_test.cpp:

Go to the source code of this file.

Macros

#define FIRST_N_TRANSFERS   10*10
 

Functions

std::string generate_random_wallet_name ()
 
uint64_t random (const uint64_t max_value)
 
bool do_send_etn (tools::wallet2 &w1, tools::wallet2 &w2, size_t mix_in_factor, uint64_t amount_to_transfer, transaction &tx, size_t parts=1)
 
uint64_t get_etn_in_first_transfers (const tools::wallet2::transfer_container &incoming_transfers, size_t n_transfers)
 
bool transactions_flow_test (std::string &working_folder, std::string path_source_wallet, std::string path_target_wallet, std::string &daemon_addr_a, std::string &daemon_addr_b, uint64_t amount_to_transfer, size_t mix_in_factor, size_t transactions_count, size_t transactions_per_second)
 

Macro Definition Documentation

◆ FIRST_N_TRANSFERS

#define FIRST_N_TRANSFERS   10*10

Definition at line 113 of file transactions_flow_test.cpp.

Function Documentation

◆ do_send_etn()

bool do_send_etn ( tools::wallet2 w1,
tools::wallet2 w2,
size_t  mix_in_factor,
uint64_t  amount_to_transfer,
transaction tx,
size_t  parts = 1 
)

Definition at line 61 of file transactions_flow_test.cpp.

62 {
63  CHECK_AND_ASSERT_MES(parts > 0, false, "parts must be > 0");
64 
65  std::vector<cryptonote::tx_destination_entry> dsts;
66  dsts.reserve(parts);
67  uint64_t amount_used = 0;
68  uint64_t max_part = amount_to_transfer / parts;
69 
70  for (size_t i = 0; i < parts; ++i)
71  {
74 
75  if (i < parts - 1)
76  de.amount = random(max_part);
77  else
78  de.amount = amount_to_transfer - amount_used;
79  amount_used += de.amount;
80 
81  //std::cout << "PARTS (" << amount_to_transfer << ") " << amount_used << " " << de.amount << std::endl;
82 
83  dsts.push_back(de);
84  }
85 
86  try
87  {
88  std::vector<tools::wallet2::pending_tx> ptx;
89  ptx = w1.create_transactions_2(dsts, mix_in_factor, 0, 0, std::vector<uint8_t>(), 0, {});
90  for (auto &p: ptx)
91  w1.commit_tx(p);
92  return true;
93  }
94  catch (const std::exception&)
95  {
96  return false;
97  }
98 }
void commit_tx(pending_tx &ptx_vector)
Definition: wallet2.cpp:6887
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
Definition: misc_log_ex.h:181
const account_keys & get_keys() const
Definition: account.cpp:264
std::vector< wallet2::pending_tx > create_transactions_2(std::vector< cryptonote::tx_destination_entry > dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector< uint8_t > &extra, uint32_t subaddr_account, std::set< uint32_t > subaddr_indices)
Definition: wallet2.cpp:9725
unsigned __int64 uint64_t
Definition: stdint.h:136
uint64_t amount
account_public_address addr
account_public_address m_account_address
Definition: account.h:43
cryptonote::account_base & get_account()
Definition: wallet2.h:734
uint64_t random(const uint64_t max_value)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ generate_random_wallet_name()

std::string generate_random_wallet_name ( )

Definition at line 47 of file transactions_flow_test.cpp.

48 {
49  std::stringstream ss;
50  ss << boost::uuids::random_generator()();
51  return ss.str();
52 }
Here is the caller graph for this function:

◆ get_etn_in_first_transfers()

uint64_t get_etn_in_first_transfers ( const tools::wallet2::transfer_container incoming_transfers,
size_t  n_transfers 
)

Definition at line 100 of file transactions_flow_test.cpp.

101 {
102  uint64_t summ = 0;
103  size_t count = 0;
104  BOOST_FOREACH(const tools::wallet2::transfer_details& td, incoming_transfers)
105  {
106  summ += td.m_tx.vout[td.m_internal_output_index].amount;
107  if(++count >= n_transfers)
108  return summ;
109  }
110  return summ;
111 }
mdb_size_t count(MDB_cursor *cur)
unsigned __int64 uint64_t
Definition: stdint.h:136
cryptonote::transaction_prefix m_tx
Definition: wallet2.h:304
Here is the call graph for this function:
Here is the caller graph for this function:

◆ random()

uint64_t random ( const uint64_t  max_value)
inline

Definition at line 54 of file transactions_flow_test.cpp.

54  {
55  return (uint64_t(rand()) ^
56  (uint64_t(rand())<<16) ^
57  (uint64_t(rand())<<32) ^
58  (uint64_t(rand())<<48)) % max_value;
59 }
void rand(size_t N, uint8_t *bytes)
Definition: crypto.h:209
unsigned __int64 uint64_t
Definition: stdint.h:136
Here is the call graph for this function:
Here is the caller graph for this function:

◆ transactions_flow_test()

bool transactions_flow_test ( std::string &  working_folder,
std::string  path_source_wallet,
std::string  path_target_wallet,
std::string &  daemon_addr_a,
std::string &  daemon_addr_b,
uint64_t  amount_to_transfer,
size_t  mix_in_factor,
size_t  transactions_count,
size_t  transactions_per_second 
)

Definition at line 115 of file transactions_flow_test.cpp.

121 {
122  LOG_PRINT_L0("-----------------------STARTING TRANSACTIONS FLOW TEST-----------------------");
123  tools::wallet2 w1, w2;
124  if(path_source_wallet.empty())
125  path_source_wallet = generate_random_wallet_name();
126 
127  if(path_target_wallet.empty())
128  path_target_wallet = generate_random_wallet_name();
129 
130 
131  try
132  {
133  w1.generate(working_folder + "/" + path_source_wallet, "");
134  w2.generate(working_folder + "/" + path_target_wallet, "");
135  }
136  catch (const std::exception& e)
137  {
138  LOG_ERROR("failed to generate wallet: " << e.what());
139  return false;
140  }
141 
142  w1.init(daemon_addr_a);
143 
144  uint64_t blocks_fetched = 0;
145  bool received_etn;
146  bool ok;
147  if(!w1.refresh(true, blocks_fetched, received_etn, ok))
148  {
149  LOG_ERROR( "failed to refresh source wallet from " << daemon_addr_a );
150  return false;
151  }
152 
153  w2.init(daemon_addr_b);
154 
155  MGINFO_GREEN("Using wallets: " << ENDL
156  << "Source: " << w1.get_account().get_public_address_str(MAINNET) << ENDL << "Path: " << working_folder + "/" + path_source_wallet << ENDL
157  << "Target: " << w2.get_account().get_public_address_str(MAINNET) << ENDL << "Path: " << working_folder + "/" + path_target_wallet);
158 
159  //lets do some etn
161  COMMAND_RPC_STOP_MINING::request daemon1_req = AUTO_VAL_INIT(daemon1_req);
162  COMMAND_RPC_STOP_MINING::response daemon1_rsp = AUTO_VAL_INIT(daemon1_rsp);
163  bool r = http_client.set_server(daemon_addr_a, boost::none) && net_utils::invoke_http_json("/stop_mine", daemon1_req, daemon1_rsp, http_client, std::chrono::seconds(10));
164  CHECK_AND_ASSERT_MES(r, false, "failed to stop mining");
165 
166  COMMAND_RPC_START_MINING::request daemon_req = AUTO_VAL_INIT(daemon_req);
167  COMMAND_RPC_START_MINING::response daemon_rsp = AUTO_VAL_INIT(daemon_rsp);
168  daemon_req.miner_address = w1.get_account().get_public_address_str(MAINNET);
169  daemon_req.threads_count = 9;
170  r = net_utils::invoke_http_json("/start_mining", daemon_req, daemon_rsp, http_client, std::chrono::seconds(10));
171  CHECK_AND_ASSERT_MES(r, false, "failed to start mining getrandom_outs");
172  CHECK_AND_ASSERT_MES(daemon_rsp.status == CORE_RPC_STATUS_OK, false, "failed to start mining");
173 
174  //wait for etn, until balance will have enough etn
175  w1.refresh(true, blocks_fetched, received_etn, ok);
176  while(w1.unlocked_balance(0, false) < amount_to_transfer)
177  {
179  w1.refresh(true, blocks_fetched, received_etn, ok);
180  }
181 
182  //lets make a lot of small outs to ourselves
183  //since it is not possible to start from transaction that bigger than 20Kb, we gonna make transactions
184  //with 500 outs (about 18kb), and we have to wait appropriate count blocks, mined for test wallet
185  while(true)
186  {
187  tools::wallet2::transfer_container incoming_transfers;
188  w1.get_transfers(incoming_transfers);
189  if(incoming_transfers.size() > FIRST_N_TRANSFERS && get_etn_in_first_transfers(incoming_transfers, FIRST_N_TRANSFERS) < w1.unlocked_balance(0, false) )
190  {
191  //lets go!
192  size_t count = 0;
193  BOOST_FOREACH(tools::wallet2::transfer_details& td, incoming_transfers)
194  {
196  bool r = do_send_etn(w1, w1, 0, td.m_tx.vout[td.m_internal_output_index].amount - TEST_FEE, tx_s, 50);
197  CHECK_AND_ASSERT_MES(r, false, "Failed to send starter tx " << get_transaction_hash(tx_s));
198  MGINFO_GREEN("Starter transaction sent " << get_transaction_hash(tx_s));
199  if(++count >= FIRST_N_TRANSFERS)
200  break;
201  }
202  break;
203  }else
204  {
206  w1.refresh(true, blocks_fetched, received_etn, ok);
207  }
208  }
209  //do actual transfer
210  uint64_t transfered_etn = 0;
211  uint64_t transfer_size = amount_to_transfer/transactions_count;
212  size_t i = 0;
213  struct tx_test_entry
214  {
215  transaction tx;
216  size_t m_received_count;
217  uint64_t amount_transfered;
218  };
219  crypto::key_image lst_sent_ki = AUTO_VAL_INIT(lst_sent_ki);
220  std::unordered_map<crypto::hash, tx_test_entry> txs;
221  for(i = 0; i != transactions_count; i++)
222  {
223  uint64_t amount_to_tx = (amount_to_transfer - transfered_etn) > transfer_size ? transfer_size: (amount_to_transfer - transfered_etn);
224  while(w1.unlocked_balance(0, false) < amount_to_tx + TEST_FEE)
225  {
227  LOG_PRINT_L0("not enough ETN, waiting for cashback or mining");
228  w1.refresh(true, blocks_fetched, received_etn, ok);
229  }
230 
231  transaction tx;
232  /*size_t n_attempts = 0;
233  while (!do_send_etn(w1, w2, mix_in_factor, amount_to_tx, tx)) {
234  n_attempts++;
235  std::cout << "failed to transfer ETN, refresh and try again (attempts=" << n_attempts << ")" << std::endl;
236  w1.refresh();
237  }*/
238 
239 
240  if(!do_send_etn(w1, w2, mix_in_factor, amount_to_tx, tx))
241  {
242  LOG_PRINT_L0("failed to transfer ETN, tx: " << get_transaction_hash(tx) << ", refresh and try again" );
243  w1.refresh(true, blocks_fetched, received_etn, ok);
244  if(!do_send_etn(w1, w2, mix_in_factor, amount_to_tx, tx))
245  {
246  LOG_PRINT_L0( "failed to transfer ETN, second chance. tx: " << get_transaction_hash(tx) << ", exit" );
247  LOCAL_ASSERT(false);
248  return false;
249  }
250  }
251  lst_sent_ki = boost::get<txin_to_key>(tx.vin[0]).k_image;
252 
253  transfered_etn += amount_to_tx;
254 
255  LOG_PRINT_L0("transferred " << amount_to_tx << ", i=" << i );
256  tx_test_entry& ent = txs[get_transaction_hash(tx)] = boost::value_initialized<tx_test_entry>();
257  ent.amount_transfered = amount_to_tx;
258  ent.tx = tx;
259  //if(i % transactions_per_second)
260  // misc_utils::sleep_no_w(1000);
261  }
262 
263 
264  LOG_PRINT_L0( "waiting some new blocks...");
265  misc_utils::sleep_no_w(DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN*20*1000);//wait two blocks before sync on another wallet on another daemon
266  LOG_PRINT_L0( "refreshing...");
267  bool recvd_etn = false;
268  while(w2.refresh(true, blocks_fetched, recvd_etn, ok) && ( (blocks_fetched && recvd_etn) || !blocks_fetched ) )
269  {
270  misc_utils::sleep_no_w(DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN*1000);//wait two blocks before sync on another wallet on another daemon
271  }
272 
273  uint64_t etn_2 = w2.balance(0, false);
274  if(etn_2 == transfered_etn)
275  {
276  MGINFO_GREEN("-----------------------FINISHING TRANSACTIONS FLOW TEST OK-----------------------");
277  MGINFO_GREEN("transferred " << print_etn(transfered_etn) << " via " << i << " transactions" );
278  return true;
279  }else
280  {
282  w2.get_transfers(tc);
283  BOOST_FOREACH(tools::wallet2::transfer_details& td, tc)
284  {
285  auto it = txs.find(td.m_txid);
286  CHECK_AND_ASSERT_MES(it != txs.end(), false, "transaction not found in local cache");
287  it->second.m_received_count += 1;
288  }
289 
290  BOOST_FOREACH(auto& tx_pair, txs)
291  {
292  if(tx_pair.second.m_received_count != 1)
293  {
294  MERROR("Transaction lost: " << get_transaction_hash(tx_pair.second.tx));
295  }
296 
297  }
298 
299  MERROR("-----------------------FINISHING TRANSACTIONS FLOW TEST FAILED-----------------------" );
300  MERROR("income " << print_etn(etn_2) << " via " << i << " transactions, expected ETN = " << print_etn(transfered_etn) );
301  LOCAL_ASSERT(false);
302  return false;
303  }
304 
305  return true;
306 }
#define MERROR(x)
Definition: misc_log_ex.h:73
uint64_t unlocked_balance(uint32_t subaddr_index_major, bool public_blockchain, uint64_t *blocks_to_unlock=NULL) const
Definition: wallet2.cpp:6172
#define LOCAL_ASSERT(expr)
Definition: misc_log_ex.h:122
std::string print_etn(uint64_t amount, unsigned int decimal_point)
uint64_t balance(uint32_t subaddr_index_major, bool public_blockchain) const
Definition: wallet2.cpp:6162
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
Definition: misc_log_ex.h:181
bool invoke_http_json(const boost::string_ref uri, const t_request &out_struct, t_response &result_struct, t_transport &transport, std::chrono::milliseconds timeout=std::chrono::seconds(15), const boost::string_ref method="GET")
#define LOG_PRINT_L0(x)
Definition: misc_log_ex.h:99
std::string get_public_address_str(network_type nettype) const
Definition: account.cpp:269
#define FIRST_N_TRANSFERS
#define CORE_RPC_STATUS_OK
#define MGINFO_GREEN(x)
Definition: misc_log_ex.h:82
mdb_size_t count(MDB_cursor *cur)
std::vector< transfer_details > transfer_container
Definition: wallet2.h:449
bool init(std::string daemon_address="http://localhost:8080", boost::optional< epee::net_utils::http::login > daemon_login=boost::none, boost::asio::ip::tcp::endpoint proxy={}, uint64_t upper_transaction_weight_limit=0, bool trusted_daemon=true, epee::net_utils::ssl_options_t ssl_options=epee::net_utils::ssl_support_t::e_ssl_support_autodetect, std::string blockchain_db_path="")
Definition: wallet2.cpp:1282
unsigned __int64 uint64_t
Definition: stdint.h:136
cryptonote::transaction_prefix m_tx
Definition: wallet2.h:304
std::string generate_random_wallet_name()
bool sleep_no_w(long ms)
#define LOG_ERROR(x)
Definition: misc_log_ex.h:98
#define ENDL
Definition: misc_log_ex.h:149
POD_CLASS key_image
Definition: crypto.h:102
crypto::hash get_transaction_hash(const transaction &t)
uint64_t get_etn_in_first_transfers(const tools::wallet2::transfer_container &incoming_transfers, size_t n_transfers)
#define AUTO_VAL_INIT(v)
Definition: misc_language.h:53
cryptonote::account_base & get_account()
Definition: wallet2.h:734
#define DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN
bool do_send_etn(tools::wallet2 &w1, tools::wallet2 &w2, size_t mix_in_factor, uint64_t amount_to_transfer, transaction &tx, size_t parts=1)
void refresh(bool trusted_daemon)
Definition: wallet2.cpp:3060
void generate(const std::string &wallet_, const epee::wipeable_string &password, const epee::wipeable_string &multisig_data, bool create_address_file=false)
Generates a wallet or restores one.
Definition: wallet2.cpp:4869
void get_transfers(wallet2::transfer_container &incoming_transfers) const
Definition: wallet2.cpp:6315
Here is the call graph for this function:
Here is the caller graph for this function: