diff --git a/src/daemon/MoneroDaemonModel.cpp b/src/daemon/MoneroDaemonModel.cpp index 5c42e74..7122578 100644 --- a/src/daemon/MoneroDaemonModel.cpp +++ b/src/daemon/MoneroDaemonModel.cpp @@ -61,6 +61,23 @@ */ namespace monero { + // ----------------------- UNDECLARED PRIVATE HELPERS ----------------------- + + void mergeTx(vector> txs, const shared_ptr& tx) { + cout << "Merging this other guy in: " << tx << endl; + for (const shared_ptr& aTx : txs) { + cout << "Comparaing against self tx: " << aTx << endl; + if (aTx->id.get() == tx->id.get()) { + cout << "And we're merging..." << endl; + cout << aTx << endl; + cout << tx << endl; + aTx->merge(aTx, tx); + return; + } + } + txs.push_back(tx); + } + // ------------------------- INITIALIZE CONSTANTS --------------------------- const string MoneroTx::DEFAULT_PAYMENT_ID = string("0000000000000000"); @@ -133,44 +150,86 @@ namespace monero { } void MoneroBlock::merge(const shared_ptr& self, const shared_ptr& other) { + cout << "CALLING MONERO BLOCK BASE MERGE" << endl; merge(static_pointer_cast(self), static_pointer_cast(other)); } void MoneroBlock::merge(const shared_ptr& self, const shared_ptr& other) { + cout << "MoneroBlock::merge()" << endl; + cout << self << ", " << other << endl; if (this != self.get()) throw runtime_error("this != self"); if (self == other) return; + cout << "1" << endl; - // merge header fields + cout << "Lets iterate over self block tx pointers" << endl; + for (const shared_ptr& tx : self->txs) { + cout << tx << endl; + } + + cout << "Lets iterate over other block tx pointers" << endl; + for (const shared_ptr& tx : other->txs) { + cout << tx << endl; + } + + // merge base classes MoneroBlockHeader::merge(self, other); + // merge reconcilable block extensions + hex = MoneroUtils::reconcile(hex, other->hex); + txIds = MoneroUtils::reconcile(txIds, other->txIds); + + cout << "2" << endl; + // merge coinbase tx if (coinbaseTx == boost::none) coinbaseTx = other->coinbaseTx; else if (other->coinbaseTx != boost::none) coinbaseTx.get()->merge(*coinbaseTx, *other->coinbaseTx); + cout << "3" << endl; + + // merge non-coinbase txs - if (txs.empty()) txs = other->txs; - else if (!other->txs.empty()) { - for (const shared_ptr& thatTx : other->txs) { - bool found = false; - for (const shared_ptr& thisTx : txs) { - if (thatTx->id == thisTx->id) { - thisTx->merge(thisTx, thatTx); - found = true; - break; - } - } - if (!found) txs.push_back(thatTx); - } - } - if (!txs.empty()) { - for (const shared_ptr& tx : txs) { - tx->block = self; + if (!other->txs.empty()) { + cout << "4" << endl; + for (const shared_ptr otherTx : other->txs) { // NOTE: not using reference so shared_ptr is not deleted when block is dereferenced + cout << "5" << endl; + cout << "Merging into existing txs: " << otherTx << endl; + otherTx->block = self; + cout << "Merging into existing txs: " << otherTx << endl; + mergeTx(self->txs, otherTx); } } - // merge other fields - hex = MoneroUtils::reconcile(hex, other->hex); - txIds = MoneroUtils::reconcile(txIds, other->txIds); +// // merge non-coinbase txs +// if (txs.empty()) { +// txs = other->txs; +// cout << "4" << endl; +// } +// else if (!other->txs.empty()) { +// cout << "5" << endl; +// for (const shared_ptr& thatTx : other->txs) { +// bool found = false; +// for (const shared_ptr& thisTx : txs) { +// cout << "6" << endl; +// if (thatTx->id == thisTx->id) { +// cout << "7" << endl; +// thatTx->block = self; +// cout << "And here we go for merging txs" << endl; +// thisTx->merge(thisTx, thatTx); +// found = true; +// break; +// } +// } +// if (!found) txs.push_back(thatTx); +// } +// } +// cout << "4.2" << endl; +// if (!txs.empty()) { +// for (const shared_ptr& tx : txs) { +// tx->block = self; +// } +// } + + cout << "Returning from MoneroBlock merge" << endl; } // ------------------------------- MONERO TX -------------------------------- @@ -224,8 +283,40 @@ namespace monero { } void MoneroTx::merge(const shared_ptr& self, const shared_ptr& other) { + cout << "MoneroTx::merge()" << endl; if (this != self.get()) throw runtime_error("this != self"); + cout << self << ", " << other << endl; + cout << "1" << endl; if (self == other) return; + cout << "2" << endl; + + // merge blocks if they're different which comes back to merging txs + if (block != other->block) { + cout << "4" << endl; + if (block == boost::none) { + cout << "5" << endl; + block = shared_ptr(new MoneroBlock()); + block.get()->txs.push_back(self); + block.get()->height = other->getHeight(); + } + if (other->block == boost::none) { + cout << "About to access other->block" << endl; + cout << other->block << endl; + cout << "6" << endl; + other->block = shared_ptr(new MoneroBlock()); + cout << "7" << endl; + other->block.get()->txs.push_back(other); + cout << "8" << endl; + other->block.get()->height = self->getHeight(); + cout << "9" << endl; + } + cout << "Merging blocks!" << endl; + block.get()->merge(block.get(), other->block.get()); + return; + } + cout << "merging tx fields!!!" << endl; + + // otherwise merge tx fields id = MoneroUtils::reconcile(id, other->id); version = MoneroUtils::reconcile(version, other->version); paymentId = MoneroUtils::reconcile(paymentId, other->paymentId); @@ -258,9 +349,11 @@ namespace monero { unlockTime = MoneroUtils::reconcile(unlockTime, other->unlockTime); numConfirmations = MoneroUtils::reconcile(numConfirmations, other->numConfirmations); + cout << "Merging vins!" << endl; + // merge vins if (!other->vins.empty()) { - for (const shared_ptr& merger : other->vins) { + for (shared_ptr merger : other->vins) { bool merged = false; merger->tx = self; for (const shared_ptr& mergee : vins) { @@ -274,9 +367,11 @@ namespace monero { } } + cout << "Merging vouts!" << endl; + // merge vouts if (!other->vouts.empty()) { - for (const shared_ptr& vout : other->vouts) vout->tx = self; + for (shared_ptr vout : other->vouts) vout->tx = self; if (vouts.empty()) vouts = other->vouts; else { @@ -298,8 +393,9 @@ namespace monero { // merge by key images if (numKeyImages > 0) { - for (const shared_ptr& merger : other->vouts) { + for (shared_ptr merger : other->vouts) { bool merged = false; + merger->tx = self; // TODO: this update needs made in Java and JS for (const shared_ptr& mergee : vouts) { if ((*mergee->keyImage)->hex == (*merger->keyImage)->hex) { mergee->merge(mergee, merger); @@ -331,6 +427,8 @@ namespace monero { receivedTimestamp = MoneroUtils::reconcile(receivedTimestamp, other->receivedTimestamp, boost::none, boost::none, false); // take earliest receive time lastRelayedTimestamp = MoneroUtils::reconcile(lastRelayedTimestamp, other->lastRelayedTimestamp, boost::none, boost::none, true); // take latest relay time } + + cout << "Returning from MoneroTx::merge()" << endl; } // --------------------------- MONERO KEY IMAGE ----------------------------- diff --git a/src/wallet/MoneroWallet.cpp b/src/wallet/MoneroWallet.cpp index d4e1120..3795a6c 100644 --- a/src/wallet/MoneroWallet.cpp +++ b/src/wallet/MoneroWallet.cpp @@ -340,6 +340,50 @@ namespace monero { return tx; } + /** + * Merges a transaction into a unique set of transactions. + * + * TODO monero-core: skipIfAbsent only necessary because incoming payments not returned + * when sent from/to same account #4500 + * + * @param tx is the transaction to merge into the existing txs + * @param txMap maps tx ids to txs + * @param skipIfAbsent specifies if the tx should not be added if it doesn't already exist + */ + void mergeTx(shared_ptr tx, map>& txMap, bool skipIfAbsent) { + + if (tx->block != boost::none) { + bool found = false; + for (const shared_ptr& blockTx : tx->block.get()->txs) { + if (tx == blockTx) { + found = true; + break; + } + } + if (!found) throw new runtime_error("But this tx's block does not reference the tx"); + } + + if (tx->id == boost::none) throw runtime_error("Tx id is not initialized"); + + // if tx doesn't exist, add it (unless skipped) + map>::const_iterator txIter = txMap.find(*tx->id); + if (txIter == txMap.end()) { + if (!skipIfAbsent) { + txMap[*tx->id] = tx; + } else { + cout << "WARNING: tx does not already exist" << endl; // TODO: proper logging + } + } + + // otherwise merge with existing tx + else { + shared_ptr& aTx = txMap[*tx->id]; + aTx->merge(aTx, tx); + } + + cout << "Now how back is the tx map? " << txMap.size() << endl; + } + /** * ---------------- DUPLICATED WALLET RPC TRANSFER CODE --------------------- * @@ -557,71 +601,6 @@ namespace monero { } return true; } - // -------------------- END DUPLICATED WALLET RPC CODE --------------------- - - /** - * Merges a transaction into a unique set of transactions. - * - * TODO monero-core: skipIfAbsent only necessary because incoming payments not returned - * when sent from/to same account #4500 - * - * @param tx is the transaction to merge into the existing txs - * @param txMap maps tx ids to txs - * @param blockMap maps block heights to blocks - * @param skipIfAbsent specifies if the tx should not be added if it doesn't already exist - */ - void mergeTx(const shared_ptr& tx, map>& txMap, map>& blockMap, bool skipIfAbsent) { - if (tx->id == boost::none) throw runtime_error("Tx id is not initialized"); - -// txMap[*tx->id] = tx; -// if (true) return; - - // if tx doesn't exist, add it (unless skipped) - map>::const_iterator txIter = txMap.find(*tx->id); - if (txIter == txMap.end()) { - if (!skipIfAbsent) { - txMap[*tx->id] = tx; - } else { - cout << "WARNING: tx does not already exist" << endl; // TODO: proper logging - } - } - - // otherwise merge with existing tx - else { - - // get existing tx to merge with - shared_ptr& aTx = txMap[*tx->id]; - - // merge blocks if confirmed, txs otherwise - // TODO: follow transfer->tx merging pattern which merges txs which comes back to transfers - if (aTx->block != boost::none || tx->block != boost::none) { - if (aTx->block == boost::none) { - aTx->block = shared_ptr(new MoneroBlock()); - aTx->block.get()->txs.push_back(tx); - aTx->block.get()->height = tx->getHeight(); - } - if (tx->block == boost::none) { - tx->block = shared_ptr(new MoneroBlock()); - tx->block.get()->txs.push_back(tx); - tx->block.get()->height = aTx->getHeight(); - } - aTx->block.get()->merge(aTx->block.get(), tx->block.get()); - } else { - aTx->merge(aTx, tx); - } - } - - // if confirmed, merge tx's block - if (tx->getHeight() != boost::none) { - map>::const_iterator blockIter = blockMap.find(tx->getHeight().get()); - if (blockIter == blockMap.end()) { - blockMap[tx->getHeight().get()] = tx->block.get(); - } else { - shared_ptr& aBlock = blockMap[tx->getHeight().get()]; - aBlock->merge(aBlock, tx->block.get()); - } - } - } // ----------------------------- WALLET LISTENER ---------------------------- @@ -1213,9 +1192,8 @@ namespace monero { // cache types into maps for merging and lookup map> txMap; - map> blockMap; for (const shared_ptr& tx : txs) { - mergeTx(tx, txMap, blockMap, false); + mergeTx(tx, txMap, false); } // fetch and merge outputs if requested @@ -1231,7 +1209,7 @@ namespace monero { for (const shared_ptr& output : outputs) { shared_ptr tx = static_pointer_cast(output->tx); if (outputTxs.find(tx) == outputTxs.end()) { - mergeTx(tx, txMap, blockMap, true); + mergeTx(tx, txMap, true); outputTxs.insert(tx); } } @@ -1329,10 +1307,9 @@ namespace monero { //cout << "4" << endl; - // collect unique txs and blocks + // collect unique txs uint64_t chainHeight = getChainHeight(); map> txMap; - map> blockMap; // get confirmed incoming transfers if (isIn) { @@ -1340,7 +1317,7 @@ namespace monero { wallet2->get_payments(payments, minHeight, maxHeight, accountIndex, subaddressIndices); for (std::list>::const_iterator i = payments.begin(); i != payments.end(); ++i) { shared_ptr tx = buildTxWithIncomingTransfer(*wallet2, chainHeight, i->first, i->second); - mergeTx(tx, txMap, blockMap, false); + mergeTx(tx, txMap, false); } } @@ -1352,7 +1329,7 @@ namespace monero { 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(*wallet2, chainHeight, i->first, i->second); - mergeTx(tx, txMap, blockMap, false); + mergeTx(tx, txMap, false); } } @@ -1365,7 +1342,7 @@ namespace monero { for (std::list>::const_iterator i = upayments.begin(); i != upayments.end(); ++i) { shared_ptr tx = buildTxWithOutgoingTransferUnconfirmed(*wallet2, i->first, i->second); if (txReq.isFailed != boost::none && txReq.isFailed.get() != tx->isFailed.get()) continue; // skip merging if tx unrequested - mergeTx(tx, txMap, blockMap, false); + mergeTx(tx, txMap, false); } } @@ -1378,7 +1355,7 @@ namespace monero { wallet2->get_unconfirmed_payments(payments, accountIndex, subaddressIndices); for (std::list>::const_iterator i = payments.begin(); i != payments.end(); ++i) { shared_ptr tx = buildTxWithIncomingTransferUnconfirmed(*wallet2, i->first, i->second); - mergeTx(tx, txMap, blockMap, false); + mergeTx(tx, txMap, false); } } @@ -1393,7 +1370,7 @@ namespace monero { if (tx->outgoingTransfer != boost::none && request.meetsCriteria(tx->outgoingTransfer.get().get())) transfers.push_back(tx->outgoingTransfer.get()); else tx->outgoingTransfer = boost::none; - // collect incoming transfers, erase if filtered + // collect incoming transfers, erase if unrequested vector>::iterator iter = tx->incomingTransfers.begin(); while (iter != tx->incomingTransfers.end()) { if (request.meetsCriteria((*iter).get())) { @@ -1434,14 +1411,13 @@ namespace monero { // collect unique txs and blocks map> txMap; - map> blockMap; for (const auto& outputW2 : outputsW2) { // TODO: skip tx building if w2 output filtered by indices, etc shared_ptr tx = buildTxWithVout(*wallet2, outputW2); - mergeTx(tx, txMap, blockMap, false); + mergeTx(tx, txMap, false); } - // collect requested outputs and discard irrelevant data + // collect requested vouts vector> vouts; for (map>::const_iterator txIter = txMap.begin(); txIter != txMap.end(); txIter++) { shared_ptr tx = txIter->second; diff --git a/src/wallet/MoneroWalletModel.cpp b/src/wallet/MoneroWalletModel.cpp index 5d1c7f0..690cc37 100644 --- a/src/wallet/MoneroWalletModel.cpp +++ b/src/wallet/MoneroWalletModel.cpp @@ -67,13 +67,14 @@ namespace monero { // ----------------------- UNDECLARED PRIVATE HELPERS ----------------------- - void mergeIncomingTransfer(const vector> transfers, const shared_ptr& transfer) { + void mergeIncomingTransfer(vector> transfers, const shared_ptr& transfer) { for (const shared_ptr& aTransfer : transfers) { if (aTransfer->accountIndex.get() == transfer->accountIndex.get() && aTransfer->subaddressIndex.get() == transfer->subaddressIndex.get()) { aTransfer->merge(aTransfer, transfer); return; } } + transfers.push_back(transfer); } // ---------------------------- MONERO ACCOUNT ------------------------------ @@ -127,35 +128,76 @@ namespace monero { } void MoneroTxWallet::merge(const shared_ptr& self, const shared_ptr& other) { + cout << "MoneroTxWallet::merge(MoneroTxs)" << endl; + cout << self << ", " << other << endl; + //cout << "MoneroTxWallet::merge(MoneroTx&, MoneroTx&)" << endl; + cout << self->id << endl; + cout << "bump" << endl; + cout << other->id << endl; + cout << "And onward..." << endl; + shared_ptr temp = dynamic_pointer_cast(self); + if (temp == nullptr) cout << "you're gonna be in for a bad time" << endl; + shared_ptr temp2 = dynamic_pointer_cast(other); + if (temp2 == nullptr) cout << "you're gonna be in for a bad time 2" << endl; + merge(static_pointer_cast(self), static_pointer_cast(other)); } void MoneroTxWallet::merge(const shared_ptr& self, const shared_ptr& other) { - //cout << "MoneroTxWallet::merge()" << endl; + cout << "MoneroTxWallet::merge()" << endl; + cout << self << ", " << other << endl; + + + cout << "Lets iterate over self block tx pointers" << endl; + if (self->block != boost::none) { + for (const shared_ptr& tx : self->block.get()->txs) { + cout << tx << endl; + } + } + + cout << "Lets iterate over other block tx pointers" << endl; + if (other->block != boost::none) { + for (const shared_ptr& tx : other->block.get()->txs) { + cout << tx << endl; + } + } + if (this != self.get()) throw runtime_error("this != self"); - if (self == other) return; + if (self == other) { + cout << "These are the same reference so we're returning" << endl; + return; + } // merge base classes + cout << "Merging base classes" << endl; MoneroTx::merge(self, other); + cout << "Returned from MoneroTx::merge()" << endl; + // merge wallet extensions note = MoneroUtils::reconcile(note, other->note); + cout << "2" << endl; + // merge incoming transfers if (!other->incomingTransfers.empty()) { - for (const shared_ptr& transfer : other->incomingTransfers) { + for (const shared_ptr transfer : other->incomingTransfers) { // NOTE: not using reference so shared_ptr is not deleted when tx is dereferenced transfer->tx = self; mergeIncomingTransfer(self->incomingTransfers, transfer); } } + cout << "3" << endl; + // merge outgoing transfer if (other->outgoingTransfer != boost::none) { other->outgoingTransfer.get()->tx = self; if (self->outgoingTransfer == boost::none) self->outgoingTransfer = other->outgoingTransfer; else self->outgoingTransfer.get()->merge(self->outgoingTransfer.get(), other->outgoingTransfer.get()); } + + cout << "4" << endl; } //boost::property_tree::ptree MoneroUtils::txWalletToPropertyTree(const MoneroTxWallet& tx) { @@ -296,14 +338,15 @@ namespace monero { if (self == other) return; // merge txs if they're different which comes back to merging transfers - if (tx != other->tx) tx->merge(tx, other->tx); + if (tx != other->tx) { + tx->merge(tx, other->tx); + return; + } // otherwise merge transfer fields - else { - amount = MoneroUtils::reconcile(amount, other->amount); - accountIndex = MoneroUtils::reconcile(accountIndex, other->accountIndex); - numSuggestedConfirmations = MoneroUtils::reconcile(numSuggestedConfirmations, other->numSuggestedConfirmations, boost::none, boost::none, false); - } + amount = MoneroUtils::reconcile(amount, other->amount); + accountIndex = MoneroUtils::reconcile(accountIndex, other->accountIndex); + numSuggestedConfirmations = MoneroUtils::reconcile(numSuggestedConfirmations, other->numSuggestedConfirmations, boost::none, boost::none, false); } // ----------------------- MONERO INCOMING TRANSFER -------------------------