refactor MoneroBlock::merge() to use mergeTx() helper;

MoneroTx::merge merges blocks if necessary
This commit is contained in:
woodser
2019-07-07 21:54:59 -04:00
parent 122788249f
commit a811215499
3 changed files with 229 additions and 112 deletions
+122 -24
View File
@@ -61,6 +61,23 @@
*/
namespace monero {
// ----------------------- UNDECLARED PRIVATE HELPERS -----------------------
void mergeTx(vector<shared_ptr<MoneroTx>> txs, const shared_ptr<MoneroTx>& tx) {
cout << "Merging this other guy in: " << tx << endl;
for (const shared_ptr<MoneroTx>& 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<MoneroBlockHeader>& self, const shared_ptr<MoneroBlockHeader>& other) {
cout << "CALLING MONERO BLOCK BASE MERGE" << endl;
merge(static_pointer_cast<MoneroBlock>(self), static_pointer_cast<MoneroBlock>(other));
}
void MoneroBlock::merge(const shared_ptr<MoneroBlock>& self, const shared_ptr<MoneroBlock>& 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<MoneroTx>& tx : self->txs) {
cout << tx << endl;
}
cout << "Lets iterate over other block tx pointers" << endl;
for (const shared_ptr<MoneroTx>& 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<MoneroTx>& thatTx : other->txs) {
bool found = false;
for (const shared_ptr<MoneroTx>& 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<MoneroTx>& tx : txs) {
tx->block = self;
if (!other->txs.empty()) {
cout << "4" << endl;
for (const shared_ptr<MoneroTx> 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<MoneroTx>& thatTx : other->txs) {
// bool found = false;
// for (const shared_ptr<MoneroTx>& 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<MoneroTx>& 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<MoneroTx>& self, const shared_ptr<MoneroTx>& 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<MoneroBlock>(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<MoneroBlock>(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<MoneroOutput>& merger : other->vins) {
for (shared_ptr<MoneroOutput> merger : other->vins) {
bool merged = false;
merger->tx = self;
for (const shared_ptr<MoneroOutput>& mergee : vins) {
@@ -274,9 +367,11 @@ namespace monero {
}
}
cout << "Merging vouts!" << endl;
// merge vouts
if (!other->vouts.empty()) {
for (const shared_ptr<MoneroOutput>& vout : other->vouts) vout->tx = self;
for (shared_ptr<MoneroOutput> 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<MoneroOutput>& merger : other->vouts) {
for (shared_ptr<MoneroOutput> merger : other->vouts) {
bool merged = false;
merger->tx = self; // TODO: this update needs made in Java and JS
for (const shared_ptr<MoneroOutput>& 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 -----------------------------
+54 -78
View File
@@ -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<MoneroTxWallet> tx, map<string, shared_ptr<MoneroTxWallet>>& txMap, bool skipIfAbsent) {
if (tx->block != boost::none) {
bool found = false;
for (const shared_ptr<MoneroTx>& 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<string, shared_ptr<MoneroTxWallet>>::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<MoneroTxWallet>& 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<MoneroTxWallet>& tx, map<string, shared_ptr<MoneroTxWallet>>& txMap, map<uint64_t, shared_ptr<MoneroBlock>>& 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<string, shared_ptr<MoneroTxWallet>>::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<MoneroTxWallet>& 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<MoneroBlock>(new MoneroBlock());
aTx->block.get()->txs.push_back(tx);
aTx->block.get()->height = tx->getHeight();
}
if (tx->block == boost::none) {
tx->block = shared_ptr<MoneroBlock>(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<uint64_t, shared_ptr<MoneroBlock>>::const_iterator blockIter = blockMap.find(tx->getHeight().get());
if (blockIter == blockMap.end()) {
blockMap[tx->getHeight().get()] = tx->block.get();
} else {
shared_ptr<MoneroBlock>& 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<string, shared_ptr<MoneroTxWallet>> txMap;
map<uint64_t, shared_ptr<MoneroBlock>> blockMap;
for (const shared_ptr<MoneroTxWallet>& 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<MoneroOutputWallet>& output : outputs) {
shared_ptr<MoneroTxWallet> tx = static_pointer_cast<MoneroTxWallet>(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<string, shared_ptr<MoneroTxWallet>> txMap;
map<uint64_t, shared_ptr<MoneroBlock>> blockMap;
// get confirmed incoming transfers
if (isIn) {
@@ -1340,7 +1317,7 @@ namespace monero {
wallet2->get_payments(payments, minHeight, maxHeight, accountIndex, subaddressIndices);
for (std::list<std::pair<crypto::hash, tools::wallet2::payment_details>>::const_iterator i = payments.begin(); i != payments.end(); ++i) {
shared_ptr<MoneroTxWallet> 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<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>>::const_iterator i = payments.begin(); i != payments.end(); ++i) {
shared_ptr<MoneroTxWallet> 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<std::pair<crypto::hash, tools::wallet2::unconfirmed_transfer_details>>::const_iterator i = upayments.begin(); i != upayments.end(); ++i) {
shared_ptr<MoneroTxWallet> 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<std::pair<crypto::hash, tools::wallet2::pool_payment_details>>::const_iterator i = payments.begin(); i != payments.end(); ++i) {
shared_ptr<MoneroTxWallet> 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<shared_ptr<MoneroIncomingTransfer>>::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<string, shared_ptr<MoneroTxWallet>> txMap;
map<uint64_t, shared_ptr<MoneroBlock>> blockMap;
for (const auto& outputW2 : outputsW2) {
// TODO: skip tx building if w2 output filtered by indices, etc
shared_ptr<MoneroTxWallet> tx = buildTxWithVout(*wallet2, outputW2);
mergeTx(tx, txMap, blockMap, false);
mergeTx(tx, txMap, false);
}
// collect requested outputs and discard irrelevant data
// collect requested vouts
vector<shared_ptr<MoneroOutputWallet>> vouts;
for (map<string, shared_ptr<MoneroTxWallet>>::const_iterator txIter = txMap.begin(); txIter != txMap.end(); txIter++) {
shared_ptr<MoneroTxWallet> tx = txIter->second;
+53 -10
View File
@@ -67,13 +67,14 @@ namespace monero {
// ----------------------- UNDECLARED PRIVATE HELPERS -----------------------
void mergeIncomingTransfer(const vector<shared_ptr<MoneroIncomingTransfer>> transfers, const shared_ptr<MoneroIncomingTransfer>& transfer) {
void mergeIncomingTransfer(vector<shared_ptr<MoneroIncomingTransfer>> transfers, const shared_ptr<MoneroIncomingTransfer>& transfer) {
for (const shared_ptr<MoneroIncomingTransfer>& 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<MoneroTx>& self, const shared_ptr<MoneroTx>& 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<MoneroTxWallet> temp = dynamic_pointer_cast<MoneroTxWallet>(self);
if (temp == nullptr) cout << "you're gonna be in for a bad time" << endl;
shared_ptr<MoneroTxWallet> temp2 = dynamic_pointer_cast<MoneroTxWallet>(other);
if (temp2 == nullptr) cout << "you're gonna be in for a bad time 2" << endl;
merge(static_pointer_cast<MoneroTxWallet>(self), static_pointer_cast<MoneroTxWallet>(other));
}
void MoneroTxWallet::merge(const shared_ptr<MoneroTxWallet>& self, const shared_ptr<MoneroTxWallet>& 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<MoneroTx>& 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<MoneroTx>& 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<MoneroIncomingTransfer>& transfer : other->incomingTransfers) {
for (const shared_ptr<MoneroIncomingTransfer> 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 -------------------------