From e77ec2309be1a61cb4d4e1b2caf9c8128c3de417 Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Tue, 3 Jul 2018 10:54:48 +0800 Subject: [PATCH] select_for_tx templated and new tests added --- src/MySqlAccounts.cpp | 134 ++++++++----------------------------- src/MySqlAccounts.h | 29 ++++---- src/YourMoneroRequests.cpp | 8 +-- src/ssqlses.h | 7 +- tests/mysql_tests.cpp | 114 +++++++++++++++++++++++++++++++ 5 files changed, 163 insertions(+), 129 deletions(-) diff --git a/src/MySqlAccounts.cpp b/src/MySqlAccounts.cpp index f80e46f..ae565b5 100755 --- a/src/MySqlAccounts.cpp +++ b/src/MySqlAccounts.cpp @@ -18,34 +18,6 @@ MysqlInputs::MysqlInputs(shared_ptr _conn) : conn {_conn} {} -bool -MysqlInputs::select_for_tx(const uint64_t& address_id, vector& ins) -{ - - Query query = conn->query(XmrInput::SELECT_STMT2); - query.parse(); - - try - { - query.storein(ins, address_id); - - return !ins.empty(); - } - catch (mysqlpp::Exception& e) - { - MYSQL_EXCEPTION_MSG(e); - //throw e; - } - catch (std::exception& e) - { - MYSQL_EXCEPTION_MSG(e); - //throw e; - } - - return false; -} - - bool MysqlInputs::select_for_out(const uint64_t& output_id, vector& ins) { @@ -106,33 +78,6 @@ MysqlOutpus::select(uint64_t out_id, XmrOutput& out) -bool -MysqlOutpus::select_for_tx(const uint64_t& tx_id, vector& outs) -{ - Query query = conn->query(XmrOutput::SELECT_STMT2); - query.parse(); - - try - { - query.storein(outs, tx_id); - - return !outs.empty(); - } - catch (mysqlpp::Exception& e) - { - MYSQL_EXCEPTION_MSG(e); - //throw e; - } - catch (std::exception& e) - { - MYSQL_EXCEPTION_MSG(e); - //throw e; - } - - return false; -} - - bool MysqlOutpus::exist(const string& output_public_key_str, XmrOutput& out) { @@ -383,49 +328,13 @@ bool MySqlAccounts::select(const string& address, XmrAccount& account) { - Query query = conn->query(XmrAccount::SELECT_STMT); - query.parse(); - - try - { - vector res; - query.storein(res, address); - - if (!res.empty()) - { - account = res.at(0); - return true; - } - - } - catch (std::exception& e) - { - MYSQL_EXCEPTION_MSG(e); - //throw e; - } - - return false; -} - -bool -MySqlAccounts::select(const int64_t& acc_id, XmrAccount& account) -{ - - if (!conn->connect()) - { - cerr << __FUNCTION__ << ":" << __LINE__ - << " failed connecting to mysql" - << endl; - return false; - } - Query query = conn->query(XmrAccount::SELECT_STMT2); query.parse(); try { vector res; - query.storein(res, acc_id); + query.storein(res, address); if (!res.empty()) { @@ -509,11 +418,11 @@ uint64_t MySqlAccounts::insert(const vector& data_to_inser template uint64_t MySqlAccounts::insert(const vector& data_to_insert); -template +template bool MySqlAccounts::select(uint64_t account_id, vector& selected_data) { - Query query = conn->query(T::SELECT_STMT); + Query query = conn->query((query_no == 1 ? T::SELECT_STMT : T::SELECT_STMT2)); query.parse(); try @@ -531,15 +440,40 @@ MySqlAccounts::select(uint64_t account_id, vector& selected_data) return false; } +template +bool MySqlAccounts::select(uint64_t account_id, vector& selected_data); + template bool MySqlAccounts::select(uint64_t account_id, vector& selected_data); template bool MySqlAccounts::select(uint64_t account_id, vector& selected_data); +template // this will use SELECT_STMT2 which selectes based on transaction id, not account_id, +bool MySqlAccounts::select(uint64_t tx_id, vector& selected_data); + template bool MySqlAccounts::select(uint64_t account_id, vector& selected_data); +template // this will use SELECT_STMT2 which selectes based on transaction id, not account_id, +bool MySqlAccounts::select(uint64_t tx_id, vector& selected_data); + + +template +bool +MySqlAccounts::select_for_tx(uint64_t tx_id, vector& selected_data) +{ + return select(tx_id, selected_data); +} + +template // this will use SELECT_STMT2 which selectes based on transaction id, not account_id, +bool MySqlAccounts::select_for_tx(uint64_t tx_id, vector& selected_data); + + +template // this will use SELECT_STMT2 which selectes based on transaction id, not account_id, +bool MySqlAccounts::select_for_tx(uint64_t tx_id, vector& selected_data); + + bool MySqlAccounts::select_txs_for_account_spendability_check( const uint64_t& account_id, @@ -645,18 +579,6 @@ MySqlAccounts::select_output_with_id(const uint64_t& out_id, XmrOutput& out) return mysql_out->select(out_id, out); } -bool -MySqlAccounts::select_outputs_for_tx(const uint64_t& tx_id, vector& outs) -{ - return mysql_out->select_for_tx(tx_id, outs); -} - -bool -MySqlAccounts::select_inputs_for_tx(const uint64_t& tx_id, vector& ins) -{ - return mysql_in->select_for_tx(tx_id, ins); -} - bool MySqlAccounts::select_inputs_for_out(const uint64_t& output_id, vector& ins) diff --git a/src/MySqlAccounts.h b/src/MySqlAccounts.h index 774d7f2..b8c7e15 100755 --- a/src/MySqlAccounts.h +++ b/src/MySqlAccounts.h @@ -45,9 +45,6 @@ public: bool select(const uint64_t& address_id, vector& ins); - bool - select_for_tx(const uint64_t& address_id, vector& ins); - bool select_for_out(const uint64_t& output_id, vector& ins); }; @@ -66,9 +63,6 @@ public: bool select(uint64_t out_id, XmrOutput& outs); - bool - select_for_tx(const uint64_t& tx_id, vector& outs); - bool exist(const string& output_public_key_str, XmrOutput& out); }; @@ -144,9 +138,6 @@ public: bool select(const string& address, XmrAccount& account); - bool - select(const int64_t& acc_id, XmrAccount& account); - template uint64_t insert(const T& data_to_insert); @@ -155,10 +146,22 @@ public: uint64_t insert(const vector& data_to_insert); - template + /** + * + * @tparam T + * @tparam query_no which query to use, for SELECT_STMT or SELECT_STMT2 + * @param account_id + * @param selected_data + * @return + */ + template bool select(uint64_t account_id, vector& selected_data); + template + bool + select_for_tx(uint64_t tx_id, vector& selected_data); + bool select_txs_for_account_spendability_check(const uint64_t& account_id, vector& txs); @@ -166,12 +169,6 @@ public: bool select_output_with_id(const uint64_t& out_id, XmrOutput& out); - bool - select_outputs_for_tx(const uint64_t& tx_id, vector& outs); - - bool - select_inputs_for_tx(const uint64_t& tx_id, vector& ins); - bool select_inputs_for_out(const uint64_t& output_id, vector& ins); diff --git a/src/YourMoneroRequests.cpp b/src/YourMoneroRequests.cpp index e64ae68..9151e30 100755 --- a/src/YourMoneroRequests.cpp +++ b/src/YourMoneroRequests.cpp @@ -248,7 +248,7 @@ YourMoneroRequests::get_address_txs(const shared_ptr< Session > session, const B vector inputs; - if (xmr_accounts->select_inputs_for_tx(tx.id.data, inputs)) + if (xmr_accounts->select_for_tx(tx.id.data, inputs)) { json j_spent_outputs = json::array(); @@ -447,7 +447,7 @@ YourMoneroRequests::get_address_info(const shared_ptr< Session > session, const { vector outs; - if (xmr_accounts->select_outputs_for_tx(tx.id.data, outs)) + if (xmr_accounts->select_for_tx(tx.id.data, outs)) { for (XmrOutput &out: outs) { @@ -598,7 +598,7 @@ YourMoneroRequests::get_unspent_outs(const shared_ptr< Session > session, const vector outs; - if (xmr_accounts->select_outputs_for_tx(tx.id.data, outs)) + if (xmr_accounts->select_for_tx(tx.id.data, outs)) { for (XmrOutput &out: outs) { @@ -1410,7 +1410,7 @@ YourMoneroRequests::get_tx(const shared_ptr< Session > session, const Bytes & bo vector inputs; - if (xmr_accounts->select_inputs_for_tx(xmr_tx.id.data, inputs)) + if (xmr_accounts->select_for_tx(xmr_tx.id.data, inputs)) { json j_spent_outputs = json::array(); diff --git a/src/ssqlses.h b/src/ssqlses.h index fcd685a..ee14b1a 100755 --- a/src/ssqlses.h +++ b/src/ssqlses.h @@ -43,15 +43,16 @@ sql_create_8(Accounts, 1, 6, struct XmrAccount : public Accounts, Table { - static constexpr const char* SELECT_STMT = R"( - SELECT * FROM `Accounts` WHERE `address` = (%0q) + SELECT * FROM `Accounts` WHERE `id` = (%0q) )"; + static constexpr const char* SELECT_STMT2 = R"( - SELECT * FROM `Accounts` WHERE `id` = (%0q) + SELECT * FROM `Accounts` WHERE `address` = (%0q) )"; + static constexpr const char* INSERT_STMT = R"( INSERT INTO `Accounts` (`address`, `viewkey_hash`, `scanned_block_height`, diff --git a/tests/mysql_tests.cpp b/tests/mysql_tests.cpp index 94c5804..db00c2c 100644 --- a/tests/mysql_tests.cpp +++ b/tests/mysql_tests.cpp @@ -343,6 +343,7 @@ TEST_F(MYSQL_TEST, IfTxExistsForInNoneOnwnerAccount) TEST_F(MYSQL_TEST, DeleteExistingTx) { + // tx hash fc4b8d5956b30dc4a353b171b4d974697dfc32730778f138a8e7f16c11907691 TX_AND_ACC_FROM_HEX(tx_fc4_hex, owner_addr_5Ajfk); xmreg::XmrTransaction tx_data; @@ -354,6 +355,53 @@ TEST_F(MYSQL_TEST, DeleteExistingTx) EXPECT_EQ(no_of_deleted_rows, 1); } +string tx_1640_hex {"020002020007d08602b5019318990e8e469607ac6645d3cf7b4f5db9d614602e9e956c63c35cf3da6f7b93740c514e06c898fb0da2020007bb76e15af107934aa55f8156b6163ef54482411c54a280081a87fd35e542b3b8906b702123c55468e71dd620d3a402000254b5891ba8c1de2419bcc877383f004929e01a8ef8f9b5ae87549c5a5284d7710002a9d876b01eb972db944b78899b4c90c2b66a3c81fe04bf54ff61565f3db534194201cbfd2dec16b9cb35c8b5177e18615e7273b2bd43517dca8bd9ec9aaae6b7f67d01cbfd2dec16b9cb35c8b5177e18615e7273b2bd43517dca8bd9ec9aaae6b7f67d0280fa9b98fd01d82bde315b0324aa236d87c7dd34bee321eef33186febc0a38d0d57090027dfa03aa67466407567b7f8c1fa4587c003fe89426787b1a96f30e4a2a010fc685a095aa65eb5c3fac215aaab75565381a0721d50199fb902f58bf0dbc7a19f9ef086da5fd12a08dd89ab63e8becfffc1b2ad6510e4753b06191092e0ff159d18202a80d1e7a2ac0ff89f7151e1d8736b4a4b720464a262f52bba0c2ffa5355b3a0bbd5a5a87a2610c12d2edc410d2d26fc855c1ea3ce211e19881a4bc79b7ef28045951e126e8a05f6d69a9736691988eab8d711501f8b9098d9e4338c1da65da4fdadad568ed09dd2ce4f22b8375bc3c8fb7391af13ad24d34eed99cc61977a853d1f98016ed8610632bbcc6c31257359858afe724492953d2580973518efd1003e906f2c04ba82f9a758e2c79b9bf9741af8ad259357e31935fcd33c02167bf0bbebecf0529db992fd3634a165407ed6cabdfe53c794f0070ffc0a2f862ea720908986e1b8c458e8d3782b22ecfc230df2e10686b3c4ac2f801e308a248485e0d2d005cc47dfc92da9d5b57202e1a267784d98bcb2bc385fd8d6b119ee2ce7e0c14a7991413bc310871d53fcbe2d863c074d136ef4b912e1a93d00c92f777cd024bf4b84ba5688b84ef989a3cf56db681bf973dff7149610fc9c4f901f0b2bb0589cf064b9da57fc5506dbc058a76d7a960bd489c22dd58290b552359d53e6e0bbcc2443684d6410ce8f0c480f719532022a52cd0dbe87d8feb81a2180e45e90b30fa0ca3b81d6ad3940d78a181691c427c4211042b556a054388163b49ee4b0a188d4fa530af830ad5bacfc6333e33943af4b4b8d7c34293d52bb0e5a6259a06b2a31ee6529d55860ccb9b6b087bcde693afc82cb76eda4b981f8593e78bf703d2cdbcf3e2ac02b0ec66ce864ed5f00ca70acacaf87530b3d87289b45db3b007a080e9cff29bd7fd27d5ad5e978ab0eac1a4b789a942b8f37639cd8df0787a023e1d32610f6d775262974b398bfca302c6c43bbcf9b27b2796fd1cf7d135c801f55ca6595183f79d8ec32a1bcb5a61314952b73ed488fa77622cb3d3cb7b43049af38ce804cdfd5055c4368ffd8ddbf83ac71da0949079bae68ecd699216ea086b4e32de20a89284cee23058ecb2537719fd1c5d9979d88242a1473e58b91e016905d79511ab3ea90aca5722982099cac5e143ccea4d9cd0aba68d3196170c007a28fd08646dbb02c60e37a85e978e60dc5367322572c9af86f60a4e7893000d5c6acb5a1463bc3b114f14a00679b3bcda4d9f4ecbe12879c83f51debad5d6044905edef20946562bfc928e0dbc504b266dbeda3f8d7a4e1adf26019176626010a0e53a56cc387bae895f22d8dde4e4dc07a8cac57dfcb974c225e94462ae100b5fb06aa5f8829d9d8c318f0e60a609c9a5b0b5646471b939044458df98f33095e034929c8095cf28ea4fa2f515161e007b7f63ce164f7150ebe7df571ee1a0abe14e63260d891f8d800019fb32b6b421b683b9dcfe739bf3e85c1125a59890f6259f127ef8aa309f226506cbdc7e0362d327c01b24d4897c42fbc9c7b7fd101287dd6c1576e4db50eeaf9512902d880e05bace368d83cd0a3ed44fa9bfb0706a7429addc2491fb0325bb19c8996637c307851374e7d27dc09e779349c2c06043b5efd3a3cd045e5fad7e1735dceaadbac2e08189e2b1e2138fdf1ff783fb3093d0486430d62adc0687fbf8547765ce63ef4d637fda88836882bc6fbcf723000c84457bac63973793bce419d5a2f3b2b6b72c84e8dfdd8799a3c2d37f81b0607f8a09809afd99e51262b5e372278553504bb5862f7b2a57d05296c1bca79b407d1c88c875e7f7212c38b64826a83ac2fcce37888b86a870eeccfb35f4042470e3d0ef3a4fcf02c645644e33641de834ab3d37315dc3f508580f6734e1df9e10fd368a0cd8a4e58c5d259dce025ebb299478712e9ffde3ecbc67e71d3c9eaa20f898829cdc7bb2ffc041df360d14bc683ebbc62c6995fd2ae5b99b433dc18ca05dc05710159dfaf2b85f65c1949e9ba64efd068dc1626d7ac3899d0770d083f01818867a3d18b531cd7d46630e9f9582e30e6d8977cfe02ee48032b84f2bfc908cb21db8ddf71d64bff7a67f605801d5903fdf6c7bd76ed1a7842c2be672d6a0bc3f4b7aecab3203cfafff53b4647650db10c3af55521491c31b57e9581a7410d432303747fc20fd0d34b978450df1448a50f5a83a5b1598fdc0964e9501dff0cd345f2adedf34a0772970e5ea30c6c30671b49721dad3ef863beb92d89513b0b3c5190b4293c1f7a90f93f53cee4c4ed02b55d6c7c7450f04a81cc4f663ab80828a65d7342c17d17dd366c6db0b05d58a9be78ff2428ae878ba4ca7091b1910b120408bc946c2c0f6195e5a884b3399cec920d2117ebe56d759b51d5b4d838048a4322bfa22daaa42a5b7d9c2ec7682926e5e8473335905a440b50b4110f6a051a8709754281fec21f7a9252e989dc127c489fcef630d7d12c99b34e0fa101012b663304f27a9ba7b1391100bf2079c98b3dca37f7d6eb6f80d5e032635d8303ab8812cb9e6d8ed68f4bb505ec2ab20b2c9bd14576b4ca38a5e264e104ba730cafef08919f21b09414b25a78c680c496e0916925fb70cc26bdb92b7b5b7a5c0e539c8a67c1ddde3243ad30f7c0f0873686b7a6913df1e8381c0067183e1c2a0d529adb661cc18fd226298bb6040411dc169aad5d6f5e80bbff00bf5635d9500954341fef317b3ef58bf428eaecf52567ba995fd126ba5dc9328824348f827208f4ffa19a4bf6a50235d9dd6f59d6231471ac31bb4e2a70ff91652ae11adf320f73d286b43d26986bdfa07f0740c8f5091ee1f2aa01f76a04ccc117f50eac550f2e63d76734274e520ccb794f614902edb433449d8f6376ebb3b0ca37e3dc6c00e264e9767efccce7984006bffb606559c4933db4ada7e48b6cda74fb45481c09d5fbcad64ede0c35f31e30258a7b13201723eece318c6dbe9d4ff0d930a3520e41b7c6242177abf7e55a30ad955af77fd01d8113c93fa218164256b51ca5f702a1729aa6ca79da812c5fbc95f66ad0b17ffe1e6738cd459fbf188495aa58ca0820730ef1462241797287dbab3305762995b2c26f127a3d4ab77f5997b3137a035d99ab26278f1c1f55e6216d43f89c4ed464acf6bcaa00abe2b1ab1710ce090894ec9c3c037b1d9ba3781218161a061578fe80e66023147a6aa28aabb6bdeb0cb7f4e362fa41fa067054018f785cbaf0fd7eb0b00b706e9d78bea4c8273c4b04ce5fa38084f13781913e645f221fb7c813ca90944d9e46f28538f2fc7a1c1a07f2ff0052c692451b1a0d099fece7a9b25bdc7d0b4a88d12bd6160727c54bfb0a2dc11baa3f5f4439950a4e23f88afc673e880670d5faa29e339e45dc8973880587daf25544f2af5efad48846b4750646b417b178b127e4fb7694b72a9827460e5c041fe13002875d1850f66bac6f153231122d51b7948be2a1a45e0a66b9a909e8a9e93fef114884164a388743e048e0a9d262452ec7c494ae2974c41219110e14df0d487e820924fbb5de949b811bc2f7ce2e31af6c46d67d9e3fd35eb0ae0aeb74f8add01ea5ad7fa708f129670a636c3224dcf1c908ea6852afedb152920b73ee3e0594b50d05f22059a4f536ac619ac8235e1ad675d6b5207fb29f1d0f013d719023ea1291e8070f7385af52cee9432e2a05236bc5df2f6e79c308d0950192f6cb1dfcff809c1b048cd9796dc27750e51ecaeddecce534e26510c1a8240db192b4a996982066dd1823f39f9cb0cf5d729c2d608d7a25b3f9620f9998b50ad13c7e44919cd6f8d49127d6b8edbecb325a4dc6d2874a16c4bca46da49e510cf51030d536ceba148271c9b25c93727c17ad6c8664313c6d82a8865381282f0b2df3a52d5ba494b93e0a38e4bd6ab461167d50b4c566df3647cbdcf63bf4c901903374972ca9bbab1c46788e554727267136b2c70f4cdf62a758abafefd48f06650c2ee3eb0d4adacef120c3e602d8684d09b7bc77dfe7abcf6d879051aaa20248069e025ca07df2f90a5cb992adff4a3500109101c20ffcb09f4050daebdf01f2d3b3b2eb988babacee8e3f3c2d5243fa932e9554dfdcaa245e7536e0d7470c5fd5353518544bb620da91c5ea12ee5fdddc083c91c0dc235033b60e2d525200ce293bc046f3b04cf0f5b73175b0ace5c9b295a15f9fb04306b73b21ba701109e348765264529a1bfeb3b0839ecaae94d985c99c095809d992a889c4c0ee230e83f16d11cd25d172336dd11c1b2913aeb9ac3b90d8e6db8654d623b85fa15902a61b8149adcb35d0ffcb72e804d36d41827c327139a0f7ecbc2685e62bdb870b05197679d6509b08fb458c2394cfab860a70edafd37d52af5f42ddaeda125d092eccdce9d6c6375988f2a0d93b72eabd044fa1aaa4ac0f71f33984114c4409038780d60a500829d4bd2302680965e3c3fe2779c8cfeb22abc37034df926b1e0baffdbbd2a844fedfe523c9e922f7342e53567dc2f0a1c52e3958d4dc21b075080c42427ed1f287bcba9e202daa5e1c216eb203aa52c7c6b00e38c865ade17307d51082a7ee880b64487fe16fbd1abf9e2044817136f7a571caed2d6eca24c402965cb741098e1ad46aaedb55f97f4a6e7bf96ac64262f7a16cd93497d81a6b0becff75632838c6fca810c8ff8f7bb8ff6092472eb0418c6feac0056314deb005887adba7e19af0fda0ed694c041709b6739fa6bc58dbe4d9761777cd7829a50926bc3814ec4227e9b81ae3b48186fa683aa721da09a06444ced71a0c5f8abc034740ab09c1b9247a45bcebd8ea1d57022d5f47f2fb41eb75fb7ad4c23de48e0d70fb25c0ff68db1ff3ade50889548c22782f8d7eafe4e54c36d45538158ee00c69e6f3f7fff561ccf532c2e1a1b870e52ab0c380fa7ef5fa9c93144a3469b20b7e2eb5f6e13f5a3eee6631cb7a8673f1ac175fe97b71c613336e2ccd7b6dcf058161e1f15eae11460d3df68bff20402f9e4d86a4a842d54bf8a150dc10b25a05f5cf57fb6a7036a55b880c134828a9e39d647ffbec94d9e12dba7ce6d7741702fff89137499e9ad8a9ef2e7c685101ba98af0c87e9f132c3459d8942c00442080f13dea6233c30e46ef46fc2f8c7deee1bd15568d08218fdf24d6e0d20730d04e3856b7556f2dd6ae74838bf189e4266bb069be3836d5d45cbfd3ed5856cef08f0765bf45ef900d51c0a38e8434ac9ab4efc1af79bf952f2dc3ee36b668cf808083620b61c6040a9b7635eb11ed847dd15834dd1ee826e4c37b51a8aabf6510a3a08e79d2bf4bce66dab207fad2e1208600e2565a3ceb34c91645469527f2502bdb433e1106b87dc3f405bed626932bcca26c1fd0da2c99fe40320e2cbe9f00515d6cf6eafbc6f86afe80ab532958cc34293304cd5f2e795eeea56728a77da01acd3d807a4a3f26d7e61f68d4ed5a8c0c6a725be564edf9ff05fab91e93df10c3ca8d3f9466b98892f7d58383184b2113f23339efb985a5bbf0e116230a348094450178a7345fd8954d0438cc3e0b8e0d53e6430d7dac95ade2f2afce72d1f0d694295c988491bf33586387fd59c3d807dcd71fd3821ed6a4c744610010a98053a914cfa2a27fb7d6144000e2dc249556eec289c4a9d799cca46741f34bc3e050a6c9bcee65cdc386a62cef193fa8e1ce88b5dd144479f9114899aa54a40df061740d21203f8a985f656448159e02f60b63814e1c39d89aada78c42290f72a08cc7587d0fadcec62d993d6a3f5fb698393bd7d207b5276ada2bef680c3df2006be338eea4921c7ad3b8ba5f8345ea20c25ea25da97dfb48c2635532dd502e709287f1a0be0314ce39fec53eeccb5f22b3d705ffd26a91020f7fafa3597120509fce00480ae400649bc8d80818b066cc397af45377840591b6cbff9a195285a0fd6c38001691e8b7b8beb1b70661b9ab337fd067a6ed0074ad5f02008fbe0cc00958c406a1a0176a46a3880fa7e02294e32faef7ed3ff3cda60f46e00ede3010b9bfc20b78066b7b13dac642a3928ff7cdfbefc211be16503f14021c72815c50d9346e3c75131230bb95791809b7786ea86691aa988e454e845595207d90f64036eedb30b30a9e2e1ffc4b34f3e5c8c023395cae9cd876536326c0f465746ed0ce36189eb31a65dfc2cd37443cbac286fac019d56b588421b86f3719605f4451560d68b1b6894bf0c4c0e0bdbc3ce62a74ba93512e778cad286c86e908ce8278ee8c9a96dae82a62161dbcd9a6559d2b66d9648deaac79409c826b8497835bea2e3f13a09ed68e9c29cf39d096c2825869bf9e7332c3424739c6293a5f48c43145ce17692f00763dcf111ff6fe1c33eef1f1b9174dea7b52a94e04cfce8828e239d321bb7c1dc23e25d97bde9799df98c5812762b7ea05cea4f8983986a10ede3d178ee5cf537ab87dea0916a078f737a7d707588321e44680fb58f73896ee4680317f2ab6becc859b4c90a3deb5f921ea01c9a2b5354b418c9059856df23b90eec5859b05d45b2199b80e875073873659a1d9f85ee539f5edf9c5cb0ddb5f16a0d6e5f6aa1dd19ad6b2b1dfffdbf73ac0d242be68c16db992c8493969ab8aac727fbd1a45720443aad31e25d68ec63d831305681c38c64481c420f3c4bfa53b0ed3f230d00ff6308996419063c2d1d77eda0f87793d634a92581b650faac14c065fbcd00b5ae38acfd55807f40e181d99ff45c3a8ab75a04dba8bd60c739ca100bc5c74392de47d7beda4d9acfd29eaa7bbd4d1a2e735715549f7e3ccc550e1b3925d78105908d61b63b45fd9f36587c2c462f54d4c5291a0775454d94a7b6d386af4ef6c986ea3fdb9610954d48c6da970c797d93cfe9198eed598e27995f421dacc696a663d543e53d3ba3e1822b9ae9f2d38c3b00e73a7ea2c9b9faa586ed25ce07804520e12d63e49cdf5ffe9eb9d445195aa6e74d0562dafe5f0f2f947579a3a91448de9bb75484cca3f4dd437aa0800180252d7550332f7e94d9c6b04b7ded8aa754a400484ec4a38185fa2a92eb0c2fe8d38a74a754d3dfd51f246c3476a97f1dd805185c176f61028733929b5197b959acfb1197d3ea024cf6d3d9df5acf9490afccefb397b2b24d55347adb3f97ed5f0a3f411a4d57ecaf1a7000e48a04bd40314d84e0f7f86a9d9eda2a3f5c21a84432bcb441274dbaa9630e2a544479be2a9a0aa8b26ec1a5258d4d7042c2c9196d4380d6878dc62f8714e4a93d4eeecd970b3ff39b351354b431a1aef5ee9ad685083c7b5c5a4e53722676228f5df06be6df850dbca958b4e4c3fe82c644364846d70e0cc6bd28ff12ee11294e4fb05afef41f80094fa3458773aaf3409db5ab4315f7f279a95a23d94e5da9a5e2556fc25c92b5f15f4abda4cb80a1937e3fb954c53e527e24bf480079e84333f7b23fd0f7f70c911c2b97bebdb596c1fcd33af9155c282fcbbe0ec971733f3549a2fe9dcf8b3e0feab2f3dc57dfa9413ffede85bac8076875d0461e8c4dfac107b9aa696426863d7b3bba80fd6ed7e349175c506587a773c3a4937e8b395975eb95175351ebce82184c8ffbe8f08435b86d72b2cb11c851ad508712f09c2da6796018195a45186004e274dc023b2aeb2c0672b873176005fa72bc948b5de2fbd31954089a919e5b2925d632ae7d54ac4466f8f50d66ead8a98b9761a0531d6e79edb6cb37c9a3eda44a4dcc9ed89dbfe3f82ea184c1e1594c98b18eedc996f5c33fa72619f782f39803210f0510db63251a7163d4a0b60059a95704aa5e2c8a2e26e89ab4a07ec65cd5aa840a0c8439c94b1e649c7436f84765402ff3b8f162c541beb9d821414595a40c9a9badbd3cb4f244db8d69f0bf8d544ab3ca46e5a225110f3ed57ec3518339f8d36bd4cbdd9a2b28b4a0a36f9c9f6ff1038d3eeafd323705d5558179a35db9c99d99ceca47a266cbb0b6563a8b85b17b2a274201953317b9ac2bbe1e50c403adebf3abea6958f153743ec3ee353955ebf89469b2fc2bc2464068cc3943bdefd23224b0fabfbad9c681dc921f38c2d75ec22f0c02c4e44622c39a43a05d46031242f5141315843f5f8e67539ef04a92168ad6ea5cb1921dd07382e9446304748e2b443c90d139352a725866f1a7033c566a86e4c1d15d02066473abf49919bf3ff17aa58eb456a5ab68f46c46032cdc428e5a2189507b054d0d1a4b633668b5250568f6c6f6fe6c23a80317b032ba09166a7ad025dd6571e2cf04ddbc5f9fd27129715ed4fce30f7878721dd5f3b519c957de9dc14996658d83c0929f5f402562c84875e8e4b43f91320b7607835bc76df4a7c2b51047a36073e1cf735e0f973704bdc7ba7934430716dc0ef255a5ee64e4dde7cef7f2496270a6404966f91ca535ad8a6d2e2f97aab4d8370d648734ba2e4924795e63b24a9c38c9e8ce41ed08e52146f8604b3d03fa96ee3e0b1841ca0bc80bb6d1cbb4bc522daafc54ad5dfbfd4b4981fa227ce80df1ecc30bbd623e907177d3125b4ff2641191de37f8620facbd03d3d13c3be7b48b32162992c90b552c3af21272cd8275e32184fe41eac9a5f96ecdf89b30aa2b6bd85b251c63e1664990ff336a848612e97188c4d28e92ee44a0f450bf04cf3c5f520f47fba5cd5d4087f43978a41bd9b928f769c2fe65ccd0f2db99e039ae83fcfccc585ebbbe82b2c5a48bb36331108b12c53fd17ac0083dd14d9f2723af95ff4298e83b7b832c8c7f50c4be73b5f7a90e7b3b97619c037add74a808fa4f29f0057d9fd279bf6125505ff0f39e7e6873823d256906abe8f6f691aac9a3b61a6e8510a7ee51b3001538f41c1426501f3600a8613e60bf8d6b07f8bbb3d54b04a9c6f9c00a073b19e4b7a07e07661875927781d48c01ba73351934e07683f732989db667f717180a114618dd249a5bc6d8b89876d4fa9cdeb7d8d8b2ee21874d0e39461a81e6ad556ba17e4db7d72c14b7dc31223778cefff9fcc6725ef0bce9e9a330b35e7f2821b1b144eeb94a3d191f3d60d6ec2623b495abbb519bf3244a4eea138dd2670500dde9c1a017ef97db10f2f4f127a764f4332ce5691f85c6209eb85f845a3100d84318fc0b0e6003977f07887f8585b8240d842bdf056a26ce4a4707e73fa42d1adf18170256a4886222d7b4e1ebb3b4f4df24cefac4645038cc3d92e4ad773ad647bab005aed06d75e3e7dd2012886151e38d818d1056d8aaa14cfcd72810882ff7e8fc088de4fe84d9dd0d77317984fcdf191d93a5066f93179768d2b12e3ab690525c0a73d01270d90bee6f6f4f7a9bbc53a6aa165dfb77171e7fefb3a3b2081d5d0d01f04e0f26b784961c92e83493a5332ec26ae72d2ab8ca284a12967c13358f440cf6b0acde4d5db567a70f9233396bd448366a61a00211c344d91e70b87eb8da06cb37dae17329252ce4a070eaa002ef35df8a51fc735c59fae774351db839ff0d46bb3139c24f4c4029890ce35c58f7de84983bbb371750aa5e6abf3ce7ca28098ca8230372a1509f4e1978d42b27f7f53ae40498f8720195b45f183a00d4f40c029c96b1c979ec0ff0fe63b07bfcff4ce283ca07fb70075ab9b52db2aaeb79065f697f82aa3c484594ff8270c621084946dccff9b60de482767aa2a88d026b0212d0d00fcdeff9972ead613e958a701e407f589e8e088af12c6550ddcdabb200f61255ded6a6b1ca38d5617e6c905668e32b6338daf41020a3493d9ec1b5db0a7da20a380112671d3d751e433e49bcf6b81508434e556633242a907a02d1490b1a4c794d65f109b0c32aea5f313411b7bc5564a3e5d1c794bb7546662211740d70b9f5c4095391cb934f165a702e82fd58c68ccdd6725988d4df281f6ab34f0b15e2794312c3853c5342aceaac0dc83ca83c1134cc1ea524d5520b670d554700988bf01ce91d4a648bd8e49b3d36f4940d27b549cfce79f186abeda0bbfffc0d6dc166a803f2880f03e27f4b0b0c49ca415a04f48f18c1c6aaf18914a391ff08591d8db7621038174ee2edfe9eda59c1b51677c17ceab23a714c40cb521d1f0a01d1cc524ad350b16ecf4b3e99ceb3dc1c78a82c002772e3f463f7a8bc3672049f0d448deb14847b89f62d647d8efcf30f183aa737fdf852b74936d987dbd604dff05e351422d1062eb7cb89ef0783c87d61c328d1c165bb4bd920be1149b3097958c68bdce0b0cc2ce8a66cc114ec76a79647cd1a37891c66060fbc1c2e5c06fa9294fe698ad2b7a922656b15371bd8c25830772a498ed382c5f36c96f59a07ec38911ccafa43c1c15054f7d49d8831d8593f1258b6e490e1cbd6617e3fb605de6d25e17af040f4439d51aa22c45fe624c49b0d56ee5e1577f3fa6920754d07d21c919a216a1b0af774e4ed1f469696c20171ed652df83ad4572c830042f708179836e48aebf19114e9509b9ef801ec73efa5e21278e57f74c92b8069450c06fe6137fd9d33391682a1837b55a536d128b93d46a8fc137f4b760435a5ea000bec515ff86c776724e9d03f67ddbd0d6756c267dadee045516fe787dc42ca8a055fe0908647c41eaf9e3d99f39dc61440eaebf12639e534e2b8cd2f0c0ecb02051a582b40b1ed4fcad467aad4c7260572c42f9d4a002c6a5313de5e46c5362702cf9306c862d4880eeabd74dfd516fc307d78a81c0a7309a5086260b47790e10892c5bd471270a6232e8826dd73c0fa269670e5eabcd0b21177c77887083b75025ee2c0af1d3e234a657ae58bd508ab41b2deffe6ddfc345bc707b8b7eb842202bdaeb5ab2323d3a9f150477e684570b3c9b648c9d86e8af65346177cb8ed1b042f37f43f2707f5ffbf90d8b6c975305d94fedc7f2fd58fcdb668a14f232b9f0eeeac098fb6b0e323da03d95c88d7cb180a40f320decbbb3f7371e60971b4c808df2a89a7a3f0cdf3c134ea1ac6a7da978c967aebf194e0340e59bf3588af930c717495f9787326385182e27f6445ebb966de97a3b28f2ecc89a941ab8272000865b47ecaed9192a6b3ffdddefbd5370325966a64d2b83b0c1c6750ee7501d005223fb398b082ba6a36629d02dacd473e682623b94a0574ae66761c74737ffe0c72f66a9f23f7297ce7a37a3db893bd57242e2524652450646d61d06e629b1a0fbe71d721b18a643f3236e8fb13d1e017c4e88d3913cb0537c9efddde48b1af030451f07cef3ff65b6b59bae6f60c03a6cba17dc802e6a074421d30531339e50a6a7e7b33b154bf8157e6831afe50e36738a1077a3290890e8d16f8703953980cab87093bdb9e91220db0f1c4347ec557d46fdb0578165604931bb804bf7efd0fffb444d3ca9ff102e226cec2192cf7d90400321ed51ba66143a769002960b90d893f472d8827ebe4534011e87918eba2a7cb19b76e74b19c26cbb5feea73f30eb48389ed6aecd32b963532bcd80ab154ec6d4f96072ed4866a12f5743bae240990b6f75347502bd26befe323725fbe5ef739311f793569770dc18f71c0a3aa0f1517ce82956ca83537c3a2f5c596ffc7fb0bba55195c2c21bdd22d4c83ffe90d7dbc99a92b124572a58c9e4a7d0171caff06c11d54977265e2ec98e03a8d0709ceca0b9a9e5ed48557d11290279b5de62c2d42fa5edb9448899eb20042abcc0d57584cf791a07f30790fbef1acc15f1a2d010f4a9e69590b8bfd5f6da126a80cfde8153e7d45d68193483842896964c953a489b758df5a971a37687ccd9989059cbe19454514572a3a9afaebe6a70cc46aa574ec9c055f50e623886691ec5a00c48a0ed80702f09220cc65ba8ba0eadd55a18bfb644d3a9f0cf1534b7e8b5003651cd05a5dbc68dc97917e7318bde04523004b55c84909eb218bb35ddf899f00109e0eeaa0ea160e523a32bc3875a6d0b3faeab9da80f3cdfa289693d3190a04142911169bfd7eca5c300d0e5a69ae612256e410e555a0ad0045ad406dc04808dedcd2b7288368eddb92834049d3c44b8c32b642ff64bcc9e0b5f4b4d1188a0aa81b3c55f3b6ea6c0bc975298c99a443b8acffc9418afd3a1298f1ec0feee90b6481a44cd4977ae5581b9ec4f4a84984f5a54b67d1a41883b3cf30727365d60a943b81637974b4505a8ce3594e43b389340cf9a814d03b47faaf9d674ad18107bb063d1038b488b2a0a906d9194495c9c1be5e8a1feba17e8fe704414b58c70498412044e664695a47b4f5ac8996d50bdc3e86d3b73026b39d665cf4daa0860fd68a6ffa67159bf147cd4524740e9e267e4d4729a76fa4682b305d80979b1606b464e0e572c4f64ce4650331f5919dc5328cbddce65afd40b14f0cd57af3bb0867e756870841806cf90bb244ab6ce9cb5758dd1d89178ce5f7d3136b25745802aaa6a6578792ba1d08d756cdeaea021a6a45c1f1e1212a59ee4989eea80e72004b55e2ab120c3ff8458460d70475e633267d796c47170ef500ae46cc7b8d4702bfcb3a84e07b89672fcca35bcf4b77368bf0a67608b07606527d29a56c979d0797e66659cd569507aca4fd8aaf2ba8a96df24666c627c1f76d31cde794fd7b0cc8f9d016ba903e664ca20a63c51c9179968b01af073f85221f3d3a9b16eba30eaf7e6fb86cfe5396cf7f367477d14b15cbd586ff612af520e80e27fc5c182a09824811ca79a42e124063a5c28a918b6ab1ac228afee4cffefeb8deeb0aa6340a987b5fef5659156f24f18a5a6d5a167352c6ecb51b2f5dc1a8e69933e913f5087b8a2f861f8a9fec3d8abece0526b9c4ad0908182968bab6114b64c3559f2005c6305173e720bf9d4d7022de294387e77e5597e815e2dd99fde84ddfcdff7209f6d5115c2a0a0470975477749522f7df02e4e33dfe52522cc1d28159da46a30ced6cc8c78e840dce4d705bf56984d0a9892ae23d1b47d959b58b8e43d64ae10ca9a6a022ff2e020037dc46a290b480ebf0ab84ea5c35f6a484b4f001b542280585d1e12e78548ded37a4ce76653c48095b78dcf8e7d1e61271e7945cdc49dc0a165c8b172b43891b0dda51a31c359e94b72cccc17b4261efcde7dd1f100ffa0308f75d9a7f1bfdd78f82a8212c91df247c5483d83480625a0e7a190e4fe8cb0fe5d6c6038d7c4700ebffa02b50ec8be0acb36c3dbb0fb9ad0e4a2bb89be1ae009bdf06898b901a08b8ed0ec7d4cdd6b56b8a633b96cc3e72872ff11427007205bef412f6dc6e72e0ece54d254b796fd1d3841eca121342925fd878b55baca40214b512cf5e6e762730d3845b7d62c12809aa2c774dc11b22086540d9f89605064ab3d2dec1a48b1c66b594fde8fc3936ecdc60c819671ee035c4800da3400809703468dce83e440edcd117b9f171e9480f0fc3c5fb0558f8d03db403dba8e90ebfb469d0344efc90a7cae60b2f7bc973a4509c36b8c8b2605fa6495aea5c420d12c5da36e28e86a5b1e19cb8791b2e34143c48f9427a0f6889bf67535836c70282597aa5cf1a1c9830f9e8662237c94dc87a80ddd457025e7581dc4d7b2f500798a211bc1125fcd5568864f920733c46fc314d786743eacb1d8d6c3d3c75890ac10a3764a62c8355d06bfe42d8c2be524212ec2efa5eeae13bd7281ad6bb8a0f0750bfaaa0e6662a09ee58f2e1fe7ad7efe4a77856acec9e3bec5885ac84900b2f0b087838c0ad5dfbb789981f1847b3e101fb8b3010a8e05562cc73e619ba04ab72cf831da54fe7666f4e6e23b54b58390da61116c05174b5562cebc1e61801585519d90768fd63dfaafe821905c03886ac3c4ab8653265744d3fc995cf580dcb5d87fe7e176b33be82d0e9359453eda2d0a64fac6adb7e4c84caf6f5a236049dcc46b0ddc33504af75fedf553bf5626c5a3e182ecdca9d73121e370ed4080b5c873cc2a8ad0aff884c5209c8657d6599d87a291b60b4dff71565ca835bf4044876d04c11c21592c1b76d32ef93bea8d8fa960efc10da09202f9a31cba31c0414fdfe2a166b317e74c7ce66429ba3598d2a279e460d410a82a091b527371f0078cbcc48e33e3e737e4eec08e789b670ca8a301ee5451f62587a0b221632b00eda21598a9d231e3b9cdf8901095257f91ff193b0aba0e80b5ce6f01f6dd87f0d8ca74c2b836cdd39beb2b2e9c56a7ed34557ab0c0e242a7410dd2bbe201e4900095dc8cd1dc2e46b6ab4dd3f88be5a362edded24fa7dc84e6f22a0065ae1870e2db17f06cd53c29939b3fff04bbb062b21456ee10d3b4cc68502245f086f900b2a506030285f591130044f5cb8b4348cbfb13cd7d2c237664b0a9ceb042803041c85d43757375195d903ab89b46fc8837629b0d113c6e191972150e3cefccc022a274f67276a362ed8475165298210a60bcca8bfaeae64b23a2c314f9efcb60a78a115ef60a1c2e3879cdd3e20e0401a67ece917a438f3b64953046e5768b7086c58911b01ee8772c2b5082e78cfcbf32eef2066280c32b647c9c01d90ab520b4215a9edadc9761dc0bd7f89e848b85fb2c1e0ba890794985a4c6abcbabc0c0f0612d486e040f084c45bd52430c7f9619f0433caa6ffe673c92387b04f8b3409dc55c2367adfab904b7572f4c9a87d5bf8590fb06aecb6beb952e06c959d3202878b36745448bfb77b99e04d08091a3accfe5c5718d75d084d06fc542b871f0113a4078a649eaac15893eddbb6495d95659ffdc26e5d7f1f22acd574ec8ceb0882829ee7edba0c9fc661eb18391959ada211de34c2ef0809345d3ffb9ead7b0d4460d57b4dbdd6076a6751198995f45d4fd5f7b32440e3742a00b5e2ce849905df13f3d951b9ec11d20cb29ad26c0bc8b07b3c522f09d027e337d6439c8a3b0d865a04531228cac81b93b3f3b0795108010312d719d3313ec2b71b26419ec20c04a9ba6d993f356bffd93bfa26fcc52e5eadacd27af8e652560739976c5987082a37fda65e9e0ebd5a52a47b845a57d2e1b3e0523ba6b5f06a51e328c88dfd561c4b45c4c5e2887a7cc5a0b71591f549258c0b23351bdcf5036c0db867cc7eb4a268c9e08aab7700509cd5097d9ef25a1d6772cbb915f337d45ad64e84301cd13162c130504371e3bbe62e02194c2cadcabda444c42ca9a1fd95ba4d16eb6757b19072d92b3c2f2e8b2c5a195c5f95236bded0c7e0ba6ded8c4f50abeb10aaf162855386d41f43daf1377bd478bf04c6e89670335d9abb4b67b1a402921ce434eafe3ced979b46705fec26fd073909f4a90115ffbee2e3e645f3653ef54a6119ebb31c96e47f26bee912ae84322e85eeaa54a4feb1d3a804f2e637e982b7f0367754d27423905e91ee3151c1284b0ee2c7a6bbbbf9898bc24da61a8ac8673855709f0fea1cd32bceb681ed41995b6accdc39669771c86d2890fd936805eca6ff1438a04ad5220dcfbdc99260eb9c3717f641175f8b5d38ea68cebeef36691b487277495cf1ff2643b173d8fab6234b26a54284a907f0634ee1d26cea69a6edeacef99404607b2d52500c43120786e74884cbe2ac4908e0937ec45c6e3066a4a03dc02035e1bd3e689200a54f6e37e48cf0c929c178da8acd6da2722bcdbd4133a032c30b33cd07d08a5772142d137e524d7600ea7db2ad71327fe8b04aa57c2b64f1e09279c373e354eb825163073c8bc8ba39206ea251be37c2e846520c62ffd24990675f9bca10f78740d69127b6af53b6744b115bb3e6866774a43d2b7b16962fbfd6df9be1ea25448f8005e53f6cf70429982ee7b992f1280664ad8665792c51aec555f5d3f3c61b5df4c37cf0f470498b072bc7246b1e4571ce80999a7a6c96ab1bd96ede46f84ac3ca4f4afdadd578fe642fa11378ef346aa21d30a7ea525e5b78e87a6dbc8fc67ee2153423747403fbf57c5228aafba48bc82acb6c81988f9c3e2c9049a692b1e029179f725f0005bb2df2d120a34c1ed007668a5ba635bb0c4220449d2fd40ebca28677963b668f35d0ed0035b242f206cf9079ab3bc41a93eb46bf567c82ceac29959f15f6b004a518acc3d8a414875ee5ee8266602b92cbe9e0d2d17fa1a190669d3e26a194f359db86ab469da95978318aea5432b0d68f2c1489f178453b2f42a64fdaaf123e3960b3b0911a4f70e62e88188f5dd1f873c99720271340432bc478f72567d8508fb53309dcd2641f010d3ac1c42016fd43d29b5c4d67b51610605ce99a4a9043b71d13968218f06db044f7248541735c09db726df59945fa57ea349b711577456d51581850c035b8e48f6788423834a979da19ce68a3450332d2e9252f6aefa00f99820ca56fd319b47f1113461658f4b0a31194f38c04fc20d5f9c217a40d1eaf539617e4a087476aa82607b44f5c7208cbe1c2ed9d6656c0e8d7f7b43d81c4e83278e322f4905f7d4d44367faaef40103e07bdb897514d9214df89dedace258763df7194b99d12f9e67cb16e594c5e96742dbbcd50f56fcbd560e7fa4c2b3d513b31244686f987db87dc713d7fb13b8cac30c6fc8e0f190b9a3c150a56c0fde7c674b8d020dde2b47ba799076bf1cc8bb756e7e8c2edc691dd4cb5bcdcd5e6cda7b144bbcabdd0a5456bdfd6be648c7165872c2a8ed08f7b399b6d78d7f5e6bba9ed6eed7d3ffe9f8f98e31b70a010ac56aa1523f61382f5e9549067f4b8a11e3c9f3245046b1cd491e54a698ec1a3f9ff419b19b70edcd3657fd22e63f4778c5028c92458b336f586c63c0b60dfb3425526ae340fef4485b0ffcc8f7192e1578d48b831585b77738f276fc165d2b1b0bd101a3a7463533c3b84621a3d67c5a20449912bb3cdd413d47bc66becdd9463a4c11740578563d96c8e119ced706a6b9114d328d13b71f6e65a74b517f5f5f7f977165b082ac6bc98f940dac825c57d4323d9606c2aa10af8639b85a7df6f81d921df22bdfc717006299f5d384d17ff50bb0c7d7e476c821b963f34a6276c8dc24a8abeaafd903bb51df352880d2b11b7878ad8cac9f8c3adbbeb41e53c72f3fbc5238b29489617f46b7af4b00b6fa9a975331fd715ef252bb9c9587584003d722d7b67a7323d1ee74272d2f74982477ba09715e77f3beb7b6d156cee2dbd6077567710b1bccbe2eb71e7deea3695a520575df28f3beddced7de1b8cab08b771531229ff654cc18da04ea3d6679fb4a36227a34709993a533717b10db28517cb8d20ccc715a3b5e8985e49512311ef7b32ad2ce9eb9b2970adb6015a058b947bc042e2f92e61ae31e31ea2e805c33c63bdb181b88e2538eb7fcc6d31943c28f532d954fa66d002982e15d1b1cbbcbfd75093f1c011fa7df85b5fb516e2ca102f6dd61813c8ec144a639a3b13c4bdc11454dfbf7c86c1ece0c807888c2043bbf01abdef95275209c387842ce615a3d95fd6fca7fe501f5ff792d1169aef4ded2fa7a7edbbd5b42f9ef2b97c3faf005324204e8c68a25a9bd315b1be7c1962313863377b67387a817c6b43d253476d345f87b530be4b1672ecf7762cfcfe56b65569c5ec5c217c4b9083900b53bb6798df4e7c720bca0f7632f5b3ca1e3aa16db5101c991fc320c71ce43da97f112c8fb89337d9409c5fe2da943b600bc05fbaef5a0596ad18e78097f58880d32dd0cb96fadb707398e3a655994c346f5a1908d42c95eec8cc5ecf5603ef72ab836a4245b108f9d0fdaf663a8598d89ada8a5dfc9223c906daceae073ecfe4d4635a4ff35c582f384f4d8e761a3a2d0ca6ee94e8b333326795b811df8425894b0d1cf0d24347d20be3bad080aa2914a0aa3d0f07631a072a65cee5b16f00a07ec71b64a8b9927c2c004b2e2063a3a1003c8a27a9bbd9b0ad8d473e98740e9f6b1713b08435dbaa905773841af86ab772426720308f4696e6435976cdbd83782f15f9d38100bc09f99c7c29d282836fa01da56768831bd61a9d3db398aca28667c6412906fc5e8ad49ae3860f8e51cf707785e1d3e08ca80bfa295cb42d0c2d89acc9b58fea37d0741888e393cac23840899611ca51052a40599245086c9a6b874fc3ce279fbd14f79356a25971d89230925de9414662a8a3e614e8c90922d8bf1761774ef3e5ed076b684326154ea080cd5cda28aa9e46e964130a65559c2a3ca586c03670a56a499882c2d215477ce0307bb44029c04ba1eda35625b7f68e06731e62c3ecd2a3eff3e4b2bf64b47160f6807473ab78a54d483bc758528b28e452ff0b8d373e14e0798f95ee6912f6d0f3e8c4b7ca99b784558622cf78a17415a129b4cff5cd8cd881c2c96c557a8450261be9a4f3d20d325afc6a333b96b005e6ca3c338a426aafe2d3b73c0841628084a0438e8142c0a86ca888691ccbee56fe3a20932d59065a5083b62d3a30aa30c5ac7c301ec2d5fee7b07c9a12fd12da63d7d8610befc202f2b7ddf155672ce008c3adaaf83757b472ce332c7df2e0191ec12094b17f09c7b006edbda7355fe022924222caab36eb54e55516ba65a94d7191c0508513b2365e452305d1c21a209576f2fb7b28baadfad058d311f69a7c10e40045650aa79632b4da9b8cad33c093f95bf670d06eaa139b335a613286e95c856e1474c1f3252701de49adc0e0500bf2ab2538a77971d9c7653c12b89053b2c62bfa29ce67ac894ec5ab27a72fc0c9cdc4502944760e8e74d1d391fc6ea1593f976307d49c183cffaa96f71267d0b769418c84f6af0165aa438425ec961cfc1c2038aa96e8b2c361676538954e001fad157057946511f13a7d45df1bd2c9175672d2184eadefa331c8445c75b9209134030436b2034f465831102a94681eb7ac8ba4c208c3c0404abf59fa4cad20660871821a06fd6bfc3137722e07e8abc302804d615d85e0fdd2330613bb2f302d89a9b9dc058d3ad863ffa677d6288fb2caaa5d0122d7ad66250b9973cd2db0f2ebbdea831ff11c5c3214c62f0a7dcace8f64961a0a291beef808607c20b5c06ef2f133604c8bdd2c2966e1ab2da2741e9d78e193e8d91aa97d255160531dc008c2ddc28c2103467804b7ce79aaf58b2ca5a3bb3b346a0a83ec5801615d79f0e9118c1170b0cdc7224c5fd8c85c9648f06efd23f40bbc9b8018c2a2f78a3710f1d479827149b9ef50c6547a439224e18101eac2b0c61a9234eeec7f52dbd990d2e6afc0ed06cd10e733a67140ff56cba4c7b6ba6796a1753f351d832f052fd0127e3ff48f1a526b93a62efe5a7d5d4c6080174a4d1c96f95452a3ba19de1140a"}; +// tx hash 1640236fe817f83b0bd2082c655d152be390e4f78e41db5b935bb8a53249fe8c +string addr_57H_hex {"57Hx8QpLUSMjhgoCNkvJ2Ch91mVyxcffESCprnRPrtbphMCv8iGUEfCUJxrpUWUeWrS9vPWnFrnMmTwnFpSKJrSKNuaXc5q"}; + // viewkey: 9595c2445cdd4c88d78f0af41ebdf52f68ae2e3597b9e7b99bc3d62e300df806 + +TEST_F(MYSQL_TEST, DeleteExistingTxAndAssociatedOutputsAndInputs) +{ + // removing a tx should automatically remove its outputs and inputs + // from mysql. we have constrans doing this, so we check here if + // they work as we think they do + + TX_AND_ACC_FROM_HEX(tx_1640_hex, addr_57H_hex) + + xmreg::XmrTransaction tx_data; + + ASSERT_TRUE(xmr_accounts->tx_exists(acc.id.data, tx_hash_str, tx_data)); + + uint64_t no_of_deleted_rows = xmr_accounts->delete_tx(tx_data.id.data); + + ASSERT_EQ(no_of_deleted_rows, 1); + + // this tx has 1 output and two key images. + // + // output: a9d876b01eb972db944b78899b4c90c2b66a3c81fe04bf54ff61565f3db53419 + // key1: 45d3cf7b4f5db9d614602e9e956c63c35cf3da6f7b93740c514e06c898fb0da2 + // key2: 3ef54482411c54a280081a87fd35e542b3b8906b702123c55468e71dd620d3a4 + + // so we expect those to be also deleted after tx has been deleted + + + vector outputs; + + bool is_success = xmr_accounts->select_for_tx(tx_data.id.data, outputs); + + // if no outputs found, we return false + EXPECT_FALSE(is_success); + EXPECT_EQ(outputs.size(), 0); + + vector inputs; + + is_success = xmr_accounts->select_for_tx(tx_data.id.data, inputs); + + // if no inputs found, we return false + EXPECT_FALSE(is_success); + EXPECT_EQ(inputs.size(), 0); +} + TEST_F(MYSQL_TEST, DeleteNoNExistingTx) { uint64_t some_non_existing_tx_id = 7774748483; @@ -453,6 +501,39 @@ make_mock_output_data(string last_char_pub_key = "4") return mock_output_data; } +TEST_F(MYSQL_TEST, SelectOutputsForAccount) +{ + // select all outputs associated with the given account + + ACC_FROM_HEX(owner_addr_5Ajfk); + + vector outputs; + + ASSERT_TRUE(xmr_accounts->select(acc.id.data, outputs)); + + EXPECT_EQ(outputs.size(), 9); +} + +TEST_F(MYSQL_TEST, SelectOutputsForTransaction) +{ + // select all outputs associated with given transaction + + // tx hash 1640236fe817f83b0bd2082c655d152be390e4f78e41db5b935bb8a53249fe8c + TX_AND_ACC_FROM_HEX(tx_1640_hex, addr_57H_hex) + + xmreg::XmrTransaction tx_data; + + ASSERT_TRUE(xmr_accounts->tx_exists(acc.id.data, tx_hash_str, tx_data)); + + vector outputs; + + bool is_success = xmr_accounts->select_for_tx(tx_data.id.data, outputs); + + ASSERT_TRUE(is_success); + + EXPECT_EQ(outputs.size(), 1); + EXPECT_EQ(outputs[0].out_pub_key, "a9d876b01eb972db944b78899b4c90c2b66a3c81fe04bf54ff61565f3db53419"); +} TEST_F(MYSQL_TEST, InsertOneOutput) { @@ -567,7 +648,40 @@ TEST_F(MYSQL_TEST, InsertSeverlOutputsAtOnce) } +TEST_F(MYSQL_TEST, SelectInputsForAccount) +{ + // select all inputs associated with the given account + + ACC_FROM_HEX(owner_addr_5Ajfk); + + vector inputs; + ASSERT_TRUE(xmr_accounts->select(acc.id.data, inputs)); + + EXPECT_EQ(inputs.size(), 12); +} + +TEST_F(MYSQL_TEST, SelectInputsForTransaction) +{ + // select all outputs associated with given transaction + + // tx hash 1640236fe817f83b0bd2082c655d152be390e4f78e41db5b935bb8a53249fe8c + TX_AND_ACC_FROM_HEX(tx_1640_hex, addr_57H_hex) + + xmreg::XmrTransaction tx_data; + + ASSERT_TRUE(xmr_accounts->tx_exists(acc.id.data, tx_hash_str, tx_data)); + + vector inputs; + + bool is_success = xmr_accounts->select_for_tx(tx_data.id.data, inputs); + + ASSERT_TRUE(is_success); + + EXPECT_EQ(inputs.size(), 2); + EXPECT_EQ(inputs[0].key_image, "45d3cf7b4f5db9d614602e9e956c63c35cf3da6f7b93740c514e06c898fb0da2"); + EXPECT_EQ(inputs[1].key_image, "3ef54482411c54a280081a87fd35e542b3b8906b702123c55468e71dd620d3a4"); +}