From 9cd50b37af9f75aa0bb3c854b08a8a97d6ba4d38 Mon Sep 17 00:00:00 2001 From: woodser Date: Mon, 10 Jun 2019 15:08:48 -0400 Subject: [PATCH] all struct references are shared_ptrs --- src/daemon/MoneroDaemon.cpp | 2 +- src/daemon/MoneroDaemon.h | 2 +- src/wallet/MoneroWallet.cpp | 230 +++++++++++++++++++++++++++++++----- src/wallet/MoneroWallet.h | 16 +-- 4 files changed, 214 insertions(+), 36 deletions(-) diff --git a/src/daemon/MoneroDaemon.cpp b/src/daemon/MoneroDaemon.cpp index af2d8f6..ba5affd 100644 --- a/src/daemon/MoneroDaemon.cpp +++ b/src/daemon/MoneroDaemon.cpp @@ -47,7 +47,7 @@ namespace monero { //cout << "MoneroBlock::toPropertyTree(block)" << endl; boost::property_tree::ptree node = MoneroBlockHeader::toPropertyTree(); if (hex != boost::none) node.put("hex", *hex); - if (coinbaseTx != boost::none) node.add_child("coinbaseTx", coinbaseTx->toPropertyTree()); + if (coinbaseTx != boost::none) node.add_child("coinbaseTx", (*coinbaseTx)->toPropertyTree()); node.add_child("txs", MoneroUtils::toPropertyTree(txs)); // TODO: handle txIds return node; diff --git a/src/daemon/MoneroDaemon.h b/src/daemon/MoneroDaemon.h index faaefd9..42200cd 100644 --- a/src/daemon/MoneroDaemon.h +++ b/src/daemon/MoneroDaemon.h @@ -136,7 +136,7 @@ namespace monero { */ struct MoneroBlock : public MoneroBlockHeader { boost::optional hex; - boost::optional coinbaseTx; + boost::optional> coinbaseTx; vector> txs; vector txIds; diff --git a/src/wallet/MoneroWallet.cpp b/src/wallet/MoneroWallet.cpp index 85771b5..ae86649 100644 --- a/src/wallet/MoneroWallet.cpp +++ b/src/wallet/MoneroWallet.cpp @@ -119,10 +119,66 @@ namespace monero { // ----------------------- UNDECLARED PRIVATE HELPERS ----------------------- + // TODO: static? bool boolEquals(bool val, const boost::optional& optVal) { return optVal == boost::none ? false : val == *optVal; } +// MoneroTxWallet convertTxWithIncomingTransfer(const tools::wallet2& wallet2, const crypto::hash &txid, const crypto::hash &payment_id, const tools::wallet2::payment_details &pd) { +// +// //cout << "static convertTxWithIncomingTransfer(3)" << endl; +// shared_ptr block = shared_ptr(new MoneroBlock()); +// block->height = pd.m_block_height; +// block->timestamp = pd.m_timestamp; +// block->txs.push_back(tx); +// +// //shared_ptr tx = nullptr; +// tx.block = block +// tx.id = string_tools::pod_to_hex(pd.m_tx_hash); +// tx.paymentId = string_tools::pod_to_hex(payment_id); +// if (tx.paymentId->substr(16).find_first_not_of('0') == std::string::npos) tx.paymentId = tx.paymentId->substr(0, 16); // TODO monero core: this should be part of core wallet +// if (tx.paymentId == MoneroTx::DEFAULT_PAYMENT_ID) tx.paymentId = boost::none; // clear default payment id +// tx.unlockTime = pd.m_unlock_time; +// tx.fee = pd.m_fee; +// tx.note = wallet2.get_tx_note(pd.m_tx_hash); +// if (tx.note->empty()) tx.note = boost::none; // clear empty note +// tx.isCoinbase = pd.m_coinbase ? true : false; +// tx.isConfirmed = true; +// tx.isFailed = false; +// tx.isRelayed = true; +// tx.inTxPool = false; +// tx.doNotRelay = false; +// tx.isDoubleSpend = false; +// +// // compute numConfirmations TODO monero core: this logic is based on wallet_rpc_server.cpp:87 but it should be encapsulated in wallet2 +// uint64_t chainHeight = getChainHeight(); +// if (*block->height >= chainHeight || (*block->height == 0 && !tx.inTxPool)) tx.numConfirmations = 0; +// else tx.numConfirmations = chainHeight - *block->height; +// +// // construct transfer +// MoneroIncomingTransfer incomingTransfer; +// incomingTransfer.tx = shared_ptr(tx); +// incomingTransfer.amount = pd.m_amount; +// incomingTransfer.accountIndex = pd.m_subaddr_index.major; +// incomingTransfer.subaddressIndex = pd.m_subaddr_index.minor; +// incomingTransfer.address = wallet2->get_subaddress_as_str(pd.m_subaddr_index); +// +// // compute numSuggestedConfirmations TODO monero core: this logic is based on wallet_rpc_server.cpp:87 but it should be encapsulated in wallet2 +// uint64_t blockReward = wallet2->get_last_block_reward(); +// if (blockReward == 0) incomingTransfer.numSuggestedConfirmations = 0; +// else incomingTransfer.numSuggestedConfirmations = (*incomingTransfer.amount + blockReward - 1) / blockReward; +// +// // add transfer to tx +// tx.incomingTransfers.push_back(incomingTransfer); +// +// return incomingTransfer; +// } + + void mergeTx(vector> txs, const shared_ptr& tx) { + cout << "mergeTx()" << endl; + throw runtime_error("Not implemented"); + } + // ----------------------------- WALLET LISTENER ---------------------------- /** @@ -533,11 +589,11 @@ namespace monero { throw runtime_error("getTxs() not implemented"); } - vector MoneroWallet::getTransfers(const MoneroTransferRequest& request) const { - cout << "getTransfers(request)" << endl; + vector> MoneroWallet::getTransfers(const MoneroTransferRequest& request) const { + cout << "vector> getTransfers(request)" << endl; // normalize request - MoneroTxRequest txReq = *(request.txRequest != boost::none ? *request.txRequest : shared_ptr(make_shared(MoneroTxRequest()))); + MoneroTxRequest txReq = *(request.txRequest != boost::none ? *request.txRequest : shared_ptr(new MoneroTxRequest())); //MoneroTxRequest txReq = MoneroTxRequest(); //if (request.txRequest != boost::none) txReq = **request.txRequest; @@ -552,10 +608,7 @@ namespace monero { subaddressIndices.insert(request.subaddressIndices[i]); } - // TODO: txReq does not have field height because block has height; used accessor in Java - // TODO: transferReq does not have field isOutgoing because isIncoming is sufficient , but then need bool logic on isOutgoing - - // translate from MoneroTxRequest to in, out, pending, pool, failed terminology + // translate from MoneroTxRequest to in, out, pending, pool, failed terminology used by monero-wallet-rpc bool canBeConfirmed = !boolEquals(false, txReq.isConfirmed) && !boolEquals(true, txReq.inTxPool) && !boolEquals(true, txReq.isFailed) && !boolEquals(false, txReq.isRelayed); bool canBeInTxPool = !boolEquals(true, txReq.isConfirmed) && !boolEquals(false, txReq.inTxPool) && !boolEquals(true, txReq.isFailed) && !boolEquals(false, txReq.isRelayed) && txReq.getHeight() == boost::none && txReq.minHeight == boost::none; bool canBeIncoming = !boolEquals(false, request.isIncoming) && !boolEquals(true, request.getIsOutgoing()) && !boolEquals(true, request.hasDestinations); @@ -566,18 +619,17 @@ namespace monero { bool isPool = canBeIncoming && canBeInTxPool; bool isFailed = !boolEquals(false, txReq.isFailed) && !boolEquals(true, txReq.isConfirmed) && !boolEquals(true, txReq.inTxPool); - // TODO: this duplicates common transfer txs - // collect transfers - vector transfers; + // collect unique transactions + vector> txs; // get confirmed incoming transfers if (isIn) { std::list> payments; wallet2->get_payments(payments, minHeight, maxHeight, accountIndex, subaddressIndices); for (std::list>::const_iterator i = payments.begin(); i != payments.end(); ++i) { - MoneroTransfer transfer = wallet2ToIncomingTransfer(i->second.m_tx_hash, i->first, i->second); - transfers.push_back(transfer); + shared_ptr tx = buildTxWithIncomingTransfer(i->second.m_tx_hash, i->first, i->second); + mergeTx(txs, tx); } } @@ -598,9 +650,84 @@ namespace monero { // TODO: apply filtering + // collect resulting transfers + vector> transfers; + for (int i = 0; i < txs.size(); i++) { + shared_ptr tx = txs[i]; + for (int j = 0; j < tx->incomingTransfers.size(); j++) { + transfers.push_back(tx->incomingTransfers[j]); + } + if (tx->outgoingTransfer != boost::none) transfers.push_back(*tx->outgoingTransfer); + } + return transfers; } +// vector MoneroWallet::getTransfers(const MoneroTransferRequest& request) const { +// cout << "getTransfers(request)" << endl; +// +// // normalize request +// MoneroTxRequest txReq = *(request.txRequest != boost::none ? *request.txRequest : shared_ptr(make_shared(MoneroTxRequest()))); +// +// //MoneroTxRequest txReq = MoneroTxRequest(); +// //if (request.txRequest != boost::none) txReq = **request.txRequest; +// +// // build parameters for wallet2->get_payments() +// uint64_t minHeight = txReq.minHeight == boost::none ? 0 : *txReq.minHeight; +// uint64_t maxHeight = txReq.maxHeight == boost::none ? CRYPTONOTE_MAX_BLOCK_NUMBER : min((uint64_t) CRYPTONOTE_MAX_BLOCK_NUMBER, *txReq.maxHeight); +// boost::optional accountIndex = boost::none; +// if (request.accountIndex != boost::none) accountIndex = *request.accountIndex; +// std::set subaddressIndices; +// for (int i = 0; i < request.subaddressIndices.size(); i++) { +// subaddressIndices.insert(request.subaddressIndices[i]); +// } +// +// // translate from MoneroTxRequest to in, out, pending, pool, failed terminology used by monero-wallet-rpc +// bool canBeConfirmed = !boolEquals(false, txReq.isConfirmed) && !boolEquals(true, txReq.inTxPool) && !boolEquals(true, txReq.isFailed) && !boolEquals(false, txReq.isRelayed); +// bool canBeInTxPool = !boolEquals(true, txReq.isConfirmed) && !boolEquals(false, txReq.inTxPool) && !boolEquals(true, txReq.isFailed) && !boolEquals(false, txReq.isRelayed) && txReq.getHeight() == boost::none && txReq.minHeight == boost::none; +// bool canBeIncoming = !boolEquals(false, request.isIncoming) && !boolEquals(true, request.getIsOutgoing()) && !boolEquals(true, request.hasDestinations); +// bool canBeOutgoing = !boolEquals(false, request.getIsOutgoing()) && !boolEquals(true, request.isIncoming); +// bool isIn = canBeIncoming && canBeConfirmed; +// bool isOut = canBeOutgoing && canBeConfirmed; +// bool isPending = canBeOutgoing && canBeInTxPool; +// bool isPool = canBeIncoming && canBeInTxPool; +// bool isFailed = !boolEquals(false, txReq.isFailed) && !boolEquals(true, txReq.isConfirmed) && !boolEquals(true, txReq.inTxPool); +// +// // TODO: this duplicates common transfer txs +// +// // collect transfers +// vector transfers; +// +// // get confirmed incoming transfers +// if (isIn) { +// std::list> payments; +// wallet2->get_payments(payments, minHeight, maxHeight, accountIndex, subaddressIndices); +// for (std::list>::const_iterator i = payments.begin(); i != payments.end(); ++i) { +//// MoneroTransfer transfer = convertWallet2IncomingTransfer(i->second.m_tx_hash, i->first, i->second); +//// transfers.push_back(transfer); +// } +// } +// +// // get confirmed outgoing transfers +// if (isOut) { +// //throw runtime_error("isOut not implemented"); +// } +// +// // get unconfirmed outgoing transfers +// if (isPending || isFailed) { +// //throw runtime_error("isPending || isFailed not implemented"); +// } +// +// // get unconfirmed incoming transfers +// if (isPool) { +// //throw runtime_error("isPool not implemented"); +// } +// +// // TODO: apply filtering +// +// return transfers; +// } + vector MoneroWallet::getOutputs(const MoneroOutputRequest& request) const { cout << "getOutputs(request)" << endl; throw runtime_error("Not implemented"); @@ -682,13 +809,13 @@ namespace monero { return subaddresses; } - MoneroTransfer MoneroWallet::wallet2ToIncomingTransfer(const crypto::hash &txid, const crypto::hash &payment_id, const tools::wallet2::payment_details &pd) const { - //cout << "wallet2ToIncomingTransfer(3)" << endl; + shared_ptr MoneroWallet::buildTxWithIncomingTransfer(const crypto::hash &txid, const crypto::hash &payment_id, const tools::wallet2::payment_details &pd) const { + cout << "buildTxWithIncomingTransfer()" << endl; + shared_ptr block = shared_ptr(new MoneroBlock()); block->height = pd.m_block_height; block->timestamp = pd.m_timestamp; - //shared_ptr tx = nullptr; shared_ptr tx = shared_ptr(new MoneroTxWallet()); tx->block = block; block->txs.push_back(tx); @@ -714,21 +841,70 @@ namespace monero { else tx->numConfirmations = chainHeight - *block->height; // construct transfer - MoneroIncomingTransfer incomingTransfer; - incomingTransfer.tx = tx; - incomingTransfer.amount = pd.m_amount; - incomingTransfer.accountIndex = pd.m_subaddr_index.major; - incomingTransfer.subaddressIndex = pd.m_subaddr_index.minor; - incomingTransfer.address = wallet2->get_subaddress_as_str(pd.m_subaddr_index); + shared_ptr incomingTransfer = shared_ptr(new MoneroIncomingTransfer()); + incomingTransfer->tx = tx; + tx->incomingTransfers.push_back(incomingTransfer); + incomingTransfer->amount = pd.m_amount; + incomingTransfer->accountIndex = pd.m_subaddr_index.major; + incomingTransfer->subaddressIndex = pd.m_subaddr_index.minor; + incomingTransfer->address = wallet2->get_subaddress_as_str(pd.m_subaddr_index); // compute numSuggestedConfirmations TODO monero core: this logic is based on wallet_rpc_server.cpp:87 but it should be encapsulated in wallet2 uint64_t blockReward = wallet2->get_last_block_reward(); - if (blockReward == 0) incomingTransfer.numSuggestedConfirmations = 0; - else incomingTransfer.numSuggestedConfirmations = (*incomingTransfer.amount + blockReward - 1) / blockReward; + if (blockReward == 0) incomingTransfer->numSuggestedConfirmations = 0; + else incomingTransfer->numSuggestedConfirmations = (*incomingTransfer->amount + blockReward - 1) / blockReward; - // add transfer to tx - tx->incomingTransfers.push_back(incomingTransfer); - - return incomingTransfer; + // return pointer to new tx + return tx; } + +// MoneroTransfer MoneroWallet::convertWallet2IncomingTransfer(const tools::wallet2& wallet2, const crypto::hash &txid, const crypto::hash &payment_id, const tools::wallet2::payment_details &pd) const { +// //cout << "convertWallet2IncomingTransfer(3)" << endl; +// shared_ptr block = shared_ptr(new MoneroBlock()); +// block->height = pd.m_block_height; +// block->timestamp = pd.m_timestamp; +// +// //shared_ptr tx = nullptr; +// shared_ptr tx = shared_ptr(new MoneroTxWallet()); +// tx->block = block; +// block->txs.push_back(tx); +// tx->id = string_tools::pod_to_hex(pd.m_tx_hash); +// tx->paymentId = string_tools::pod_to_hex(payment_id); +// if (tx->paymentId->substr(16).find_first_not_of('0') == std::string::npos) tx->paymentId = tx->paymentId->substr(0, 16); // TODO monero core: this should be part of core wallet +// if (tx->paymentId == MoneroTx::DEFAULT_PAYMENT_ID) tx->paymentId = boost::none; // clear default payment id +// tx->unlockTime = pd.m_unlock_time; +// tx->fee = pd.m_fee; +// tx->note = wallet2->get_tx_note(pd.m_tx_hash); +// if (tx->note->empty()) tx->note = boost::none; // clear empty note +// tx->isCoinbase = pd.m_coinbase ? true : false; +// tx->isConfirmed = true; +// tx->isFailed = false; +// tx->isRelayed = true; +// tx->inTxPool = false; +// tx->doNotRelay = false; +// tx->isDoubleSpend = false; +// +// // compute numConfirmations TODO monero core: this logic is based on wallet_rpc_server.cpp:87 but it should be encapsulated in wallet2 +// uint64_t chainHeight = getChainHeight(); +// if (*block->height >= chainHeight || (*block->height == 0 && !tx->inTxPool)) tx->numConfirmations = 0; +// else tx->numConfirmations = chainHeight - *block->height; +// +// // construct transfer +// MoneroIncomingTransfer incomingTransfer; +// incomingTransfer.tx = tx; +// incomingTransfer.amount = pd.m_amount; +// incomingTransfer.accountIndex = pd.m_subaddr_index.major; +// incomingTransfer.subaddressIndex = pd.m_subaddr_index.minor; +// incomingTransfer.address = wallet2->get_subaddress_as_str(pd.m_subaddr_index); +// +// // compute numSuggestedConfirmations TODO monero core: this logic is based on wallet_rpc_server.cpp:87 but it should be encapsulated in wallet2 +// uint64_t blockReward = wallet2->get_last_block_reward(); +// if (blockReward == 0) incomingTransfer.numSuggestedConfirmations = 0; +// else incomingTransfer.numSuggestedConfirmations = (*incomingTransfer.amount + blockReward - 1) / blockReward; +// +// // add transfer to tx +// tx->incomingTransfers.push_back(incomingTransfer); +// +// return incomingTransfer; +// } } diff --git a/src/wallet/MoneroWallet.h b/src/wallet/MoneroWallet.h index 792d974..09c9768 100644 --- a/src/wallet/MoneroWallet.h +++ b/src/wallet/MoneroWallet.h @@ -119,7 +119,7 @@ namespace monero { struct MoneroOutgoingTransfer : public MoneroTransfer { vector subaddressIndices; vector addresses; - vector destinations; + vector> destinations; boost::property_tree::ptree toPropertyTree() const; }; @@ -139,8 +139,8 @@ namespace monero { * Models a Monero transaction in the context of a wallet. */ struct MoneroTxWallet : public MoneroTx { - vector incomingTransfers; - boost::optional outgoingTransfer; + vector> incomingTransfers; + boost::optional> outgoingTransfer; boost::optional note; boost::property_tree::ptree toPropertyTree() const; @@ -157,7 +157,7 @@ namespace monero { vector addresses; boost::optional subaddressIndex; vector subaddressIndices; - vector destinations; + vector> destinations; boost::optional hasDestinations; boost::optional> txRequest; @@ -181,7 +181,7 @@ namespace monero { boost::optional minHeight; boost::optional maxHeight; boost::optional includeOutputs; - boost::optional transferRequest; + boost::optional> transferRequest; boost::optional getHeight() { return block == boost::none ? boost::none : (*block)->height; } boost::property_tree::ptree toPropertyTree() const; @@ -744,7 +744,9 @@ namespace monero { * @param request filters query results (optional) * @return wallet transfers per the request */ - vector getTransfers(const MoneroTransferRequest& request) const; + vector> getTransfers(const MoneroTransferRequest& request) const; + +// void getTransfers(const MoneroTransferRequest& request, vector& transfers) const; // /** // * Get outputs created from previous transactions that belong to the wallet @@ -1266,7 +1268,7 @@ namespace monero { MoneroSyncResult syncAux(boost::optional startHeight, boost::optional endHeight, boost::optional listener); vector getSubaddressesAux(uint32_t accountIdx, vector subaddressIndices, vector transfers) const; - MoneroTransfer wallet2ToIncomingTransfer(const crypto::hash &txid, const crypto::hash &payment_id, const tools::wallet2::payment_details &pd) const; + shared_ptr buildTxWithIncomingTransfer(const crypto::hash &txid, const crypto::hash &payment_id, const tools::wallet2::payment_details &pd) const; }; }