diff --git a/src/wallet/MoneroWallet.cpp b/src/wallet/MoneroWallet.cpp index 0bf79b7..ea97980 100644 --- a/src/wallet/MoneroWallet.cpp +++ b/src/wallet/MoneroWallet.cpp @@ -588,13 +588,17 @@ namespace monero { for (std::list>::const_iterator i = payments.begin(); i != payments.end(); ++i) { shared_ptr tx = buildTxWithIncomingTransfer(i->second.m_tx_hash, i->first, i->second); mergeTx(tx, txMap, blockMap, false); - //txs.push_back(tx); } } // get confirmed outgoing transfers if (isOut) { - //throw runtime_error("isOut not implemented"); + std::list> payments; + wallet2->get_payments_out(payments, minHeight, maxHeight, accountIndex, subaddressIndices); + for (std::list>::const_iterator i = payments.begin(); i != payments.end(); ++i) { + shared_ptr tx = buildTxWithOutgoingTransfer(i->first, i->second); + mergeTx(tx, txMap, blockMap, false); + } } // get unconfirmed outgoing transfers @@ -630,71 +634,6 @@ namespace monero { 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"); @@ -827,53 +766,77 @@ namespace monero { 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; -// } + //void wallet_rpc_server::fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &txid, const crypto::hash &payment_id, const tools::wallet2::payment_details &pd) + + //void wallet_rpc_server::fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &txid, const tools::wallet2::confirmed_transfer_details &pd) + + //void wallet_rpc_server::fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &txid, const tools::wallet2::unconfirmed_transfer_details &pd) + + //void wallet_rpc_server::fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &payment_id, const tools::wallet2::pool_payment_details &ppd) + + shared_ptr MoneroWallet::buildTxWithOutgoingTransfer(const crypto::hash &txid, const tools::wallet2::confirmed_transfer_details &pd) const { + //cout << "buildTxWithOutgoingTransfer()" << endl; + + // construct block + shared_ptr block = shared_ptr(new MoneroBlock()); + block->height = pd.m_block_height; + block->timestamp = pd.m_timestamp; + + // construct tx + shared_ptr tx = shared_ptr(new MoneroTxWallet()); + tx->block = block; + block->txs.push_back(tx); + tx->id = string_tools::pod_to_hex(txid); + tx->paymentId = string_tools::pod_to_hex(pd.m_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_amount_in - pd.m_amount_out; + tx->note = wallet2->get_tx_note(txid); + if (tx->note->empty()) tx->note = boost::none; // clear empty note + tx->isCoinbase = 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 + shared_ptr outgoingTransfer = shared_ptr(new MoneroOutgoingTransfer()); + outgoingTransfer->tx = tx; + tx->outgoingTransfer = outgoingTransfer; + uint64_t change = pd.m_change == (uint64_t)-1 ? 0 : pd.m_change; // change may not be known + outgoingTransfer->amount = pd.m_amount_in - change - *tx->fee; + outgoingTransfer->accountIndex = pd.m_subaddr_account; + vector subaddressIndices; + vector addresses; + for (uint32_t i: pd.m_subaddr_indices) { + subaddressIndices.push_back(i); + addresses.push_back(wallet2->get_subaddress_as_str({pd.m_subaddr_account, i})); + } + outgoingTransfer->subaddressIndices = subaddressIndices; + outgoingTransfer->addresses = addresses; + + // initialize destinations + for (const auto &d: pd.m_dests) { + shared_ptr destination = shared_ptr(new MoneroDestination()); + destination->amount = d.amount; + destination->address = d.original.empty() ? cryptonote::get_account_address_as_str(wallet2->nettype(), d.is_subaddress, d.addr) : d.original; + outgoingTransfer->destinations.push_back(destination); + } + + // 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) outgoingTransfer->numSuggestedConfirmations = 0; + else outgoingTransfer->numSuggestedConfirmations = (*outgoingTransfer->amount + blockReward - 1) / blockReward; + + // return pointer to new tx + return tx; + } } diff --git a/src/wallet/MoneroWallet.h b/src/wallet/MoneroWallet.h index 37dd219..e9587b8 100644 --- a/src/wallet/MoneroWallet.h +++ b/src/wallet/MoneroWallet.h @@ -1085,6 +1085,7 @@ namespace monero { MoneroSyncResult syncAux(boost::optional startHeight, boost::optional endHeight, boost::optional listener); vector getSubaddressesAux(uint32_t accountIdx, vector subaddressIndices, vector transfers) const; - shared_ptr buildTxWithIncomingTransfer(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; // TODO: these could be made inner anonymous by moving to top of .cpp + shared_ptr buildTxWithOutgoingTransfer(const crypto::hash &txid, const tools::wallet2::confirmed_transfer_details &pd) const; }; } diff --git a/src/wallet/MoneroWalletModel.cpp b/src/wallet/MoneroWalletModel.cpp index 147512a..20f1e23 100644 --- a/src/wallet/MoneroWalletModel.cpp +++ b/src/wallet/MoneroWalletModel.cpp @@ -57,7 +57,7 @@ namespace monero { boost::property_tree::ptree node = MoneroTx::toPropertyTree(); if (!vouts.empty()) throw runtime_error("vouts not implemented"); if (!incomingTransfers.empty()) node.add_child("incomingTransfers", MoneroUtils::toPropertyTree(incomingTransfers)); - if (outgoingTransfer != boost::none) throw runtime_error("outgoingTransfers not implemented"); + if (outgoingTransfer != boost::none) node.add_child("outgoingTransfer", (*outgoingTransfer)->toPropertyTree()); if (note != boost::none) node.put("note", *note); return node; } @@ -109,6 +109,7 @@ namespace monero { if (subaddressIndex != boost::none) node.put("subaddressIndex", *subaddressIndex); if (hasDestinations != boost::none) node.put("hasDestinations", *hasDestinations); if (txRequest != boost::none) node.add_child("txRequest", (*txRequest)->toPropertyTree()); + if (!destinations.empty()) node.add_child("destinations", MoneroUtils::toPropertyTree(destinations)); // TODO: if (!addresses.empty()) node.add_child("addresses", MoneroUtils::toPropertyTree(subaddresses)); @@ -130,14 +131,6 @@ namespace monero { } node.add_child("subaddressIndices", subaddressIndicesNode); - // convert destinations - boost::property_tree::ptree destinationsNode; - for (const shared_ptr& destination : destinations) { - boost::property_tree::ptree destinationNode; - destinationNode.add_child("", destination->toPropertyTree()); - destinationsNode.push_back(std::make_pair("", destinationNode)); - } - node.add_child("destinations", destinationsNode); return node; } diff --git a/todo.txt b/todo.txt index 99d90df..9af156b 100644 --- a/todo.txt +++ b/todo.txt @@ -1,5 +1,4 @@ -separate model interfaces/impl - DaemonConnection is its own object rename external-libs/monero to monero-core for clarity -onSyncProgress(startHeight, currentHeight, endHeight, percentDone, message)? \ No newline at end of file +onSyncProgress(startHeight, currentHeight, endHeight, percentDone, message)? +optimize by moving shared_ptrs \ No newline at end of file