Skip to content

Commit 3a42adf

Browse files
Txs, transfers and outputs querying consolidation
* Implement `MoneroWalletRpc::sweep_unlocked` * Implement `test_monero_wallet_model` unit tests * Fix `MoneroWalletRpc::sweep_output`, `MoneroWalletRpc::sweep_account`, `MoneroWalletRpc::get_outputs_aux`, `PyMoneroWalletRpc::verify_message` * Fix tx query reference in transfer and output query * Add wallet `get_tx(const std::string&)` and `get_txs(const std::vector<string>&)` convenience methods * Fix `MoneroWallet::verify_message` to return bad result for consistency * Fix wallet data model deserialization
1 parent 1adbf7b commit 3a42adf

27 files changed

Lines changed: 2094 additions & 150 deletions

src/cpp/py_monero.cpp

Lines changed: 113 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -960,13 +960,32 @@ PYBIND11_MODULE(monero, m) {
960960
MONERO_CATCH_AND_RETHROW(monero::monero_transfer_query::deserialize_from_block(transfer_query_json));
961961
}, py::arg("transfer_query_json"))
962962
.def_readwrite("incoming", &monero::monero_transfer_query::m_is_incoming)
963+
.def_property("outgoing",
964+
[](const monero::monero_transfer_query& self) { return self.is_outgoing(); },
965+
[](monero::monero_transfer_query& self, const boost::optional<bool>& val) {
966+
if (val == boost::none) self.m_is_incoming = boost::none;
967+
else self.m_is_incoming = !val.get();
968+
})
963969
.def_readwrite("address", &monero::monero_transfer_query::m_address)
964970
.def_readwrite("addresses", &monero::monero_transfer_query::m_addresses)
965-
.def_readwrite("address", &monero::monero_transfer_query::m_subaddress_index)
971+
.def_readwrite("subaddress_index", &monero::monero_transfer_query::m_subaddress_index)
966972
.def_readwrite("subaddress_indices", &monero::monero_transfer_query::m_subaddress_indices)
967973
.def_readwrite("destinations", &monero::monero_transfer_query::m_destinations)
968974
.def_readwrite("has_destinations", &monero::monero_transfer_query::m_has_destinations)
969-
.def_readwrite("tx_query", &monero::monero_transfer_query::m_tx_query)
975+
.def_property("tx_query",
976+
[](const monero::monero_transfer_query& self) { return self.m_tx_query; },
977+
[](std::shared_ptr<monero::monero_transfer_query>& self, const std::shared_ptr<monero::monero_tx_query>& val) {
978+
const auto old_query = self->m_tx_query;
979+
self->m_tx_query = val;
980+
if (val != nullptr) {
981+
val->m_transfer_query = self;
982+
}
983+
else self->m_tx_query = boost::none;
984+
985+
if (old_query != boost::none) {
986+
old_query.get()->m_transfer_query = boost::none;
987+
}
988+
})
970989
.def("copy", [](const std::shared_ptr<monero::monero_transfer_query>& self) {
971990
auto tgt = std::make_shared<monero::monero_transfer_query>();
972991
MONERO_CATCH_AND_RETHROW(self->copy(self, tgt));
@@ -1003,7 +1022,21 @@ PYBIND11_MODULE(monero, m) {
10031022
.def_readwrite("subaddress_indices", &monero::monero_output_query::m_subaddress_indices)
10041023
.def_readwrite("min_amount", &monero::monero_output_query::m_min_amount)
10051024
.def_readwrite("max_amount", &monero::monero_output_query::m_max_amount)
1006-
.def_readwrite("tx_query", &monero::monero_output_query::m_tx_query)
1025+
.def_readonly("tx_query", &monero::monero_output_query::m_tx_query)
1026+
.def("set_tx_query", [](const std::shared_ptr<monero::monero_output_query>& self, const std::shared_ptr<monero::monero_tx_query>& val, bool output_query) {
1027+
const auto old_query = self->m_tx_query;
1028+
if (val != nullptr) {
1029+
self->m_tx_query = val;
1030+
if (output_query) val->m_output_query = self;
1031+
else val->m_input_query = self;
1032+
} else {
1033+
self->m_tx_query = boost::none;
1034+
}
1035+
if (old_query != boost::none) {
1036+
if (output_query) old_query.get()->m_output_query = boost::none;
1037+
else old_query.get()->m_input_query = boost::none;
1038+
}
1039+
}, py::arg("tx_query"), py::arg("output_query"))
10071040
.def("copy", [](const std::shared_ptr<monero::monero_output_query>& self) {
10081041
auto tgt = std::make_shared<monero::monero_output_query>();
10091042
MONERO_CATCH_AND_RETHROW(self->copy(self, tgt));
@@ -1093,9 +1126,51 @@ PYBIND11_MODULE(monero, m) {
10931126
.def_readwrite("min_height", &monero::monero_tx_query::m_min_height)
10941127
.def_readwrite("max_height", &monero::monero_tx_query::m_max_height)
10951128
.def_readwrite("include_outputs", &monero::monero_tx_query::m_include_outputs)
1096-
.def_readwrite("transfer_query", &monero::monero_tx_query::m_transfer_query)
1097-
.def_readwrite("input_query", &monero::monero_tx_query::m_input_query)
1098-
.def_readwrite("output_query", &monero::monero_tx_query::m_output_query)
1129+
.def_property("transfer_query",
1130+
[](const monero::monero_tx_query& self) { return self.m_transfer_query; },
1131+
[](std::shared_ptr<monero::monero_tx_query>& self, const boost::optional<std::shared_ptr<monero::monero_transfer_query>>& val) {
1132+
const auto old_query = self->m_transfer_query;
1133+
self->m_transfer_query = val;
1134+
if (self->m_transfer_query != boost::none) {
1135+
self->m_transfer_query.get()->m_tx_query = self;
1136+
}
1137+
if (old_query != boost::none) {
1138+
if (val != boost::none && val.get() == old_query.get()) {
1139+
return;
1140+
}
1141+
old_query.get()->m_tx_query = boost::none;
1142+
}
1143+
})
1144+
.def_property("input_query",
1145+
[](const monero::monero_tx_query& self) { return self.m_input_query; },
1146+
[](std::shared_ptr<monero::monero_tx_query>& self, const boost::optional<std::shared_ptr<monero::monero_output_query>>& val) {
1147+
const auto old_query = self->m_input_query;
1148+
self->m_input_query = val;
1149+
if (self->m_input_query != boost::none) {
1150+
self->m_input_query.get()->m_tx_query = self;
1151+
}
1152+
if (old_query != boost::none) {
1153+
if (val != boost::none && val.get() == old_query.get()) {
1154+
return;
1155+
}
1156+
old_query.get()->m_tx_query = boost::none;
1157+
}
1158+
})
1159+
.def_property("output_query",
1160+
[](const monero::monero_tx_query& self) { return self.m_output_query; },
1161+
[](std::shared_ptr<monero::monero_tx_query>& self, const boost::optional<std::shared_ptr<monero::monero_output_query>>& val) {
1162+
const auto old_query = self->m_output_query;
1163+
self->m_output_query = val;
1164+
if (self->m_output_query != boost::none) {
1165+
self->m_output_query.get()->m_tx_query = self;
1166+
}
1167+
if (old_query != boost::none) {
1168+
if (val != boost::none && val.get() == old_query.get()) {
1169+
return;
1170+
}
1171+
old_query.get()->m_tx_query = boost::none;
1172+
}
1173+
})
10991174
.def("copy", [](const std::shared_ptr<monero::monero_tx_query>& self) {
11001175
auto tgt = std::make_shared<monero::monero_tx_query>();
11011176
MONERO_CATCH_AND_RETHROW(self->copy(self, tgt));
@@ -1686,6 +1761,16 @@ PYBIND11_MODULE(monero, m) {
16861761
.def("set_subaddress_label", [](PyMoneroWallet& self, uint32_t account_idx, uint32_t subaddress_idx, const std::string& label) {
16871762
MONERO_CATCH_AND_RETHROW(self.set_subaddress_label(account_idx, subaddress_idx, label));
16881763
}, py::arg("account_idx"), py::arg("subaddress_idx"), py::arg("label") = "")
1764+
.def("get_tx", [](PyMoneroWallet& self, const std::string& tx_hash) {
1765+
std::shared_ptr<monero::monero_tx_wallet> result = nullptr;
1766+
monero_tx_query query;
1767+
query.m_hashes.push_back(tx_hash);
1768+
auto txs = self.get_txs(query);
1769+
if (txs.size() > 0) {
1770+
result = txs[0];
1771+
}
1772+
return result;
1773+
}, py::arg("tx_hash"))
16891774
.def("get_txs", [](PyMoneroWallet& self) {
16901775
MONERO_CATCH_AND_RETHROW(self.get_txs());
16911776
})
@@ -1703,6 +1788,22 @@ PYBIND11_MODULE(monero, m) {
17031788
throw PyMoneroError(e.what());
17041789
}
17051790
}, py::arg("query"))
1791+
.def("get_txs", [](PyMoneroWallet& self, const std::vector<std::string>& tx_hashes) {
1792+
try {
1793+
monero_tx_query query;
1794+
query.m_hashes = tx_hashes;
1795+
auto txs = self.get_txs(query);
1796+
PyMoneroUtils::sort_txs_wallet(txs, query.m_hashes);
1797+
return txs;
1798+
} catch (const PyMoneroRpcError& e) {
1799+
throw;
1800+
} catch (const PyMoneroError& e) {
1801+
throw;
1802+
}
1803+
catch (const std::exception& e) {
1804+
throw PyMoneroError(e.what());
1805+
}
1806+
}, py::arg("tx_hashes"))
17061807
.def("get_transfers", [](PyMoneroWallet& self, const monero::monero_transfer_query& query) {
17071808
MONERO_CATCH_AND_RETHROW(self.get_transfers(query));
17081809
}, py::arg("query"))
@@ -1776,7 +1877,12 @@ PYBIND11_MODULE(monero, m) {
17761877
MONERO_CATCH_AND_RETHROW(self.sign_message(msg, signature_type, account_idx, subaddress_idx));
17771878
}, py::arg("msg"), py::arg("signature_type"), py::arg("account_idx") = 0, py::arg("subaddress_idx") = 0)
17781879
.def("verify_message", [](PyMoneroWallet& self, const std::string& msg, const std::string& address, const std::string& signature) {
1779-
MONERO_CATCH_AND_RETHROW(self.verify_message(msg, address, signature));
1880+
try {
1881+
return self.verify_message(msg, address, signature);
1882+
} catch (...) {
1883+
// TODO wallet full can differentiate incorrect from invalid address, but rpc returns -2 for both, so returning bad result for consistency
1884+
return monero::monero_message_signature_result();
1885+
}
17801886
}, py::arg("msg"), py::arg("address"), py::arg("signature"))
17811887
.def("get_tx_key", [](PyMoneroWallet& self, const std::string& tx_hash) {
17821888
MONERO_CATCH_AND_RETHROW(self.get_tx_key(tx_hash));

src/cpp/wallet/py_monero_wallet_model.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,6 @@ void PyMoneroTxWallet::from_property_tree_with_output(const boost::property_tree
526526

527527
for(auto it = node.begin(); it != node.end(); ++it) {
528528
std::string key = it->first;
529-
530529
if (key == std::string("amount")) output->m_amount = it->second.get_value<uint64_t>();
531530
else if (key == std::string("spent")) output->m_is_spent = it->second.get_value<bool>();
532531
else if (key == std::string("key_image")) {
@@ -539,7 +538,11 @@ void PyMoneroTxWallet::from_property_tree_with_output(const boost::property_tree
539538
else if (key == std::string("frozen")) output->m_is_frozen = it->second.get_value<bool>();
540539
else if (key == std::string("pubkey")) output->m_stealth_public_key = it->second.data();
541540
else if (key == std::string("subaddr_index")) {
542-
541+
for(auto indices_it = it->second.begin(); indices_it != it->second.end(); ++indices_it) {
542+
std::string indices_key = indices_it->first;
543+
if (indices_key == std::string("major")) output->m_account_index = indices_it->second.get_value<uint32_t>();
544+
if (indices_key == std::string("minor")) output->m_subaddress_index = indices_it->second.get_value<uint32_t>();
545+
}
543546
}
544547
else if (key == std::string("block_height")) {
545548
auto block = std::make_shared<monero::monero_block>();
@@ -825,7 +828,7 @@ void PyMoneroTxSet::from_sent_txs(const boost::property_tree::ptree& node, const
825828
}
826829
else {
827830
auto dest = std::make_shared<monero::monero_destination>();
828-
dest->m_address = config.m_destinations[destination_idx]->m_address;
831+
dest->m_address = config.get_normalized_destinations()[destination_idx]->m_address;
829832
dest->m_amount = amount;
830833
tx->m_outgoing_transfer.get()->m_destinations.push_back(dest);
831834
destination_idx++;
@@ -1495,9 +1498,13 @@ rapidjson::Value PyMoneroSweepParams::to_rapidjson_val(rapidjson::Document::Allo
14951498
if (m_priority != boost::none) monero_utils::add_json_member("priority", m_priority.get(), allocator, root, val_num);
14961499
if (m_payment_id != boost::none) monero_utils::add_json_member("payment_id", m_payment_id.get(), allocator, root, val_str);
14971500
if (m_get_tx_key != boost::none) monero_utils::add_json_member("get_tx_key", m_get_tx_key.get(), allocator, root);
1501+
if (m_get_tx_keys != boost::none) monero_utils::add_json_member("get_tx_keys", m_get_tx_keys.get(), allocator, root);
14981502
if (m_get_tx_hex != boost::none) monero_utils::add_json_member("get_tx_hex", m_get_tx_hex.get(), allocator, root);
14991503
if (m_get_tx_metadata != boost::none) monero_utils::add_json_member("get_tx_metadata", m_get_tx_metadata.get(), allocator, root);
1500-
if (m_relay != boost::none) monero_utils::add_json_member("do_not_relay", !m_relay.get(), allocator, root);
1504+
if (m_below_amount != boost::none) monero_utils::add_json_member("below_amount", m_below_amount.get(), allocator, root, val_num);
1505+
1506+
bool relay = bool_equals_2(true, m_relay);
1507+
monero_utils::add_json_member("do_not_relay", !relay, allocator, root);
15011508
return root;
15021509
}
15031510

src/cpp/wallet/py_monero_wallet_model.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,7 @@ class PyMoneroSweepParams : public PyMoneroJsonRequestParams {
786786
boost::optional<std::string> m_payment_id;
787787
boost::optional<uint64_t> m_below_amount;
788788
boost::optional<bool> m_get_tx_key;
789+
boost::optional<bool> m_get_tx_keys;
789790
boost::optional<bool> m_get_tx_hex;
790791
boost::optional<bool> m_get_tx_metadata;
791792

0 commit comments

Comments
 (0)