mirror of
https://github.com/wownero/wownero-cpp.git
synced 2026-10-17 15:21:30 +02:00
identify and handle bug in monero core: failed tx in pool (after
testUpdateLockedDifferentAccounts()) associated with non-originating saved wallets returning duplicate incoming transfers but one has amount/numSuggestedConfirmations of 0. Resolved by rescan_bc; MoneroUtils::reconcile() supports optional custom error message for debugging
This commit is contained in:
@@ -113,22 +113,22 @@ namespace monero {
|
||||
if (this != self.get()) throw runtime_error("this != self");
|
||||
if (self == other) return;
|
||||
id = MoneroUtils::reconcile(id, other->id);
|
||||
height = MoneroUtils::reconcile(height, other->height, boost::none, boost::none, true); // height can increase
|
||||
timestamp = MoneroUtils::reconcile(timestamp, other->timestamp, boost::none, boost::none, true); // timestamp can increase
|
||||
size = MoneroUtils::reconcile(size, other->size);
|
||||
weight = MoneroUtils::reconcile(weight, other->weight);
|
||||
longTermWeight = MoneroUtils::reconcile(longTermWeight, other->longTermWeight);
|
||||
depth = MoneroUtils::reconcile(depth, other->depth);
|
||||
difficulty = MoneroUtils::reconcile(difficulty, other->difficulty);
|
||||
cumulativeDifficulty = MoneroUtils::reconcile(cumulativeDifficulty, other->cumulativeDifficulty);
|
||||
majorVersion = MoneroUtils::reconcile(majorVersion, other->majorVersion);
|
||||
minorVersion = MoneroUtils::reconcile(minorVersion, other->minorVersion);
|
||||
nonce = MoneroUtils::reconcile(nonce, other->nonce);
|
||||
height = MoneroUtils::reconcile(height, other->height, boost::none, boost::none, true, "block height"); // height can increase
|
||||
timestamp = MoneroUtils::reconcile(timestamp, other->timestamp, boost::none, boost::none, true, "block header timestamp"); // timestamp can increase
|
||||
size = MoneroUtils::reconcile(size, other->size, "block header size");
|
||||
weight = MoneroUtils::reconcile(weight, other->weight, "block header weight");
|
||||
longTermWeight = MoneroUtils::reconcile(longTermWeight, other->longTermWeight, "block header long term weight");
|
||||
depth = MoneroUtils::reconcile(depth, other->depth, "block header depth");
|
||||
difficulty = MoneroUtils::reconcile(difficulty, other->difficulty, "difficulty");
|
||||
cumulativeDifficulty = MoneroUtils::reconcile(cumulativeDifficulty, other->cumulativeDifficulty, "cumulativeDifficulty");
|
||||
majorVersion = MoneroUtils::reconcile(majorVersion, other->majorVersion, "majorVersion");
|
||||
minorVersion = MoneroUtils::reconcile(minorVersion, other->minorVersion, "minorVersion");
|
||||
nonce = MoneroUtils::reconcile(nonce, other->nonce, "nonce");
|
||||
coinbaseTxId = MoneroUtils::reconcile(coinbaseTxId, other->coinbaseTxId);
|
||||
numTxs = MoneroUtils::reconcile(numTxs, other->numTxs);
|
||||
numTxs = MoneroUtils::reconcile(numTxs, other->numTxs, "block header numTxs");
|
||||
orphanStatus = MoneroUtils::reconcile(orphanStatus, other->orphanStatus);
|
||||
prevId = MoneroUtils::reconcile(prevId, other->prevId);
|
||||
reward = MoneroUtils::reconcile(reward, other->reward);
|
||||
reward = MoneroUtils::reconcile(reward, other->reward, "block header reward");
|
||||
powHash = MoneroUtils::reconcile(powHash, other->powHash);
|
||||
}
|
||||
|
||||
@@ -249,8 +249,8 @@ namespace monero {
|
||||
id = MoneroUtils::reconcile(id, other->id);
|
||||
version = MoneroUtils::reconcile(version, other->version);
|
||||
paymentId = MoneroUtils::reconcile(paymentId, other->paymentId);
|
||||
fee = MoneroUtils::reconcile(fee, other->fee);
|
||||
mixin = MoneroUtils::reconcile(mixin, other->mixin);
|
||||
fee = MoneroUtils::reconcile(fee, other->fee, "tx fee");
|
||||
mixin = MoneroUtils::reconcile(mixin, other->mixin, "tx mixin");
|
||||
isConfirmed = MoneroUtils::reconcile(isConfirmed, other->isConfirmed);
|
||||
doNotRelay = MoneroUtils::reconcile(doNotRelay, other->doNotRelay);
|
||||
isRelayed = MoneroUtils::reconcile(isRelayed, other->isRelayed);
|
||||
@@ -260,8 +260,8 @@ namespace monero {
|
||||
prunedHex = MoneroUtils::reconcile(prunedHex, other->prunedHex);
|
||||
prunableHex = MoneroUtils::reconcile(prunableHex, other->prunableHex);
|
||||
prunableHash = MoneroUtils::reconcile(prunableHash, other->prunableHash);
|
||||
size = MoneroUtils::reconcile(size, other->size);
|
||||
weight = MoneroUtils::reconcile(weight, other->weight);
|
||||
size = MoneroUtils::reconcile(size, other->size, "tx size");
|
||||
weight = MoneroUtils::reconcile(weight, other->weight, "tx weight");
|
||||
//outputIndices = MoneroUtils::reconcile(outputIndices, other->outputIndices); // TODO
|
||||
metadata = MoneroUtils::reconcile(metadata, other->metadata);
|
||||
commonTxSets = MoneroUtils::reconcile(commonTxSets, other->commonTxSets);
|
||||
@@ -270,13 +270,13 @@ namespace monero {
|
||||
rctSigPrunable = MoneroUtils::reconcile(rctSigPrunable, other->rctSigPrunable);
|
||||
isKeptByBlock = MoneroUtils::reconcile(isKeptByBlock, other->isKeptByBlock);
|
||||
isFailed = MoneroUtils::reconcile(isFailed, other->isFailed);
|
||||
lastFailedHeight = MoneroUtils::reconcile(lastFailedHeight, other->lastFailedHeight);
|
||||
lastFailedHeight = MoneroUtils::reconcile(lastFailedHeight, other->lastFailedHeight, "lastFailedHeight");
|
||||
lastFailedId = MoneroUtils::reconcile(lastFailedId, other->lastFailedId);
|
||||
maxUsedBlockHeight = MoneroUtils::reconcile(maxUsedBlockHeight, other->maxUsedBlockHeight);
|
||||
maxUsedBlockHeight = MoneroUtils::reconcile(maxUsedBlockHeight, other->maxUsedBlockHeight, "maxUsedBlockHeight");
|
||||
maxUsedBlockId = MoneroUtils::reconcile(maxUsedBlockId, other->maxUsedBlockId);
|
||||
//signatures = MoneroUtils::reconcile(signatures, other->signatures); // TODO
|
||||
unlockTime = MoneroUtils::reconcile(unlockTime, other->unlockTime);
|
||||
numConfirmations = MoneroUtils::reconcile(numConfirmations, other->numConfirmations);
|
||||
unlockTime = MoneroUtils::reconcile(unlockTime, other->unlockTime, "unlockTime");
|
||||
numConfirmations = MoneroUtils::reconcile(numConfirmations, other->numConfirmations, "numConfirmations");
|
||||
|
||||
// merge vins
|
||||
if (!other->vins.empty()) {
|
||||
@@ -349,8 +349,8 @@ namespace monero {
|
||||
lastRelayedTimestamp = boost::none;
|
||||
} else {
|
||||
inTxPool = MoneroUtils::reconcile(inTxPool, other->inTxPool, boost::none, true, boost::none); // unrelayed -> tx pool
|
||||
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
|
||||
receivedTimestamp = MoneroUtils::reconcile(receivedTimestamp, other->receivedTimestamp, boost::none, boost::none, false, "receivedTimestamp"); // take earliest receive time
|
||||
lastRelayedTimestamp = MoneroUtils::reconcile(lastRelayedTimestamp, other->lastRelayedTimestamp, boost::none, boost::none, true, "lastRelayedTimestamp"); // take latest relay time
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,7 +395,7 @@ namespace monero {
|
||||
// otherwise merge output fields
|
||||
if (keyImage == boost::none) keyImage = other->keyImage;
|
||||
else if (other->keyImage != boost::none) keyImage.get()->merge(keyImage.get(), other->keyImage.get());
|
||||
amount = MoneroUtils::reconcile(amount, other->amount);
|
||||
index = MoneroUtils::reconcile(index, other->index);
|
||||
amount = MoneroUtils::reconcile(amount, other->amount, "output amount");
|
||||
index = MoneroUtils::reconcile(index, other->index, "output index");
|
||||
}
|
||||
}
|
||||
|
||||
+14
-19
@@ -108,7 +108,7 @@ namespace MoneroUtils
|
||||
|
||||
// TODO: refactor common template code
|
||||
template <class T, typename std::enable_if<std::is_same<T, string>::value, T>::type* = nullptr>
|
||||
boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2, boost::optional<bool> resolveDefined, boost::optional<bool> resolveTrue, boost::optional<bool> resolveMax) {
|
||||
boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2, boost::optional<bool> resolveDefined, boost::optional<bool> resolveTrue, boost::optional<bool> resolveMax, const string& errMsg = "") {
|
||||
|
||||
// check for equality
|
||||
if (val1 == val2) return val1;
|
||||
@@ -119,16 +119,15 @@ namespace MoneroUtils
|
||||
else return val1 == boost::none ? val2 : val1;
|
||||
}
|
||||
|
||||
throw runtime_error("Cannot reconcile strings");
|
||||
throw runtime_error(string("Cannot reconcile strings: ") + to_string(val1) + string(" vs ") + to_string(val2) + (!errMsg.empty() ? string(". ") + errMsg : string("")));
|
||||
}
|
||||
|
||||
template <class T, typename std::enable_if<std::is_same<T, string>::value, T>::type* = nullptr>
|
||||
boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2) {
|
||||
return reconcile(val1, val2, boost::none, boost::none, boost::none);
|
||||
boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2, const string& errMsg = "") {
|
||||
return reconcile(val1, val2, boost::none, boost::none, boost::none, errMsg);
|
||||
}
|
||||
|
||||
template <class T, typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
|
||||
boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2, boost::optional<bool> resolveDefined, boost::optional<bool> resolveTrue, boost::optional<bool> resolveMax) {
|
||||
boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2, boost::optional<bool> resolveDefined, boost::optional<bool> resolveTrue, boost::optional<bool> resolveMax, const string& errMsg = "") {
|
||||
|
||||
// check for equality
|
||||
if (val1 == val2) return val1;
|
||||
@@ -145,16 +144,15 @@ namespace MoneroUtils
|
||||
}
|
||||
|
||||
// throw runtime_error("Cannot reconcile values " + val1 + " and " + val2 + " with config: [" + resolveDefined + ", " + resolveTrue + ", " + resolveMax + "]", val1, val2);
|
||||
throw runtime_error("Cannot reconcile integrals");
|
||||
throw runtime_error(string("Cannot reconcile integrals: ") + to_string(val1) + string(" vs ") + to_string(val2) + (!errMsg.empty() ? string(". ") + errMsg : string("")));
|
||||
}
|
||||
|
||||
template <class T, typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
|
||||
boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2) {
|
||||
return reconcile(val1, val2, boost::none, boost::none, boost::none);
|
||||
boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2, const string& errMsg = "") {
|
||||
return reconcile(val1, val2, boost::none, boost::none, boost::none, errMsg);
|
||||
}
|
||||
|
||||
template <class T, typename std::enable_if<std::is_same<T, bool>::value, T>::type>
|
||||
boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2, boost::optional<bool> resolveDefined, boost::optional<bool> resolveTrue, boost::optional<bool> resolveMax) {
|
||||
boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2, boost::optional<bool> resolveDefined, boost::optional<bool> resolveTrue, boost::optional<bool> resolveMax, const string& errMsg = "") {
|
||||
|
||||
// check for equality
|
||||
if (val1 == val2) return val1;
|
||||
@@ -169,19 +167,16 @@ namespace MoneroUtils
|
||||
if (resolveTrue != boost::none) {
|
||||
return val1 == resolveTrue ? val1 : val2; // if resolve true, return true, else return false
|
||||
} else {
|
||||
throw runtime_error("Cannot reconcile booleans");
|
||||
throw runtime_error(string("Cannot reconcile booleans: ") + to_string(val1) + string(" vs ") + to_string(val2) + (!errMsg.empty() ? string(". ") + errMsg : string("")));
|
||||
}
|
||||
|
||||
throw runtime_error("Cannot reconcile booleans");
|
||||
}
|
||||
|
||||
template <class T, typename std::enable_if<std::is_same<T, bool>::value, T>::type>
|
||||
boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2) {
|
||||
return reconcile(val1, val2, boost::none, boost::none, boost::none);
|
||||
boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2, const string& errMsg = "") {
|
||||
return reconcile(val1, val2, boost::none, boost::none, boost::none, errMsg);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
vector<T> reconcile(const vector<T>& v1, const vector<T>& v2) {
|
||||
vector<T> reconcile(const vector<T>& v1, const vector<T>& v2, const string& errMsg = "") {
|
||||
|
||||
// check for equality
|
||||
if (v1 == v2) return v1;
|
||||
@@ -191,7 +186,7 @@ namespace MoneroUtils
|
||||
if (v2.empty()) return v1;
|
||||
|
||||
// otherwise cannot reconcile
|
||||
throw runtime_error("Cannot reconcile vectors");
|
||||
throw runtime_error("Cannot reconcile vectors" + (!errMsg.empty() ? string(". ") + errMsg : string("")));
|
||||
}
|
||||
|
||||
// template <class T>
|
||||
|
||||
@@ -289,9 +289,17 @@ namespace monero {
|
||||
}
|
||||
|
||||
// otherwise merge transfer fields
|
||||
amount = MoneroUtils::reconcile(amount, other->amount);
|
||||
accountIndex = MoneroUtils::reconcile(accountIndex, other->accountIndex);
|
||||
numSuggestedConfirmations = MoneroUtils::reconcile(numSuggestedConfirmations, other->numSuggestedConfirmations, boost::none, boost::none, false);
|
||||
accountIndex = MoneroUtils::reconcile(accountIndex, other->accountIndex, "acountIndex");
|
||||
|
||||
// TODO monero core: failed tx in pool (after testUpdateLockedDifferentAccounts()) causes non-originating saved wallets to return duplicate incoming transfers but one has amount/numSuggestedConfirmations of 0
|
||||
if (amount != boost::none && other->amount != boost::none && *amount != *other->amount && (*amount == 0 || *other->amount == 0)) {
|
||||
accountIndex = MoneroUtils::reconcile(accountIndex, other->accountIndex, boost::none, boost::none, true, "acountIndex");
|
||||
numSuggestedConfirmations = MoneroUtils::reconcile(numSuggestedConfirmations, other->numSuggestedConfirmations, boost::none, boost::none, true, "numSuggestedConfirmations");
|
||||
cout << "WARNING: failed tx in pool causes non-originating wallets to return duplicate incoming transfers but with one amount/numSuggestedConfirmations of 0" << endl;
|
||||
} else {
|
||||
amount = MoneroUtils::reconcile(amount, other->amount, "transfer amount");
|
||||
numSuggestedConfirmations = MoneroUtils::reconcile(numSuggestedConfirmations, other->numSuggestedConfirmations, boost::none, boost::none, false, "numSuggestedConfirmations");
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------- MONERO INCOMING TRANSFER -------------------------
|
||||
@@ -314,7 +322,7 @@ namespace monero {
|
||||
//cout << "MoneroIncomingTransfer::merge" << endl;
|
||||
if (self == other) return;
|
||||
MoneroTransfer::merge(self, other);
|
||||
subaddressIndex = MoneroUtils::reconcile(subaddressIndex, other->subaddressIndex);
|
||||
subaddressIndex = MoneroUtils::reconcile(subaddressIndex, other->subaddressIndex, "incoming transfer subaddressIndex");
|
||||
address = MoneroUtils::reconcile(address, other->address);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user