From f390a0e2dcc6b2a67b3161d167da4378e898e177 Mon Sep 17 00:00:00 2001 From: kenshi84 Date: Fri, 30 Dec 2016 22:51:43 +0900 Subject: [PATCH 1/2] portable serializer: make signerd/unsigned tx portable, ignore archive version checking --- .../archive/portable_binary_iarchive.hpp | 3 + .../archive/portable_binary_oarchive.hpp | 4 + src/cryptonote_core/cryptonote_format_utils.h | 33 +++++--- src/wallet/wallet2.cpp | 60 +++++++++----- src/wallet/wallet2.h | 78 +++++++++++-------- 5 files changed, 117 insertions(+), 61 deletions(-) diff --git a/external/boost/archive/portable_binary_iarchive.hpp b/external/boost/archive/portable_binary_iarchive.hpp index 7149cca0..78d615f2 100644 --- a/external/boost/archive/portable_binary_iarchive.hpp +++ b/external/boost/archive/portable_binary_iarchive.hpp @@ -321,6 +321,8 @@ portable_binary_iarchive::init(unsigned int flags){ boost::archive::library_version_type input_library_version; * this >> input_library_version; + // ignore archive version checking + /* // extra little .t is to get around borland quirk if(boost::archive::BOOST_ARCHIVE_VERSION() < input_library_version) boost::serialization::throw_exception( @@ -328,6 +330,7 @@ portable_binary_iarchive::init(unsigned int flags){ boost::archive::archive_exception::unsupported_version ) ); + */ #if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3205)) this->set_library_version(input_library_version); diff --git a/external/boost/archive/portable_binary_oarchive.hpp b/external/boost/archive/portable_binary_oarchive.hpp index 8fd7090a..cdb4caf0 100644 --- a/external/boost/archive/portable_binary_oarchive.hpp +++ b/external/boost/archive/portable_binary_oarchive.hpp @@ -277,10 +277,14 @@ portable_binary_oarchive::init(unsigned int flags) { boost::archive::BOOST_ARCHIVE_SIGNATURE() ); * this << file_signature; + // ignore archive version checking + const boost::archive::library_version_type v{}; + /* // write library version const boost::archive::library_version_type v( boost::archive::BOOST_ARCHIVE_VERSION() ); + */ * this << v; } save(static_cast(m_flags >> CHAR_BIT)); diff --git a/src/cryptonote_core/cryptonote_format_utils.h b/src/cryptonote_core/cryptonote_format_utils.h index 704b8467..a6610e60 100644 --- a/src/cryptonote_core/cryptonote_format_utils.h +++ b/src/cryptonote_core/cryptonote_format_utils.h @@ -36,7 +36,8 @@ #include "crypto/crypto.h" #include "crypto/hash.h" #include "ringct/rctOps.h" - +#include +#include namespace cryptonote { @@ -62,16 +63,6 @@ namespace cryptonote rct::key mask; //ringct amount mask void push_output(uint64_t idx, const crypto::public_key &k, uint64_t amount) { outputs.push_back(std::make_pair(idx, rct::ctkey({rct::pk2rct(k), rct::zeroCommit(amount)}))); } - - BEGIN_SERIALIZE_OBJECT() - FIELD(outputs) - VARINT_FIELD(real_output) - FIELD(real_out_tx_key) - VARINT_FIELD(real_output_in_tx_index) - VARINT_FIELD(amount) - FIELD(rct) - FIELD(mask) - END_SERIALIZE() }; struct tx_destination_entry @@ -261,3 +252,23 @@ namespace cryptonote specific_type& variable_name = boost::get(variant_var); } + +BOOST_CLASS_VERSION(cryptonote::tx_source_entry, 0) + +namespace boost +{ + namespace serialization + { + template + inline void serialize(Archive &a, cryptonote::tx_source_entry &x, const boost::serialization::version_type ver) + { + a & x.outputs; + a & x.real_output; + a & x.real_out_tx_key; + a & x.real_output_in_tx_index; + a & x.amount; + a & x.rct; + a & x.mask; + } + } +} diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 221dd8e0..52d9e594 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -77,8 +77,8 @@ using namespace cryptonote; // arbitrary, used to generate different hashes from the same input #define CHACHA8_KEY_TAIL 0x8c -#define UNSIGNED_TX_PREFIX "Monero unsigned tx set\002" -#define SIGNED_TX_PREFIX "Monero signed tx set\002" +#define UNSIGNED_TX_PREFIX "Monero unsigned tx set\003" +#define SIGNED_TX_PREFIX "Monero signed tx set\003" #define RECENT_OUTPUT_RATIO (0.25) // 25% of outputs are from the recent zone #define RECENT_OUTPUT_ZONE (5 * 86400) // last 5 days are the recent zone @@ -3018,14 +3018,19 @@ bool wallet2::save_tx(const std::vector& ptx_vector, const std::stri for (auto &tx: ptx_vector) txs.txes.push_back(tx.construction_data); txs.transfers = m_transfers; - std::string s = obj_to_json_str(txs); - if (s.empty()) + // save as binary + std::ostringstream oss; + boost::archive::portable_binary_oarchive ar(oss); + try + { + ar << txs; + } + catch (...) + { return false; - LOG_PRINT_L2("Saving unsigned tx data: " << s); - // save as binary as there's no implementation of loading a json_archive - if (!::serialization::dump_binary(txs, s)) - return false; - return epee::file_io_utils::save_string_to_file(filename, std::string(UNSIGNED_TX_PREFIX) + s); + } + LOG_PRINT_L2("Saving unsigned tx data: " << oss.str()); + return epee::file_io_utils::save_string_to_file(filename, std::string(UNSIGNED_TX_PREFIX) + oss.str()); } //---------------------------------------------------------------------------------------------------- bool wallet2::sign_tx(const std::string &unsigned_filename, const std::string &signed_filename, std::vector &txs, std::function accept_func) @@ -3050,7 +3055,14 @@ bool wallet2::sign_tx(const std::string &unsigned_filename, const std::string &s return false; } unsigned_tx_set exported_txs; - if (!::serialization::parse_binary(std::string(s.c_str() + magiclen, s.size() - magiclen), exported_txs)) + s = s.substr(magiclen); + try + { + std::istringstream iss(s); + boost::archive::portable_binary_iarchive ar(iss); + ar >> exported_txs; + } + catch (...) { LOG_PRINT_L0("Failed to parse data from " << unsigned_filename); return false; @@ -3123,14 +3135,19 @@ bool wallet2::sign_tx(const std::string &unsigned_filename, const std::string &s signed_txes.key_images[i] = m_transfers[i].m_key_image; } - s = obj_to_json_str(signed_txes); - if (s.empty()) + // save as binary + std::ostringstream oss; + boost::archive::portable_binary_oarchive ar(oss); + try + { + ar << signed_txes; + } + catch(...) + { return false; - LOG_PRINT_L2("Saving signed tx data: " << s); - // save as binary as there's no implementation of loading a json_archive - if (!::serialization::dump_binary(signed_txes, s)) - return false; - return epee::file_io_utils::save_string_to_file(signed_filename, std::string(SIGNED_TX_PREFIX) + s); + } + LOG_PRINT_L2("Saving signed tx data: " << oss.str()); + return epee::file_io_utils::save_string_to_file(signed_filename, std::string(SIGNED_TX_PREFIX) + oss.str()); } //---------------------------------------------------------------------------------------------------- bool wallet2::load_tx(const std::string &signed_filename, std::vector &ptx, std::function accept_func) @@ -3156,7 +3173,14 @@ bool wallet2::load_tx(const std::string &signed_filename, std::vector> signed_txs; + } + catch (...) { LOG_PRINT_L0("Failed to parse data from " << signed_filename); return false; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 54e26008..e7a6dfad 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -201,17 +201,6 @@ namespace tools uint64_t unlock_time; bool use_rct; std::vector dests; // original setup, does not include change - - BEGIN_SERIALIZE_OBJECT() - FIELD(sources) - FIELD(change_dts) - FIELD(splitted_dsts) - FIELD(selected_transfers) - FIELD(extra) - VARINT_FIELD(unlock_time) - FIELD(use_rct) - FIELD(dests) - END_SERIALIZE() }; typedef std::vector transfer_container; @@ -232,39 +221,18 @@ namespace tools std::vector dests; tx_construction_data construction_data; - - BEGIN_SERIALIZE_OBJECT() - FIELD(tx) - VARINT_FIELD(dust) - VARINT_FIELD(fee) - FIELD(dust_added_to_fee) - FIELD(change_dts) - FIELD(selected_transfers) - FIELD(key_images) - FIELD(tx_key) - FIELD(dests) - FIELD(construction_data) - END_SERIALIZE() }; struct unsigned_tx_set { std::vector txes; wallet2::transfer_container transfers; - BEGIN_SERIALIZE_OBJECT() - FIELD(txes) - FIELD(transfers) - END_SERIALIZE() }; struct signed_tx_set { std::vector ptx; std::vector key_images; - BEGIN_SERIALIZE_OBJECT() - FIELD(ptx) - FIELD(key_images) - END_SERIALIZE() }; struct keys_file_data @@ -672,6 +640,10 @@ BOOST_CLASS_VERSION(tools::wallet2::payment_details, 1) BOOST_CLASS_VERSION(tools::wallet2::unconfirmed_transfer_details, 6) BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 3) BOOST_CLASS_VERSION(tools::wallet2::address_book_row, 16) +BOOST_CLASS_VERSION(tools::wallet2::unsigned_tx_set, 0) +BOOST_CLASS_VERSION(tools::wallet2::signed_tx_set, 0) +BOOST_CLASS_VERSION(tools::wallet2::tx_construction_data, 0) +BOOST_CLASS_VERSION(tools::wallet2::pending_tx, 0) namespace boost { @@ -869,6 +841,48 @@ namespace boost a & x.m_payment_id; a & x.m_description; } + + template + inline void serialize(Archive &a, tools::wallet2::unsigned_tx_set &x, const boost::serialization::version_type ver) + { + a & x.txes; + a & x.transfers; + } + + template + inline void serialize(Archive &a, tools::wallet2::signed_tx_set &x, const boost::serialization::version_type ver) + { + a & x.ptx; + a & x.key_images; + } + + template + inline void serialize(Archive &a, tools::wallet2::tx_construction_data &x, const boost::serialization::version_type ver) + { + a & x.sources; + a & x.change_dts; + a & x.splitted_dsts; + a & x.selected_transfers; + a & x.extra; + a & x.unlock_time; + a & x.use_rct; + a & x.dests; + } + + template + inline void serialize(Archive &a, tools::wallet2::pending_tx &x, const boost::serialization::version_type ver) + { + a & x.tx; + a & x.dust; + a & x.fee; + a & x.dust_added_to_fee; + a & x.change_dts; + a & x.selected_transfers; + a & x.key_images; + a & x.tx_key; + a & x.dests; + a & x.construction_data; + } } } From ada7c7da8f2135b3792b0b56666bdd4b88400f7e Mon Sep 17 00:00:00 2001 From: kenshi84 Date: Mon, 2 Jan 2017 10:43:20 +0900 Subject: [PATCH 2/2] portable serializer: tests added --- src/wallet/wallet2.h | 3 + tests/CMakeLists.txt | 8 + tests/data/outputs | Bin 0 -> 1035 bytes tests/data/signed_monero_tx | Bin 0 -> 15284 bytes tests/data/unsigned_monero_tx | Bin 0 -> 1753 bytes tests/data/wallet_9svHk1 | Bin 0 -> 1971 bytes tests/data/wallet_9svHk1.keys | Bin 0 -> 759 bytes tests/unit_tests/serialization.cpp | 513 +++++++++++++++++++++++++++++ 8 files changed, 524 insertions(+) create mode 100644 tests/data/outputs create mode 100644 tests/data/signed_monero_tx create mode 100644 tests/data/unsigned_monero_tx create mode 100644 tests/data/wallet_9svHk1 create mode 100644 tests/data/wallet_9svHk1.keys diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index e7a6dfad..19c6c3f5 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -58,6 +58,8 @@ #include #define WALLET_RCP_CONNECTION_TIMEOUT 200000 +class Serialization_portability_wallet_Test; + namespace tools { class i_wallet2_callback @@ -86,6 +88,7 @@ namespace tools class wallet2 { + friend class ::Serialization_portability_wallet_Test; public: enum RefreshType { RefreshFull, diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 65eab49d..60b7a4db 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -62,6 +62,14 @@ else () FOLDER "${folder}") endif () +file(COPY + data/wallet_9svHk1.keys + data/wallet_9svHk1 + data/outputs + data/unsigned_monero_tx + data/signed_monero_tx + DESTINATION data) + add_subdirectory(core_tests) add_subdirectory(crypto) add_subdirectory(functional_tests) diff --git a/tests/data/outputs b/tests/data/outputs new file mode 100644 index 0000000000000000000000000000000000000000..abb351c29380a2daeb258675886cded6ad96738b GIT binary patch literal 1035 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 u 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 literal 0 HcmV?d00001 diff --git a/tests/data/wallet_9svHk1 b/tests/data/wallet_9svHk1 new file mode 100644 index 0000000000000000000000000000000000000000..a49b6b50ef8766f77da46798cf7c66f8418dd8a0 GIT binary patch literal 1971 zcmV;k2Tb^yopU+uqUk274^Riw0%uWL)YVSE>V+sQ)=9O}ws-Sf*{U2aazNlT8g`b+ z|EHb%(oKJ1@vZUEIcfv83(*m94}WGI>SUZ?JhF5Yq@iO;6-fEpYhP@1X$+}tJ#35T zq_2NO?F%*Rz)zK4QCVL%t*p{3;JDJiJp(5#-k}f7lTSUuYPHU)#85i<{ZQD_SM9tPgVFw1T?DdjcK=dsyudR(DSDdxv6CGgL+xF^ld1O$3l`Vo)GvNqE$ zswiLt4&EUew4TRYQRqmVy_huDIT^)SE|*W{4A(|wdnhzP?oq}lU1JFZe$`OOZCOJPETF&GWnLWyp9LT<$4Q{E(oxc})gk6sHMWk|RMC zE6vK2i>E}uc5At3cYCTauhM7%6m2M4L?Fc?)oRADGXmY;(BoDh+)8!fa2@x#>P^7T zo*TNcl#{jA9Xt}sM@4~Wveja|9JxL6NNf&x4EUuw=E;=`zSe@}7y~<9!Y&n2rGVe! z9dWV?=D^5}j8!xMhH*=)9kNSsvfFg_2C2Cw;0=mDHP`N!D$CyB)@w3n1Sk^48k67K6c|8%8OL~S~i~5q@pq$P!^#K5N*p@dBVwEncm3*_cH3M$073wKmE`dz zdSUq3ec6EQaEC7cy=XvK6OMW%bZ=G_hEgxT1QLw2z185E8bl!LBaLeovKG_O^)fAZ zvLC3rF9*3Xfs5k+RxsAK9EOvXR%@m?{DRN0-yXcc(0)d@m1Axoc<6S?0hARke2CxJ z$4cV`KmX~8If+>pc8@dOWj5eSbUw?K;EdNGPe3lL5wqt0oa5SN;|jd#S2(p4UcYBU zOCdFbwH0}O4=e}%r6Y(5T>e(?QY_SrdI;;QH{R31y4G1eG$`7LCuV5SJEhnU0<_tUT6;26LVu6Bh?{X@J~x;&5>l4Hex zTxJL?kia;mp6d%9xKi~~PDhVBfIY`sb~?}_us79Y`SNZIi*$8wdrlc-W{vRk5AP6& zqAU8VUT3oN(7c9Z`k-wpCnId8s4X4=S$tzZ1+`}yuR{nbAUbfgA>-8$J`Xt%P|F`N z?J0)F;r?XOj_LN@_p#p0TkjLuneIQ}H?Sk}YFPMGGn*W|-Ryz-lX<`!*jR|cq*zL! zdYDl9$^9eN&+W%vyzAuZfO>RabN>)YbC0P(p3B>@<{|QCnm1LSIpFW2$gd?M1jE+Dh?h_w;R`0=j%3T{aII2J=M>D z4n9&O{I_w7z|N1xtYl4r@JVpPGFZgDmL6l=gw^as$@C`(h#hOFeHtz2&DZ zV8Q0-wx3sOhR&eG0AtV_cSggc)3Kv=maMA>4DEIqwMoXH{pmgjPLCfncOZ>FnoSzP z9ui{W_>iLkJU!3y{W(`=9(a$s*rYlQt~Wc*+!0hYkf9!-j96Ao(l%gV%Q&*gGkrV% zaM_4Gj*jJ%2%wm2;+y+tWuzcQ#da``~UVF6RUJWJzok$(*AYCy+O z;@()ebi~J(EkAnYcdfr)o@6hMZ-JdcDfJfXpBQ11m!q0i{O!me(Be8B7`m=qMfO*7 zM%&D-6tjioe7DX`pgDT|l;-iJHQ^(8rP8{LYC0!83GzY&%lEMtRQGuz8vaOdc?@`nSB0avnd zgr@nRqR1I|rxqCY5)B#DOP0kT54$N9l%?k=p38M7HQ4gA;!y!$;hd)|>L_N1}Lc2d-S9;V@$`qsIMQp-zNOHRu^F)(}Z FyHv~3)xrP( literal 0 HcmV?d00001 diff --git a/tests/data/wallet_9svHk1.keys b/tests/data/wallet_9svHk1.keys new file mode 100644 index 0000000000000000000000000000000000000000..3159e200b22224c51f4d7bec8f6cac4c4b6e5aae GIT binary patch literal 759 zcmV1$aziZD%Du6X_Z2SPue=Z$PeGzav<33&T>%a;s-E48tEr zs72m+LOk`h+DTNzVlUyNE;6~(d9@l_iqc1M}fot z-mcyt_v|DKuYkxjUDXa5R%mQ~=697bs{uNWac=b%G3ni)<9{`N8oRsMe+V$`G$dOQi-tX3|6mMYwUW66X6~ z=#`^%pl@VjI0|$dQ98Ox*oLSm1Va7J<-y@5D0y*^PTu%^G_WL>-2+h!qnDW_plgad zT7mMbFbjKfucN<|${&KKZMc-6-Zt!@NQ3S0%@gvJcZbL8mViT|6L(1BZ*!-efR~m5 zFCHgloM7$1yX}KA%_(%a`O0k`KMK^%gHs(^>J&g4h*yVP@K;$@jgCQDu+<~6j;%tl zDGl(D{6!6vYKUIXPZ7q#-?i{Nl8Ueg?CHo*-$8pXf}Cr%7_k56erK*T?3=5m(RYL; z#-6MJSNYUj6p|F504*A&sT?m0o!XobvpU>fbR7$ruhm_P(1~O>Zho`Te#gd>EGtR- z)3(bW*UkJHZKr!+*AAVh(Vc8aJp+b%5Ab7!#c!l#o|IVBT}XdXT7^gpw9er5qLkn= zzP6HM*@0@9q_Xu-eJ^YIUjr&={CsqYoZlhMaKh6)b)ZWngE*ie0gVomf1cUhGQfZ0 pq1Xu5O&NRpP{+83EGgxNUG`Ty-{ #include #include +#include #include "cryptonote_core/cryptonote_basic.h" #include "cryptonote_core/cryptonote_basic_impl.h" #include "ringct/rctSigs.h" @@ -44,6 +45,7 @@ #include "serialization/variant.h" #include "serialization/vector.h" #include "serialization/binary_utils.h" +#include "wallet/wallet2.h" #include "gtest/gtest.h" using namespace std; @@ -649,3 +651,514 @@ TEST(Serialization, serializes_ringct_types) ASSERT_TRUE(serialization::dump_binary(tx1, blob2)); ASSERT_TRUE(blob == blob2); } + +TEST(Serialization, portability_wallet) +{ + const bool testnet = true; + const bool restricted = false; + tools::wallet2 w(testnet, restricted); + string wallet_file = "../data/wallet_9svHk1"; + string password = "test"; + bool r = false; + try + { + w.load(wallet_file, password); + r = true; + } + catch (const exception& e) + {} + ASSERT_TRUE(r); + /* + fields of tools::wallet2 to be checked: + std::vector m_blockchain + std::vector m_transfers // TODO + cryptonote::account_public_address m_account_public_address + std::unordered_map m_key_images + std::unordered_map m_unconfirmed_txs + std::unordered_multimap m_payments + std::unordered_map m_tx_keys + std::unordered_map m_confirmed_txs + std::unordered_map m_tx_notes + std::unordered_map m_unconfirmed_payments + std::unordered_map m_pub_keys + std::vector m_address_book + */ + // blockchain + ASSERT_TRUE(w.m_blockchain.size() == 1); + ASSERT_TRUE(epee::string_tools::pod_to_hex(w.m_blockchain[0]) == "48ca7cd3c8de5b6a4d53d2861fbdaedca141553559f9be9520068053cda8430b"); + // transfers (TODO) + ASSERT_TRUE(w.m_transfers.size() == 3); + // account public address + ASSERT_TRUE(epee::string_tools::pod_to_hex(w.m_account_public_address.m_view_public_key) == "e47d4b6df6ab7339539148c2a03ad3e2f3434e5ab2046848e1f21369a3937cad"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(w.m_account_public_address.m_spend_public_key) == "13daa2af00ad26a372d317195de0bdd716f7a05d33bc4d7aff1664b6ee93c060"); + // key images + ASSERT_TRUE(w.m_key_images.size() == 3); + { + crypto::key_image ki[3]; + epee::string_tools::hex_to_pod("c5680d3735b90871ca5e3d90cd82d6483eed1151b9ab75c2c8c3a7d89e00a5a8", ki[0]); + epee::string_tools::hex_to_pod("d54cbd435a8d636ad9b01b8d4f3eb13bd0cf1ce98eddf53ab1617f9b763e66c0", ki[1]); + epee::string_tools::hex_to_pod("6c3cd6af97c4070a7aef9b1344e7463e29c7cd245076fdb65da447a34da3ca76", ki[2]); + ASSERT_TRUE(w.m_key_images.find(ki[0])->second == 0); + ASSERT_TRUE(w.m_key_images.find(ki[1])->second == 1); + ASSERT_TRUE(w.m_key_images.find(ki[2])->second == 2); + } + // unconfirmed txs + ASSERT_TRUE(w.m_unconfirmed_txs.size() == 0); + // payments + ASSERT_TRUE(w.m_payments.size() == 2); + { + auto pd0 = w.m_payments.begin(); + auto pd1 = pd0; + ++pd1; + ASSERT_TRUE(epee::string_tools::pod_to_hex(pd0->first) == "0000000000000000000000000000000000000000000000000000000000000000"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(pd1->first) == "0000000000000000000000000000000000000000000000000000000000000000"); + if (epee::string_tools::pod_to_hex(pd0->second.m_tx_hash) == "ec34c9bb12b99af33d49691384eee5bed9171498ff04e59516505f35d1fc5efc") + swap(pd0, pd1); + ASSERT_TRUE(epee::string_tools::pod_to_hex(pd0->second.m_tx_hash) == "15024343b38e77a1a9860dfed29921fa17e833fec837191a6b04fa7cb9605b8e"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(pd1->second.m_tx_hash) == "ec34c9bb12b99af33d49691384eee5bed9171498ff04e59516505f35d1fc5efc"); + ASSERT_TRUE(pd0->second.m_amount == 13400845012231); + ASSERT_TRUE(pd1->second.m_amount == 1200000000000); + ASSERT_TRUE(pd0->second.m_block_height == 818424); + ASSERT_TRUE(pd1->second.m_block_height == 818522); + ASSERT_TRUE(pd0->second.m_unlock_time == 818484); + ASSERT_TRUE(pd1->second.m_unlock_time == 0); + ASSERT_TRUE(pd0->second.m_timestamp == 1483263366); + ASSERT_TRUE(pd1->second.m_timestamp == 1483272963); + } + // tx keys + ASSERT_TRUE(w.m_tx_keys.size() == 2); + { + auto tx_key0 = w.m_tx_keys.begin(); + auto tx_key1 = tx_key0; + ++tx_key1; + if (epee::string_tools::pod_to_hex(tx_key0->first) == "6e7013684d35820f66c6679197ded9329bfe0e495effa47e7b25258799858dba") + swap(tx_key0, tx_key1); + ASSERT_TRUE(epee::string_tools::pod_to_hex(tx_key0->first) == "b9aac8c020ab33859e0c0b6331f46a8780d349e7ac17b067116e2d87bf48daad"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(tx_key1->first) == "6e7013684d35820f66c6679197ded9329bfe0e495effa47e7b25258799858dba"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(tx_key0->second) == "bf3614c6de1d06c09add5d92a5265d8c76af706f7bc6ac830d6b0d109aa87701"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(tx_key1->second) == "e556884246df5a787def6732c6ea38f1e092fa13e5ea98f732b99c07a6332003"); + } + // confirmed txs + ASSERT_TRUE(w.m_confirmed_txs.size() == 1); + // tx notes + ASSERT_TRUE(w.m_tx_notes.size() == 2); + { + crypto::hash h[2]; + epee::string_tools::hex_to_pod("15024343b38e77a1a9860dfed29921fa17e833fec837191a6b04fa7cb9605b8e", h[0]); + epee::string_tools::hex_to_pod("6e7013684d35820f66c6679197ded9329bfe0e495effa47e7b25258799858dba", h[1]); + ASSERT_TRUE(w.m_tx_notes.find(h[0])->second == "sample note"); + ASSERT_TRUE(w.m_tx_notes.find(h[1])->second == "sample note 2"); + } + // unconfirmed payments + ASSERT_TRUE(w.m_unconfirmed_payments.size() == 0); + // pub keys + ASSERT_TRUE(w.m_pub_keys.size() == 3); + { + crypto::public_key pubkey[3]; + epee::string_tools::hex_to_pod("33f75f264574cb3a9ea5b24220a5312e183d36dc321c9091dfbb720922a4f7b0", pubkey[0]); + epee::string_tools::hex_to_pod("5066ff2ce9861b1d131cf16eeaa01264933a49f28242b97b153e922ec7b4b3cb", pubkey[1]); + epee::string_tools::hex_to_pod("0d8467e16e73d16510452b78823e082e05ee3a63788d40de577cf31eb555f0c8", pubkey[2]); + ASSERT_TRUE(w.m_pub_keys.find(pubkey[0])->second == 0); + ASSERT_TRUE(w.m_pub_keys.find(pubkey[1])->second == 1); + ASSERT_TRUE(w.m_pub_keys.find(pubkey[2])->second == 2); + } + // address book + ASSERT_TRUE(w.m_address_book.size() == 1); + { + auto address_book_row = w.m_address_book.begin(); + ASSERT_TRUE(epee::string_tools::pod_to_hex(address_book_row->m_address.m_spend_public_key) == "9bc53a6ff7b0831c9470f71b6b972dbe5ad1e8606f72682868b1dda64e119fb3"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(address_book_row->m_address.m_view_public_key) == "49fece1ef97dc0c0f7a5e2106e75e96edd910f7e86b56e1e308cd0cf734df191"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(address_book_row->m_payment_id) == "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"); + ASSERT_TRUE(address_book_row->m_description == "testnet wallet 9y52S6"); + } +} + +#define OUTPUT_EXPORT_FILE_MAGIC "Monero output export\003" +TEST(Serialization, portability_outputs) +{ + // read file + const std::string filename = "../data/outputs"; + std::string data; + bool r = epee::file_io_utils::load_file_to_string(filename, data); + ASSERT_TRUE(r); + const size_t magiclen = strlen(OUTPUT_EXPORT_FILE_MAGIC); + ASSERT_FALSE(data.size() < magiclen || memcmp(data.data(), OUTPUT_EXPORT_FILE_MAGIC, magiclen)); + // decrypt (copied from wallet2::decrypt) + auto decrypt = [] (const std::string &ciphertext, const crypto::secret_key &skey, bool authenticated) -> string + { + const size_t prefix_size = sizeof(chacha8_iv) + (authenticated ? sizeof(crypto::signature) : 0); + if(ciphertext.size() < prefix_size) + return {}; + crypto::chacha8_key key; + crypto::generate_chacha8_key(&skey, sizeof(skey), key); + const crypto::chacha8_iv &iv = *(const crypto::chacha8_iv*)&ciphertext[0]; + std::string plaintext; + plaintext.resize(ciphertext.size() - prefix_size); + if (authenticated) + { + crypto::hash hash; + crypto::cn_fast_hash(ciphertext.data(), ciphertext.size() - sizeof(signature), hash); + crypto::public_key pkey; + crypto::secret_key_to_public_key(skey, pkey); + const crypto::signature &signature = *(const crypto::signature*)&ciphertext[ciphertext.size() - sizeof(crypto::signature)]; + if(!crypto::check_signature(hash, pkey, signature)) + return {}; + } + crypto::chacha8(ciphertext.data() + sizeof(iv), ciphertext.size() - prefix_size, key, iv, &plaintext[0]); + return std::move(plaintext); + }; + crypto::secret_key view_secret_key; + epee::string_tools::hex_to_pod("339673bb1187e2f73ba7841ab6841c5553f96e9f13f8fe6612e69318db4e9d0a", view_secret_key); + bool authenticated = true; + data = decrypt(std::string(data, magiclen), view_secret_key, authenticated); + ASSERT_FALSE(data.empty()); + // check public view/spend keys + const size_t headerlen = 2 * sizeof(crypto::public_key); + ASSERT_FALSE(data.size() < headerlen); + const crypto::public_key &public_spend_key = *(const crypto::public_key*)&data[0]; + const crypto::public_key &public_view_key = *(const crypto::public_key*)&data[sizeof(crypto::public_key)]; + ASSERT_TRUE(epee::string_tools::pod_to_hex(public_spend_key) == "13daa2af00ad26a372d317195de0bdd716f7a05d33bc4d7aff1664b6ee93c060"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(public_view_key) == "e47d4b6df6ab7339539148c2a03ad3e2f3434e5ab2046848e1f21369a3937cad"); + r = false; + std::vector outputs; + try + { + std::istringstream iss(std::string(data, headerlen)); + boost::archive::portable_binary_iarchive ar(iss); + ar >> outputs; + r = true; + } + catch (...) + {} + ASSERT_TRUE(r); + /* + fields of tools::wallet2::transfer_details to be checked: + uint64_t m_block_height + cryptonote::transaction_prefix m_tx // TODO + crypto::hash m_txid + size_t m_internal_output_index + uint64_t m_global_output_index + bool m_spent + uint64_t m_spent_height + crypto::key_image m_key_image + rct::key m_mask + uint64_t m_amount + bool m_rct + bool m_key_image_known + size_t m_pk_index + */ + ASSERT_TRUE(outputs.size() == 3); + auto& td0 = outputs[0]; + auto& td1 = outputs[1]; + auto& td2 = outputs[2]; + ASSERT_TRUE(td0.m_block_height == 818424); + ASSERT_TRUE(td1.m_block_height == 818522); + ASSERT_TRUE(td2.m_block_height == 818522); + ASSERT_TRUE(epee::string_tools::pod_to_hex(td0.m_txid) == "15024343b38e77a1a9860dfed29921fa17e833fec837191a6b04fa7cb9605b8e"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(td1.m_txid) == "ec34c9bb12b99af33d49691384eee5bed9171498ff04e59516505f35d1fc5efc"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(td2.m_txid) == "6e7013684d35820f66c6679197ded9329bfe0e495effa47e7b25258799858dba"); + ASSERT_TRUE(td0.m_internal_output_index == 0); + ASSERT_TRUE(td1.m_internal_output_index == 0); + ASSERT_TRUE(td2.m_internal_output_index == 1); + ASSERT_TRUE(td0.m_global_output_index == 19642); + ASSERT_TRUE(td1.m_global_output_index == 19757); + ASSERT_TRUE(td2.m_global_output_index == 19760); + ASSERT_TRUE (td0.m_spent); + ASSERT_FALSE(td1.m_spent); + ASSERT_FALSE(td2.m_spent); + ASSERT_TRUE(td0.m_spent_height == 0); + ASSERT_TRUE(td1.m_spent_height == 0); + ASSERT_TRUE(td2.m_spent_height == 0); + ASSERT_TRUE(epee::string_tools::pod_to_hex(td0.m_key_image) == "c5680d3735b90871ca5e3d90cd82d6483eed1151b9ab75c2c8c3a7d89e00a5a8"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(td1.m_key_image) == "d54cbd435a8d636ad9b01b8d4f3eb13bd0cf1ce98eddf53ab1617f9b763e66c0"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(td2.m_key_image) == "6c3cd6af97c4070a7aef9b1344e7463e29c7cd245076fdb65da447a34da3ca76"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(td0.m_mask) == "0100000000000000000000000000000000000000000000000000000000000000"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(td1.m_mask) == "d3997a7b27fa199a377643b88cbd3f20f447496746dabe92d288730ecaeda007"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(td2.m_mask) == "789bafff169ef206aa21219342c69ca52ce1d78d776c10b21d14bdd960fc7703"); + ASSERT_TRUE(td0.m_amount == 13400845012231); + ASSERT_TRUE(td1.m_amount == 1200000000000); + ASSERT_TRUE(td2.m_amount == 11066009260865); + ASSERT_TRUE(td0.m_rct); + ASSERT_TRUE(td1.m_rct); + ASSERT_TRUE(td2.m_rct); + ASSERT_TRUE(td0.m_key_image_known); + ASSERT_TRUE(td1.m_key_image_known); + ASSERT_TRUE(td2.m_key_image_known); + ASSERT_TRUE(td0.m_pk_index == 0); + ASSERT_TRUE(td1.m_pk_index == 0); + ASSERT_TRUE(td2.m_pk_index == 0); +} + +#define UNSIGNED_TX_PREFIX "Monero unsigned tx set\003" +TEST(Serialization, portability_unsigned_tx) +{ + const string filename = "../data/unsigned_monero_tx"; + std::string s; + const bool testnet = true; + bool r = epee::file_io_utils::load_file_to_string(filename, s); + ASSERT_TRUE(r); + const size_t magiclen = strlen(UNSIGNED_TX_PREFIX); + ASSERT_FALSE(strncmp(s.c_str(), UNSIGNED_TX_PREFIX, magiclen)); + tools::wallet2::unsigned_tx_set exported_txs; + s = s.substr(magiclen); + r = false; + try + { + std::istringstream iss(s); + boost::archive::portable_binary_iarchive ar(iss); + ar >> exported_txs; + r = true; + } + catch (...) + {} + ASSERT_TRUE(r); + /* + fields of tools::wallet2::unsigned_tx_set to be checked: + std::vector txes + std::vector m_transfers + + fields of toolw::wallet2::tx_construction_data to be checked: + std::vector sources + cryptonote::tx_destination_entry change_dts + std::vector splitted_dsts + std::list selected_transfers + std::vector extra + uint64_t unlock_time + bool use_rct + std::vector dests + + fields of cryptonote::tx_source_entry to be checked: + std::vector> outputs + size_t real_output + crypto::public_key real_out_tx_key + size_t real_output_in_tx_index + uint64_t amount + bool rct + rct::key mask + + fields of cryptonote::tx_destination_entry to be checked: + uint64_t amount + account_public_address addr + */ + // txes + ASSERT_TRUE(exported_txs.txes.size() == 1); + auto& tcd = exported_txs.txes[0]; + // tcd.sources + ASSERT_TRUE(tcd.sources.size() == 1); + auto& tse = tcd.sources[0]; + // tcd.sources[0].outputs + ASSERT_TRUE(tse.outputs.size() == 5); + auto& out0 = tse.outputs[0]; + auto& out1 = tse.outputs[1]; + auto& out2 = tse.outputs[2]; + auto& out3 = tse.outputs[3]; + auto& out4 = tse.outputs[4]; + ASSERT_TRUE(out0.first == 6295); + ASSERT_TRUE(out1.first == 14302); + ASSERT_TRUE(out2.first == 17598); + ASSERT_TRUE(out3.first == 18671); + ASSERT_TRUE(out4.first == 19760); + ASSERT_TRUE(epee::string_tools::pod_to_hex(out0.second) == "e7272cb589954ddeedd20de9411ed57265f154d41f33cec9ff69e5d642e09814096490b0ac85308342acf436cc0270d53abef9dc04c6202f2459e879bfd40ce6"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(out1.second) == "c3a9f49d1fe75939cc3feb39871ce0a7366c2879a63faa1a5cf34e65723b120a272ff0c7d84ab8b6ee3528d196450b0e28b3fed276bc2597a2b5b17afb9354ab"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(out2.second) == "176e239c8c39000c2275e2f63ed7d55c55e0843524091522bbd3d3b869044969021fad70fc1244115449d4754829ae7c47346342ee5d52a2cdd47dfc351d0ab0"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(out3.second) == "ef12d7946302fb064f2ba9df1a73d72233ac74664ed3b370580fa3bdc377542ad93f64898bd95851d6efe0d7bf2dbbea9b7c6b3c57e2c807e7b17d55b4622259"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(out4.second) == "0d8467e16e73d16510452b78823e082e05ee3a63788d40de577cf31eb555f0c8525096cbc88d00a841eed66f3cdb6f0a018e6ce9fb9433ed61afba15cbbebd04"); + // tcd.sources[0].{real_output, real_out_tx_key, real_output_in_tx_index, amount, rct, mask} + ASSERT_TRUE(tse.real_output == 4); + ASSERT_TRUE(epee::string_tools::pod_to_hex(tse.real_out_tx_key) == "4d86c7ba1c285fe4bc1cd7b54ba894fa89fa02fc6b0bbeea67d53251acd14a05"); + ASSERT_TRUE(tse.real_output_in_tx_index == 1); + ASSERT_TRUE(tse.amount == 11066009260865); + ASSERT_TRUE(tse.rct); + ASSERT_TRUE(epee::string_tools::pod_to_hex(tse.mask) == "789bafff169ef206aa21219342c69ca52ce1d78d776c10b21d14bdd960fc7703"); + // tcd.change_dts + ASSERT_TRUE(tcd.change_dts.amount == 9631208773403); + ASSERT_TRUE(cryptonote::get_account_address_as_str(testnet, tcd.change_dts.addr) == "9svHk1wHPo3ULf2AZykghzcye6sitaRE4MaDjPC6uanTHCynHjJHZaiAb922PojE1GexhhRt1LVf5DC43feyrRZMLXQr3mk"); + // tcd.splitted_dsts + ASSERT_TRUE(tcd.splitted_dsts.size() == 2); + auto& splitted_dst0 = tcd.splitted_dsts[0]; + auto& splitted_dst1 = tcd.splitted_dsts[1]; + ASSERT_TRUE(splitted_dst0.amount == 1400000000000); + ASSERT_TRUE(splitted_dst1.amount == 9631208773403); + ASSERT_TRUE(cryptonote::get_account_address_as_str(testnet, splitted_dst0.addr) == "9xnhrMczQkPeoGi6dyu6BgKAYX4tZsDs6KHCkyTStDBKL4M4pM1gfCR3utmTAcSaKHGa1R5o266FbdnubErmij3oMdLyYgA"); + ASSERT_TRUE(cryptonote::get_account_address_as_str(testnet, splitted_dst1.addr) == "9svHk1wHPo3ULf2AZykghzcye6sitaRE4MaDjPC6uanTHCynHjJHZaiAb922PojE1GexhhRt1LVf5DC43feyrRZMLXQr3mk"); + // tcd.selected_transfers + ASSERT_TRUE(tcd.selected_transfers.size() == 1); + ASSERT_TRUE(tcd.selected_transfers.front() == 2); + // tcd.extra + ASSERT_TRUE(tcd.extra.size() == 68); + string tcd_extra_str = epee::string_tools::buff_to_hex(string(reinterpret_cast(tcd.extra.data()), tcd.extra.size())); + ASSERT_TRUE(tcd_extra_str == "0x2 0x21 0x0 0xf8 0xd 0xbc 0xfc 0xa2 0x2d 0x84 0x1e 0xa0 0x46 0x18 0x7a 0x5b 0x19 0xea 0x4d 0xd1 0xa2 0x8a 0x58 0xa8 0x72 0x9 0xd5 0xdf 0x2 0x30 0x60 0xac 0x9e 0x48 0x84 0x1 0xb2 0xfd 0x5d 0x4e 0x45 0x8b 0xf1 0x28 0xa0 0xc8 0x30 0xd1 0x35 0x4f 0x47 0xb9 0xed 0xc9 0x82 0x8c 0x83 0x37 0x7d 0xb6 0xb5 0xe5 0x3d 0xff 0x64 0xb0 0xde 0x7f "); + // tcd.{unlock_time, use_rct} + ASSERT_TRUE(tcd.unlock_time == 0); + ASSERT_TRUE(tcd.use_rct); + // tcd.dests + ASSERT_TRUE(tcd.dests.size() == 1); + auto& dest = tcd.dests[0]; + ASSERT_TRUE(dest.amount == 1400000000000); + ASSERT_TRUE(cryptonote::get_account_address_as_str(testnet, dest.addr) == "9xnhrMczQkPeoGi6dyu6BgKAYX4tZsDs6KHCkyTStDBKL4M4pM1gfCR3utmTAcSaKHGa1R5o266FbdnubErmij3oMdLyYgA"); + // transfers + ASSERT_TRUE(exported_txs.transfers.size() == 3); + auto& td0 = exported_txs.transfers[0]; + auto& td1 = exported_txs.transfers[1]; + auto& td2 = exported_txs.transfers[2]; + ASSERT_TRUE(td0.m_block_height == 818424); + ASSERT_TRUE(td1.m_block_height == 818522); + ASSERT_TRUE(td2.m_block_height == 818522); + ASSERT_TRUE(epee::string_tools::pod_to_hex(td0.m_txid) == "15024343b38e77a1a9860dfed29921fa17e833fec837191a6b04fa7cb9605b8e"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(td1.m_txid) == "ec34c9bb12b99af33d49691384eee5bed9171498ff04e59516505f35d1fc5efc"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(td2.m_txid) == "6e7013684d35820f66c6679197ded9329bfe0e495effa47e7b25258799858dba"); + ASSERT_TRUE(td0.m_internal_output_index == 0); + ASSERT_TRUE(td1.m_internal_output_index == 0); + ASSERT_TRUE(td2.m_internal_output_index == 1); + ASSERT_TRUE(td0.m_global_output_index == 19642); + ASSERT_TRUE(td1.m_global_output_index == 19757); + ASSERT_TRUE(td2.m_global_output_index == 19760); + ASSERT_TRUE (td0.m_spent); + ASSERT_FALSE(td1.m_spent); + ASSERT_FALSE(td2.m_spent); + ASSERT_TRUE(td0.m_spent_height == 0); + ASSERT_TRUE(td1.m_spent_height == 0); + ASSERT_TRUE(td2.m_spent_height == 0); + ASSERT_TRUE(epee::string_tools::pod_to_hex(td0.m_key_image) == "c5680d3735b90871ca5e3d90cd82d6483eed1151b9ab75c2c8c3a7d89e00a5a8"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(td1.m_key_image) == "d54cbd435a8d636ad9b01b8d4f3eb13bd0cf1ce98eddf53ab1617f9b763e66c0"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(td2.m_key_image) == "6c3cd6af97c4070a7aef9b1344e7463e29c7cd245076fdb65da447a34da3ca76"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(td0.m_mask) == "0100000000000000000000000000000000000000000000000000000000000000"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(td1.m_mask) == "d3997a7b27fa199a377643b88cbd3f20f447496746dabe92d288730ecaeda007"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(td2.m_mask) == "789bafff169ef206aa21219342c69ca52ce1d78d776c10b21d14bdd960fc7703"); + ASSERT_TRUE(td0.m_amount == 13400845012231); + ASSERT_TRUE(td1.m_amount == 1200000000000); + ASSERT_TRUE(td2.m_amount == 11066009260865); + ASSERT_TRUE(td0.m_rct); + ASSERT_TRUE(td1.m_rct); + ASSERT_TRUE(td2.m_rct); + ASSERT_TRUE(td0.m_key_image_known); + ASSERT_TRUE(td1.m_key_image_known); + ASSERT_TRUE(td2.m_key_image_known); + ASSERT_TRUE(td0.m_pk_index == 0); + ASSERT_TRUE(td1.m_pk_index == 0); + ASSERT_TRUE(td2.m_pk_index == 0); +} + +#define SIGNED_TX_PREFIX "Monero signed tx set\003" +TEST(Serialization, portability_signed_tx) +{ + const string filename = "../data/signed_monero_tx"; + const bool testnet = true; + std::string s; + bool r = epee::file_io_utils::load_file_to_string(filename, s); + ASSERT_TRUE(r); + const size_t magiclen = strlen(SIGNED_TX_PREFIX); + ASSERT_FALSE(strncmp(s.c_str(), SIGNED_TX_PREFIX, magiclen)); + tools::wallet2::signed_tx_set exported_txs; + s = s.substr(magiclen); + r = false; + try + { + std::istringstream iss(s); + boost::archive::portable_binary_iarchive ar(iss); + ar >> exported_txs; + r = true; + } + catch (...) + {} + ASSERT_TRUE(r); + /* + fields of tools::wallet2::signed_tx_set to be checked: + std::vector ptx + std::vector key_images + + fields of tools::walllet2::pending_tx to be checked: + cryptonote::transaction tx // TODO + uint64_t dust + uint64_t fee + bool dust_added_to_fee + cryptonote::tx_destination_entry change_dts + std::list selected_transfers + std::string key_images + crypto::secret_key tx_key + std::vector dests + tx_construction_data construction_data + */ + // ptx + ASSERT_TRUE(exported_txs.ptx.size() == 1); + auto& ptx = exported_txs.ptx[0]; + // ptx.{dust, fee, dust_added_to_fee} + ASSERT_TRUE (ptx.dust == 0); + ASSERT_TRUE (ptx.fee == 34800487462); + ASSERT_FALSE(ptx.dust_added_to_fee); + // ptx.change.{amount, addr} + ASSERT_TRUE(ptx.change_dts.amount == 9631208773403); + ASSERT_TRUE(cryptonote::get_account_address_as_str(testnet, ptx.change_dts.addr) == "9svHk1wHPo3ULf2AZykghzcye6sitaRE4MaDjPC6uanTHCynHjJHZaiAb922PojE1GexhhRt1LVf5DC43feyrRZMLXQr3mk"); + // ptx.selected_transfers + ASSERT_TRUE(ptx.selected_transfers.size() == 1); + ASSERT_TRUE(ptx.selected_transfers.front() == 2); + // ptx.{key_images, tx_key} + ASSERT_TRUE(ptx.key_images == "<6c3cd6af97c4070a7aef9b1344e7463e29c7cd245076fdb65da447a34da3ca76> "); + ASSERT_TRUE(epee::string_tools::pod_to_hex(ptx.tx_key) == "0100000000000000000000000000000000000000000000000000000000000000"); + // ptx.dests + ASSERT_TRUE(ptx.dests.size() == 1); + ASSERT_TRUE(ptx.dests[0].amount == 1400000000000); + ASSERT_TRUE(cryptonote::get_account_address_as_str(testnet, ptx.dests[0].addr) == "9xnhrMczQkPeoGi6dyu6BgKAYX4tZsDs6KHCkyTStDBKL4M4pM1gfCR3utmTAcSaKHGa1R5o266FbdnubErmij3oMdLyYgA"); + // ptx.construction_data + auto& tcd = ptx.construction_data; + ASSERT_TRUE(tcd.sources.size() == 1); + auto& tse = tcd.sources[0]; + // ptx.construction_data.sources[0].outputs + ASSERT_TRUE(tse.outputs.size() == 5); + auto& out0 = tse.outputs[0]; + auto& out1 = tse.outputs[1]; + auto& out2 = tse.outputs[2]; + auto& out3 = tse.outputs[3]; + auto& out4 = tse.outputs[4]; + ASSERT_TRUE(out0.first == 6295); + ASSERT_TRUE(out1.first == 14302); + ASSERT_TRUE(out2.first == 17598); + ASSERT_TRUE(out3.first == 18671); + ASSERT_TRUE(out4.first == 19760); + ASSERT_TRUE(epee::string_tools::pod_to_hex(out0.second) == "e7272cb589954ddeedd20de9411ed57265f154d41f33cec9ff69e5d642e09814096490b0ac85308342acf436cc0270d53abef9dc04c6202f2459e879bfd40ce6"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(out1.second) == "c3a9f49d1fe75939cc3feb39871ce0a7366c2879a63faa1a5cf34e65723b120a272ff0c7d84ab8b6ee3528d196450b0e28b3fed276bc2597a2b5b17afb9354ab"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(out2.second) == "176e239c8c39000c2275e2f63ed7d55c55e0843524091522bbd3d3b869044969021fad70fc1244115449d4754829ae7c47346342ee5d52a2cdd47dfc351d0ab0"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(out3.second) == "ef12d7946302fb064f2ba9df1a73d72233ac74664ed3b370580fa3bdc377542ad93f64898bd95851d6efe0d7bf2dbbea9b7c6b3c57e2c807e7b17d55b4622259"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(out4.second) == "0d8467e16e73d16510452b78823e082e05ee3a63788d40de577cf31eb555f0c8525096cbc88d00a841eed66f3cdb6f0a018e6ce9fb9433ed61afba15cbbebd04"); + // ptx.construction_data.sources[0].{real_output, real_out_tx_key, real_output_in_tx_index, amount, rct, mask} + ASSERT_TRUE(tse.real_output == 4); + ASSERT_TRUE(epee::string_tools::pod_to_hex(tse.real_out_tx_key) == "4d86c7ba1c285fe4bc1cd7b54ba894fa89fa02fc6b0bbeea67d53251acd14a05"); + ASSERT_TRUE(tse.real_output_in_tx_index == 1); + ASSERT_TRUE(tse.amount == 11066009260865); + ASSERT_TRUE(tse.rct); + ASSERT_TRUE(epee::string_tools::pod_to_hex(tse.mask) == "789bafff169ef206aa21219342c69ca52ce1d78d776c10b21d14bdd960fc7703"); + // ptx.construction_data.change_dts + ASSERT_TRUE(tcd.change_dts.amount == 9631208773403); + ASSERT_TRUE(cryptonote::get_account_address_as_str(testnet, tcd.change_dts.addr) == "9svHk1wHPo3ULf2AZykghzcye6sitaRE4MaDjPC6uanTHCynHjJHZaiAb922PojE1GexhhRt1LVf5DC43feyrRZMLXQr3mk"); + // ptx.construction_data.splitted_dsts + ASSERT_TRUE(tcd.splitted_dsts.size() == 2); + auto& splitted_dst0 = tcd.splitted_dsts[0]; + auto& splitted_dst1 = tcd.splitted_dsts[1]; + ASSERT_TRUE(splitted_dst0.amount == 1400000000000); + ASSERT_TRUE(splitted_dst1.amount == 9631208773403); + ASSERT_TRUE(cryptonote::get_account_address_as_str(testnet, splitted_dst0.addr) == "9xnhrMczQkPeoGi6dyu6BgKAYX4tZsDs6KHCkyTStDBKL4M4pM1gfCR3utmTAcSaKHGa1R5o266FbdnubErmij3oMdLyYgA"); + ASSERT_TRUE(cryptonote::get_account_address_as_str(testnet, splitted_dst1.addr) == "9svHk1wHPo3ULf2AZykghzcye6sitaRE4MaDjPC6uanTHCynHjJHZaiAb922PojE1GexhhRt1LVf5DC43feyrRZMLXQr3mk"); + // ptx.construction_data.selected_transfers + ASSERT_TRUE(tcd.selected_transfers.size() == 1); + ASSERT_TRUE(tcd.selected_transfers.front() == 2); + // ptx.construction_data.extra + ASSERT_TRUE(tcd.extra.size() == 68); + string tcd_extra_str = epee::string_tools::buff_to_hex(string(reinterpret_cast(tcd.extra.data()), tcd.extra.size())); + ASSERT_TRUE(tcd_extra_str == "0x2 0x21 0x0 0xf8 0xd 0xbc 0xfc 0xa2 0x2d 0x84 0x1e 0xa0 0x46 0x18 0x7a 0x5b 0x19 0xea 0x4d 0xd1 0xa2 0x8a 0x58 0xa8 0x72 0x9 0xd5 0xdf 0x2 0x30 0x60 0xac 0x9e 0x48 0x84 0x1 0xb2 0xfd 0x5d 0x4e 0x45 0x8b 0xf1 0x28 0xa0 0xc8 0x30 0xd1 0x35 0x4f 0x47 0xb9 0xed 0xc9 0x82 0x8c 0x83 0x37 0x7d 0xb6 0xb5 0xe5 0x3d 0xff 0x64 0xb0 0xde 0x7f "); + // ptx.construction_data.{unlock_time, use_rct} + ASSERT_TRUE(tcd.unlock_time == 0); + ASSERT_TRUE(tcd.use_rct); + // ptx.construction_data.dests + ASSERT_TRUE(tcd.dests.size() == 1); + auto& dest = tcd.dests[0]; + ASSERT_TRUE(dest.amount == 1400000000000); + ASSERT_TRUE(cryptonote::get_account_address_as_str(testnet, dest.addr) == "9xnhrMczQkPeoGi6dyu6BgKAYX4tZsDs6KHCkyTStDBKL4M4pM1gfCR3utmTAcSaKHGa1R5o266FbdnubErmij3oMdLyYgA"); + // key_images + ASSERT_TRUE(exported_txs.key_images.size() == 3); + auto& ki0 = exported_txs.key_images[0]; + auto& ki1 = exported_txs.key_images[1]; + auto& ki2 = exported_txs.key_images[2]; + ASSERT_TRUE(epee::string_tools::pod_to_hex(ki0) == "c5680d3735b90871ca5e3d90cd82d6483eed1151b9ab75c2c8c3a7d89e00a5a8"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(ki1) == "d54cbd435a8d636ad9b01b8d4f3eb13bd0cf1ce98eddf53ab1617f9b763e66c0"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(ki2) == "6c3cd6af97c4070a7aef9b1344e7463e29c7cd245076fdb65da447a34da3ca76"); +}