From 54d823b3e8265066281e330c61bc5d325691490d Mon Sep 17 00:00:00 2001 From: miketout Date: Sun, 4 Jun 2023 11:02:47 -0700 Subject: [PATCH 01/12] Sync fix --- src/pbaas/reserves.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pbaas/reserves.cpp b/src/pbaas/reserves.cpp index b231e2767a6..bccbace214c 100644 --- a/src/pbaas/reserves.cpp +++ b/src/pbaas/reserves.cpp @@ -4369,7 +4369,7 @@ bool CReserveTransactionDescriptor::AddReserveTransferImportOutputs(const CCurre } else { - CCurrencyValueMap cumulativeReservesIn = importCurrencyState.NativeToReserveRaw(importCurrencyState.primaryCurrencyIn, importCurrencyState.conversionPrice); + CCurrencyValueMap cumulativeReservesIn = CCurrencyValueMap(importCurrencyState.currencies, importCurrencyState.primaryCurrencyIn); CCurrencyValueMap newTotalReserves = cumulativeReservesIn + newReserveIn + preConvertedReserves; From 92ac114d699298a8923635806095fabc9112860d Mon Sep 17 00:00:00 2001 From: miketout Date: Sun, 4 Jun 2023 14:04:28 -0700 Subject: [PATCH 02/12] Improved limit checks --- src/pbaas/notarization.cpp | 26 ++++++++++++++++++++------ src/pbaas/pbaas.cpp | 7 +++++++ src/pbaas/reserves.cpp | 20 +++++++++++++++++++- 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/src/pbaas/notarization.cpp b/src/pbaas/notarization.cpp index 86d5ca66b57..861c85c6730 100644 --- a/src/pbaas/notarization.cpp +++ b/src/pbaas/notarization.cpp @@ -1147,6 +1147,8 @@ bool CPBaaSNotarization::NextNotarizationInfo(const CCurrencyDefinition &sourceS 1 : chainActive.Height() + 1; + bool improvedMinCheck = ConnectedChains.CheckZeroViaOnlyPostLaunch(currentHeight); + CTransferDestination notaryPayee; if (!externalSystemID.IsNull()) @@ -1161,10 +1163,16 @@ bool CPBaaSNotarization::NextNotarizationInfo(const CCurrencyDefinition &sourceS CNativeHashWriter hw(hashType); CCurrencyValueMap newPreConversionReservesIn; + CCurrencyValueMap prelaunchReserveIn; if (!IsPreLaunch() && !IsLaunchComplete()) { newPreConversionReservesIn = CCurrencyValueMap(currencyState.currencies, currencyState.primaryCurrencyIn); + prelaunchReserveIn = newPreConversionReservesIn; + } + else if (improvedMinCheck && IsPreLaunch()) + { + prelaunchReserveIn = CCurrencyValueMap(currencyState.currencies, currencyState.reserveIn); } for (int i = 0; i < exportTransfers.size(); i++) @@ -1200,14 +1208,16 @@ bool CPBaaSNotarization::NextNotarizationInfo(const CCurrencyDefinition &sourceS CCurrencyValueMap newTotalReserves; if (IsPreLaunch()) { - newTotalReserves = CCurrencyValueMap(destCurrency.currencies, newNotarization.currencyState.reserves) + newReserveIn + newPreConversionReservesIn; + newTotalReserves = CCurrencyValueMap(destCurrency.currencies, newNotarization.currencyState.reserves) + newReserveIn + prelaunchReserveIn; } else { - newTotalReserves = CCurrencyValueMap(destCurrency.currencies, newNotarization.currencyState.primaryCurrencyIn) + newReserveIn + newPreConversionReservesIn; + newTotalReserves = CCurrencyValueMap(destCurrency.currencies, newNotarization.currencyState.primaryCurrencyIn) + newReserveIn + prelaunchReserveIn; } - if (destCurrency.maxPreconvert.size() && newTotalReserves > CCurrencyValueMap(destCurrency.currencies, destCurrency.maxPreconvert)) + if (destCurrency.maxPreconvert.size() && + ((!improvedMinCheck && newTotalReserves > CCurrencyValueMap(destCurrency.currencies, destCurrency.maxPreconvert)) || + (improvedMinCheck && (CCurrencyValueMap(destCurrency.currencies, destCurrency.maxPreconvert) - newTotalReserves).HasNegative()))) { LogPrintf("%s: refunding pre-conversion over maximum\n", __func__); reserveTransfer = reserveTransfer.GetRefundTransfer(); @@ -1215,6 +1225,7 @@ bool CPBaaSNotarization::NextNotarizationInfo(const CCurrencyDefinition &sourceS else { newPreConversionReservesIn += newReserveIn; + prelaunchReserveIn += newReserveIn; } } } @@ -1298,9 +1309,12 @@ bool CPBaaSNotarization::NextNotarizationInfo(const CCurrencyDefinition &sourceS // check our currency and any co-launch currency to determine our eligibility, as ALL // co-launch currencies must launch for one to launch + CCurrencyValueMap coLaunchReserveIn = CCurrencyValueMap(coLaunchCurrency.currencies, coLaunchState.reserveIn); + CCurrencyValueMap coLaunchMinMap = CCurrencyValueMap(coLaunchCurrency.currencies, coLaunchCurrency.minPreconvert); if (coLaunchState.IsRefunding() || !coLaunchState.ValidateConversionLimits(true) || - CCurrencyValueMap(coLaunchCurrency.currencies, coLaunchState.reserveIn) < CCurrencyValueMap(coLaunchCurrency.currencies, coLaunchCurrency.minPreconvert) || + (!improvedMinCheck && coLaunchReserveIn < coLaunchMinMap) || + (improvedMinCheck && (coLaunchReserveIn - coLaunchMinMap).HasNegative()) || (coLaunchCurrency.IsFractional() && CCurrencyValueMap(coLaunchCurrency.currencies, coLaunchState.reserveIn).CanonicalMap().valueMap.size() != coLaunchCurrency.currencies.size())) { @@ -1319,10 +1333,10 @@ bool CPBaaSNotarization::NextNotarizationInfo(const CCurrencyDefinition &sourceS minPreMap = CCurrencyValueMap(destCurrency.currencies, destCurrency.minPreconvert).CanonicalMap(); } - bool improvedMinCheck = ConnectedChains.CheckZeroViaOnlyPostLaunch(currentHeight); if (forcedRefund || (minPreMap.valueMap.size() && - ((!improvedMinCheck && preConvertedMap < minPreMap) || (improvedMinCheck && (preConvertedMap - minPreMap).HasNegative()))) || + ((!improvedMinCheck && preConvertedMap < minPreMap) || + (improvedMinCheck && (preConvertedMap - minPreMap).HasNegative()))) || (destCurrency.IsFractional() && (CCurrencyValueMap(destCurrency.currencies, newNotarization.currencyState.reserveIn) + newPreConversionReservesIn).CanonicalMap().valueMap.size() != destCurrency.currencies.size())) diff --git a/src/pbaas/pbaas.cpp b/src/pbaas/pbaas.cpp index 298c5fa5667..64840e880fc 100644 --- a/src/pbaas/pbaas.cpp +++ b/src/pbaas/pbaas.cpp @@ -7410,6 +7410,13 @@ bool CConnectedChains::CreateLatestImports(const CCurrencyDefinition &sourceSyst // pay the fee out to the miner CReserveTransactionDescriptor rtxd(tb.mtx, view, nHeight + 1); + if (!rtxd.IsValid()) + { + printf("%s: Created invalid import transaction for currency %s\n", __func__, EncodeDestination(CIdentityID(ccx.destCurrencyID)).c_str()); + LogPrintf("%s: Created invalid import transaction for currency %s\n", __func__, EncodeDestination(CIdentityID(ccx.destCurrencyID)).c_str()); + return false; + } + tb.SetFee(rtxd.nativeIn - rtxd.nativeOut); CCurrencyValueMap intersectMap; diff --git a/src/pbaas/reserves.cpp b/src/pbaas/reserves.cpp index bccbace214c..e4db7b61928 100644 --- a/src/pbaas/reserves.cpp +++ b/src/pbaas/reserves.cpp @@ -2906,6 +2906,22 @@ CReserveTransactionDescriptor::CReserveTransactionDescriptor(const CTransaction } // these affect comparison, but not calculations + if (newState.reserveIn != importNotarization.currencyState.reserveIn || + newState.reserveOut != importNotarization.currencyState.reserveOut || + newState.primaryCurrencyIn != importNotarization.currencyState.primaryCurrencyIn) + { + if (LogAcceptCategory("defi")) + { + LogPrintf("%s: Expected - reserveIn: %ld, reserveOut: %ld, primaryCurrencyIn: %ld\n Actual - reserveIn: %ld, reserveOut: %ld, primaryCurrencyIn: %ld\n", + __func__, + newState.reserveIn, + newState.reserveOut, + newState.primaryCurrencyIn, + importNotarization.currencyState.reserveIn, + importNotarization.currencyState.reserveOut, + importNotarization.currencyState.primaryCurrencyIn); + } + } newState.reserveIn = importNotarization.currencyState.reserveIn; newState.reserveOut = importNotarization.currencyState.reserveOut; newState.primaryCurrencyIn = importNotarization.currencyState.primaryCurrencyIn; @@ -4355,7 +4371,9 @@ bool CReserveTransactionDescriptor::AddReserveTransferImportOutputs(const CCurre { CCurrencyValueMap cumulativeReservesIn = importCurrencyDef.IsFractional() ? - CCurrencyValueMap(importCurrencyState.currencies, importCurrencyState.primaryCurrencyIn) : + (importCurrencyState.IsPrelaunch() ? + CCurrencyValueMap(importCurrencyState.currencies, importCurrencyState.reserveIn) : + CCurrencyValueMap(importCurrencyState.currencies, importCurrencyState.primaryCurrencyIn)) : importCurrencyState.NativeToReserveRaw(importCurrencyState.primaryCurrencyIn, importCurrencyState.conversionPrice); // check if it exceeds pre-conversion maximums, and refund if so From a9fafc71d74d739f9a79eee7be92a6ea2389aa40 Mon Sep 17 00:00:00 2001 From: miketout Date: Sun, 4 Jun 2023 14:11:03 -0700 Subject: [PATCH 03/12] Build fix --- src/pbaas/reserves.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/pbaas/reserves.cpp b/src/pbaas/reserves.cpp index e4db7b61928..f243601578d 100644 --- a/src/pbaas/reserves.cpp +++ b/src/pbaas/reserves.cpp @@ -2912,14 +2912,7 @@ CReserveTransactionDescriptor::CReserveTransactionDescriptor(const CTransaction { if (LogAcceptCategory("defi")) { - LogPrintf("%s: Expected - reserveIn: %ld, reserveOut: %ld, primaryCurrencyIn: %ld\n Actual - reserveIn: %ld, reserveOut: %ld, primaryCurrencyIn: %ld\n", - __func__, - newState.reserveIn, - newState.reserveOut, - newState.primaryCurrencyIn, - importNotarization.currencyState.reserveIn, - importNotarization.currencyState.reserveOut, - importNotarization.currencyState.primaryCurrencyIn); + LogPrintf("%s: Expected: %s\nActual: %s\n", __func__, newState.ToUniValue().write(1,2).c_str(), importNotarization.currencyState.ToUniValue().write(1,2).c_str()); } } newState.reserveIn = importNotarization.currencyState.reserveIn; From 4cd1ff179db4432344f0e90e90d62e37c5b732e8 Mon Sep 17 00:00:00 2001 From: miketout Date: Sun, 4 Jun 2023 23:15:01 -0700 Subject: [PATCH 04/12] Fee validation cleanup --- src/pbaas/notarization.cpp | 25 ++++++++--- src/pbaas/pbaas.cpp | 44 +++++++++++++++--- src/pbaas/reserves.cpp | 91 +++++++++++++++++++++++++++++++++++--- 3 files changed, 144 insertions(+), 16 deletions(-) diff --git a/src/pbaas/notarization.cpp b/src/pbaas/notarization.cpp index 861c85c6730..ae1330e8516 100644 --- a/src/pbaas/notarization.cpp +++ b/src/pbaas/notarization.cpp @@ -1175,6 +1175,12 @@ bool CPBaaSNotarization::NextNotarizationInfo(const CCurrencyDefinition &sourceS prelaunchReserveIn = CCurrencyValueMap(currencyState.currencies, currencyState.reserveIn); } + CCurrencyValueMap maxPreconvertMap = CCurrencyValueMap(destCurrency.currencies, destCurrency.maxPreconvert); + if (destCurrency.maxPreconvert.size()) + { + maxPreconvertMap = CCurrencyValueMap(destCurrency.currencies, destCurrency.maxPreconvert); + } + for (int i = 0; i < exportTransfers.size(); i++) { CReserveTransfer reserveTransfer = exportTransfers[i]; @@ -1215,9 +1221,14 @@ bool CPBaaSNotarization::NextNotarizationInfo(const CCurrencyDefinition &sourceS newTotalReserves = CCurrencyValueMap(destCurrency.currencies, newNotarization.currencyState.primaryCurrencyIn) + newReserveIn + prelaunchReserveIn; } + if (improvedMinCheck) + { + newTotalReserves = newTotalReserves.IntersectingValues(newReserveIn); + } + if (destCurrency.maxPreconvert.size() && - ((!improvedMinCheck && newTotalReserves > CCurrencyValueMap(destCurrency.currencies, destCurrency.maxPreconvert)) || - (improvedMinCheck && (CCurrencyValueMap(destCurrency.currencies, destCurrency.maxPreconvert) - newTotalReserves).HasNegative()))) + ((!improvedMinCheck && newTotalReserves > maxPreconvertMap) || + (improvedMinCheck && (maxPreconvertMap - newTotalReserves).HasNegative()))) { LogPrintf("%s: refunding pre-conversion over maximum\n", __func__); reserveTransfer = reserveTransfer.GetRefundTransfer(); @@ -1463,10 +1474,14 @@ bool CPBaaSNotarization::NextNotarizationInfo(const CCurrencyDefinition &sourceS { if (rtxd.currencies.count(oneCurrencyID)) { - int64_t reservesConverted = rtxd.currencies[oneCurrencyID].nativeOutConverted; - if (reservesConverted) + int64_t reservesIn = improvedMinCheck ? + oneCurrencyID == ASSETCHAINS_CHAINID ? + (rtxd.nativeIn - rtxd.nativeOut) : + (rtxd.currencies[oneCurrencyID].reserveIn - (rtxd.currencies[oneCurrencyID].reserveConversionFees + rtxd.currencies[oneCurrencyID].reserveOut)) : + rtxd.currencies[oneCurrencyID].nativeOutConverted; + if (reservesIn) { - tempReserves.valueMap[oneCurrencyID] = reservesConverted; + tempReserves.valueMap[oneCurrencyID] = reservesIn; } } } diff --git a/src/pbaas/pbaas.cpp b/src/pbaas/pbaas.cpp index 64840e880fc..144fa47e2b1 100644 --- a/src/pbaas/pbaas.cpp +++ b/src/pbaas/pbaas.cpp @@ -2797,6 +2797,7 @@ bool ValidateReserveDeposit(struct CCcontract_info *cp, Eval* eval, const CTrans } bool isClearLaunch = ccxSource.IsClearLaunch(); + std::vector vOutputs; if (ConnectedChains.CheckZeroViaOnlyPostLaunch(nHeight) && isClearLaunch && @@ -2829,9 +2830,43 @@ bool ValidateReserveDeposit(struct CCcontract_info *cp, Eval* eval, const CTrans priorNotar.currencyID == mainImport.importCurrencyID) { checkState = priorNotar.currencyState; + checkState.SetPrelaunch(false); - validNotarization = true; - break; + // clear launch export is not clear launch import + checkState.SetLaunchClear(false); + CCoinbaseCurrencyState pricingState; + CCurrencyValueMap dummyCurrency, dummyCurrencyUsed, dummyCurrencyOut; + + if (rtxd.AddReserveTransferImportOutputs(sourceSysDef, + destSysDef, + destCurDef, + checkState, + reserveTransfers, + nHeight, + vOutputs, + dummyCurrency, + dummyCurrencyUsed, + dummyCurrencyOut, + &pricingState, + ccxSource.exporter, + importNotarization.proposer, + EntropyHashFromHeight(CBlockIndex::BlockEntropyKey(), importNotarization.notarizationHeight, destCurDef.GetID()))) + { + checkState.conversionPrice = pricingState.conversionPrice; + checkState.viaConversionPrice = pricingState.viaConversionPrice; + validNotarization = true; + vOutputs.clear(); + rtxd = CReserveTransactionDescriptor(); + break; + } + else + { + if (LogAcceptCategory("defi")) + { + LogPrintf("%s: Invalid currency state for import: %s\n", __func__, checkState.ToUniValue().write(1,2).c_str()); + } + return eval->Error(std::string(__func__) + ": invalid prior notarization for clear launch import: " + mainImport.ToUniValue().write(1,2)); + } } } if (!validNotarization) @@ -2842,7 +2877,7 @@ bool ValidateReserveDeposit(struct CCcontract_info *cp, Eval* eval, const CTrans } return eval->Error(std::string(__func__) + ": invalid prior notarization for clear launch import: " + mainImport.ToUniValue().write(1,2)); } - checkState.SetLaunchClear(false); + //checkState.SetLaunchClear(false); } else { @@ -2856,7 +2891,6 @@ bool ValidateReserveDeposit(struct CCcontract_info *cp, Eval* eval, const CTrans } } - std::vector vOutputs; CCurrencyValueMap importedCurrency, gatewayCurrencyUsed, spentCurrencyOut; if (!rtxd.AddReserveTransferImportOutputs(sourceSysDef, @@ -5620,7 +5654,7 @@ bool CConnectedChains::CheckZeroViaOnlyPostLaunch(uint32_t height) const { if (IsVerusActive()) { - if ((PBAAS_TESTMODE && height > 61982) || + if ((PBAAS_TESTMODE && height > 186 /* 61982 */) || (!PBAAS_TESTMODE && height > 2570264)) { return true; diff --git a/src/pbaas/reserves.cpp b/src/pbaas/reserves.cpp index f243601578d..43f41b45754 100644 --- a/src/pbaas/reserves.cpp +++ b/src/pbaas/reserves.cpp @@ -2765,9 +2765,16 @@ CReserveTransactionDescriptor::CReserveTransactionDescriptor(const CTransaction bool isClearLaunch = (ccx.IsClearLaunch() && ccx.sourceSystemID == importCurrencyDef.launchSystemID); CReserveTransactionDescriptor rtxd = *this; + rtxd.currencies.clear(); + rtxd.nativeIn = 0; + rtxd.nativeConversionFees = 0; + rtxd.nativeOut = 0; + uint256 weakEntropyHash = EntropyHashFromHeight(CBlockIndex::BlockEntropyKey(), importNotarization.notarizationHeight, importCurrencyDef.GetID()); - if (ConnectedChains.CheckZeroViaOnlyPostLaunch(nHeight) && + bool updatedChecks = ConnectedChains.CheckZeroViaOnlyPostLaunch(nHeight); + + if (updatedChecks && isClearLaunch && importTransfers.size()) { @@ -2788,6 +2795,7 @@ CReserveTransactionDescriptor::CReserveTransactionDescriptor(const CTransaction return; } bool validNotarization = false; + // get the prior output notarization for (int o = priorOutNum; o < priorTx.vout.size(); o++) { @@ -2801,6 +2809,10 @@ CReserveTransactionDescriptor::CReserveTransactionDescriptor(const CTransaction { checkState = priorNotar.currencyState; checkState.SetPrelaunch(false); + + // clear launch export is not clear launch import + checkState.SetLaunchClear(false); + if (rtxd.AddReserveTransferImportOutputs(sourceSystemDef, ConnectedChains.thisChain, importCurrencyDef, @@ -2834,7 +2846,6 @@ CReserveTransactionDescriptor::CReserveTransactionDescriptor(const CTransaction flags |= IS_REJECT; return; } - checkState.SetLaunchClear(false); } else { @@ -2872,6 +2883,10 @@ CReserveTransactionDescriptor::CReserveTransactionDescriptor(const CTransaction } rtxd = *this; + rtxd.currencies.clear(); + rtxd.nativeIn = 0; + rtxd.nativeConversionFees = 0; + rtxd.nativeOut = 0; if (!rtxd.AddReserveTransferImportOutputs(sourceSystemDef, ConnectedChains.thisChain, @@ -2914,6 +2929,56 @@ CReserveTransactionDescriptor::CReserveTransactionDescriptor(const CTransaction { LogPrintf("%s: Expected: %s\nActual: %s\n", __func__, newState.ToUniValue().write(1,2).c_str(), importNotarization.currencyState.ToUniValue().write(1,2).c_str()); } + if (updatedChecks && !checkState.IsRefunding()) + { + if (!(checkState.IsPrelaunch() || checkState.IsLaunchCompleteMarker())) + { + // accumulate reserves during pre-conversions import to enforce max pre-convert + CCurrencyValueMap tempReserves; + for (auto &oneCurrencyID : checkState.currencies) + { + if (rtxd.currencies.count(oneCurrencyID)) + { + int64_t reservesIn = oneCurrencyID == ASSETCHAINS_CHAINID ? + (rtxd.nativeIn - rtxd.nativeOut) : + rtxd.currencies[oneCurrencyID].reserveIn - + (rtxd.currencies[oneCurrencyID].reserveConversionFees + rtxd.currencies[oneCurrencyID].reserveOut); + + if (reservesIn) + { + tempReserves.valueMap[oneCurrencyID] = reservesIn; + } + } + } + + // use double entry to enable pass through of the accumulated reserve such that when + // reverting supply and reserves, we end up with what we started, after prelaunch and + // before all post launch functions are complete, we use primaryCurrencyIn to accumulate + // reserves to enforce maxPreconvert + newState.primaryCurrencyIn = newState.AddVectors(checkState.primaryCurrencyIn, tempReserves.AsCurrencyVector(newState.currencies)); + newState.reserveOut = + newState.AddVectors(newState.reserveOut, + (CCurrencyValueMap(newState.currencies, newState.reserveIn) * -1).AsCurrencyVector(newState.currencies)); + if (!isClearLaunch) + { + newState.reserveIn = tempReserves.AsCurrencyVector(newState.currencies); + } + } + if (newState.reserveIn != importNotarization.currencyState.reserveIn || + newState.reserveOut != importNotarization.currencyState.reserveOut || + newState.primaryCurrencyIn != importNotarization.currencyState.primaryCurrencyIn) + { + if (LogAcceptCategory("defi")) + { + LogPrintf("%s: Mismatched currency states - Expected: %s\nActual: %s\n", __func__, newState.ToUniValue().write(1,2).c_str(), importNotarization.currencyState.ToUniValue().write(1,2).c_str()); + /* + flags &= ~IS_VALID; + flags |= IS_REJECT; + return; + */ + } + } + } } newState.reserveIn = importNotarization.currencyState.reserveIn; newState.reserveOut = importNotarization.currencyState.reserveOut; @@ -3872,6 +3937,12 @@ bool CReserveTransactionDescriptor::AddReserveTransferImportOutputs(const CCurre CCurrencyValueMap convertedFees; // post conversion transfer fees CCurrencyValueMap liquidityFees; // for fractionals, this value is added to the currency itself + CCurrencyValueMap maxPreconvert; + if (importCurrencyDef.maxPreconvert.size()) + { + maxPreconvert = CCurrencyValueMap(importCurrencyDef.currencies, importCurrencyDef.maxPreconvert); + } + bool feeOutputStart = false; // fee outputs must come after all others, this indicates they have started int nFeeOutputs = 0; // number of fee outputs @@ -4107,6 +4178,7 @@ bool CReserveTransactionDescriptor::AddReserveTransferImportOutputs(const CCurre std::make_pair(systemDestID, convertedFractionalFee))); } } + // loop through, subtract "from" and add "to" convertedFees = transferFees; if (feeConversions.size()) @@ -4355,7 +4427,7 @@ bool CReserveTransactionDescriptor::AddReserveTransferImportOutputs(const CCurre } // enforce maximum if present - if (curTransfer.IsPreConversion() && importCurrencyDef.maxPreconvert.size()) + if (curTransfer.IsPreConversion() && maxPreconvert.valueMap.size()) { CCurrencyValueMap newReserveIn = CCurrencyValueMap(std::vector({curTransfer.FirstCurrency()}), std::vector({curTransfer.FirstValue() - CReserveTransactionDescriptor::CalculateConversionFee(curTransfer.FirstValue())})); @@ -4370,9 +4442,10 @@ bool CReserveTransactionDescriptor::AddReserveTransferImportOutputs(const CCurre importCurrencyState.NativeToReserveRaw(importCurrencyState.primaryCurrencyIn, importCurrencyState.conversionPrice); // check if it exceeds pre-conversion maximums, and refund if so - CCurrencyValueMap newTotalReserves = cumulativeReservesIn + newReserveIn + preConvertedReserves; + CCurrencyValueMap newTotalReserves = (cumulativeReservesIn + newReserveIn + preConvertedReserves).IntersectingValues(newReserveIn); - if ((CCurrencyValueMap(importCurrencyDef.currencies, importCurrencyDef.maxPreconvert) - newTotalReserves).HasNegative()) + // check without regard to other currencies + if ((maxPreconvert - newTotalReserves).HasNegative()) { LogPrint("defi", "%s: refunding pre-conversion over maximum: %s\n", __func__, curTransfer.ToUniValue().write(1,2).c_str()); curTransfer = curTransfer.GetRefundTransfer(); @@ -4773,7 +4846,13 @@ bool CReserveTransactionDescriptor::AddReserveTransferImportOutputs(const CCurre if (newCurrencyConverted == -1) { - // if we have an overflow, this isn't going to work + // if we have an overflow, this isn't going to work, so, return error + printf("%s: ERROR - conversion overflow in reserve transfer %s\n", __func__, curTransfer.ToUniValue().write().c_str()); + LogPrintf("%s: ERROR - conversion overflow in reserve transfer %s\n", __func__, curTransfer.ToUniValue().write().c_str()); + if (updatedPostLaunch) + { + return false; + } newCurrencyConverted = 0; } From 22d5411f5ff21e0b9cdc93df0c94b55046f6bc59 Mon Sep 17 00:00:00 2001 From: miketout Date: Mon, 5 Jun 2023 00:35:21 -0700 Subject: [PATCH 05/12] Fee compensation in max calculation --- src/pbaas/notarization.cpp | 22 +++++++++++++++++++++- src/pbaas/reserves.cpp | 21 ++++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/pbaas/notarization.cpp b/src/pbaas/notarization.cpp index ae1330e8516..d898d9c57b0 100644 --- a/src/pbaas/notarization.cpp +++ b/src/pbaas/notarization.cpp @@ -1470,6 +1470,8 @@ bool CPBaaSNotarization::NextNotarizationInfo(const CCurrencyDefinition &sourceS { // accumulate reserves during pre-conversions import to enforce max pre-convert CCurrencyValueMap tempReserves; + CCurrencyValueMap cumulativeReserves; + auto currencyIdxMap = tempState.GetReserveMap(); for (auto &oneCurrencyID : tempState.currencies) { if (rtxd.currencies.count(oneCurrencyID)) @@ -1479,6 +1481,21 @@ bool CPBaaSNotarization::NextNotarizationInfo(const CCurrencyDefinition &sourceS (rtxd.nativeIn - rtxd.nativeOut) : (rtxd.currencies[oneCurrencyID].reserveIn - (rtxd.currencies[oneCurrencyID].reserveConversionFees + rtxd.currencies[oneCurrencyID].reserveOut)) : rtxd.currencies[oneCurrencyID].nativeOutConverted; + + if (improvedMinCheck) + { + int idx = currencyIdxMap[oneCurrencyID]; + if (oneCurrencyID == ASSETCHAINS_CHAINID) + { + tempState.primaryCurrencyIn[idx] = + (this->currencyState.primaryCurrencyIn[idx] + rtxd.nativeIn + tempState.reserveOut[idx]) - rtxd.nativeOut; + } + else + { + tempState.primaryCurrencyIn[idx] = this->currencyState.primaryCurrencyIn[idx] + reservesIn; + } + } + if (reservesIn) { tempReserves.valueMap[oneCurrencyID] = reservesIn; @@ -1490,7 +1507,10 @@ bool CPBaaSNotarization::NextNotarizationInfo(const CCurrencyDefinition &sourceS // reverting supply and reserves, we end up with what we started, after prelaunch and // before all post launch functions are complete, we use primaryCurrencyIn to accumulate // reserves to enforce maxPreconvert - tempState.primaryCurrencyIn = tempState.AddVectors(this->currencyState.primaryCurrencyIn, tempReserves.AsCurrencyVector(tempState.currencies)); + if (!improvedMinCheck) + { + tempState.primaryCurrencyIn = tempState.AddVectors(this->currencyState.primaryCurrencyIn, tempReserves.AsCurrencyVector(tempState.currencies)); + } tempState.reserveOut = tempState.AddVectors(tempState.reserveOut, (CCurrencyValueMap(tempState.currencies, tempState.reserveIn) * -1).AsCurrencyVector(tempState.currencies)); diff --git a/src/pbaas/reserves.cpp b/src/pbaas/reserves.cpp index 43f41b45754..d997ed0c17e 100644 --- a/src/pbaas/reserves.cpp +++ b/src/pbaas/reserves.cpp @@ -2935,6 +2935,7 @@ CReserveTransactionDescriptor::CReserveTransactionDescriptor(const CTransaction { // accumulate reserves during pre-conversions import to enforce max pre-convert CCurrencyValueMap tempReserves; + auto currencyIdxMap = newState.GetReserveMap(); for (auto &oneCurrencyID : checkState.currencies) { if (rtxd.currencies.count(oneCurrencyID)) @@ -2944,6 +2945,20 @@ CReserveTransactionDescriptor::CReserveTransactionDescriptor(const CTransaction rtxd.currencies[oneCurrencyID].reserveIn - (rtxd.currencies[oneCurrencyID].reserveConversionFees + rtxd.currencies[oneCurrencyID].reserveOut); + if (updatedChecks) + { + int idx = currencyIdxMap[oneCurrencyID]; + if (oneCurrencyID == ASSETCHAINS_CHAINID) + { + newState.primaryCurrencyIn[idx] = + (checkState.primaryCurrencyIn[idx] + rtxd.nativeIn + newState.reserveOut[idx]) - rtxd.nativeOut; + } + else + { + newState.primaryCurrencyIn[idx] = checkState.primaryCurrencyIn[idx] + reservesIn; + } + } + if (reservesIn) { tempReserves.valueMap[oneCurrencyID] = reservesIn; @@ -2955,7 +2970,11 @@ CReserveTransactionDescriptor::CReserveTransactionDescriptor(const CTransaction // reverting supply and reserves, we end up with what we started, after prelaunch and // before all post launch functions are complete, we use primaryCurrencyIn to accumulate // reserves to enforce maxPreconvert - newState.primaryCurrencyIn = newState.AddVectors(checkState.primaryCurrencyIn, tempReserves.AsCurrencyVector(newState.currencies)); + if (!updatedChecks) + { + newState.primaryCurrencyIn = + newState.AddVectors(checkState.primaryCurrencyIn, tempReserves.AsCurrencyVector(newState.currencies)); + } newState.reserveOut = newState.AddVectors(newState.reserveOut, (CCurrencyValueMap(newState.currencies, newState.reserveIn) * -1).AsCurrencyVector(newState.currencies)); From b78f0e509663b279deee22bfa12636972c39c1c7 Mon Sep 17 00:00:00 2001 From: miketout Date: Mon, 5 Jun 2023 00:47:32 -0700 Subject: [PATCH 06/12] Use old method for non-fractional --- src/pbaas/notarization.cpp | 7 ++++--- src/pbaas/reserves.cpp | 17 ++++++++++------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/pbaas/notarization.cpp b/src/pbaas/notarization.cpp index d898d9c57b0..aac5820dccf 100644 --- a/src/pbaas/notarization.cpp +++ b/src/pbaas/notarization.cpp @@ -1472,17 +1472,18 @@ bool CPBaaSNotarization::NextNotarizationInfo(const CCurrencyDefinition &sourceS CCurrencyValueMap tempReserves; CCurrencyValueMap cumulativeReserves; auto currencyIdxMap = tempState.GetReserveMap(); + bool newCumulative = improvedMinCheck && tempState.IsFractional(); for (auto &oneCurrencyID : tempState.currencies) { if (rtxd.currencies.count(oneCurrencyID)) { - int64_t reservesIn = improvedMinCheck ? + int64_t reservesIn = newCumulative ? oneCurrencyID == ASSETCHAINS_CHAINID ? (rtxd.nativeIn - rtxd.nativeOut) : (rtxd.currencies[oneCurrencyID].reserveIn - (rtxd.currencies[oneCurrencyID].reserveConversionFees + rtxd.currencies[oneCurrencyID].reserveOut)) : rtxd.currencies[oneCurrencyID].nativeOutConverted; - if (improvedMinCheck) + if (newCumulative) { int idx = currencyIdxMap[oneCurrencyID]; if (oneCurrencyID == ASSETCHAINS_CHAINID) @@ -1507,7 +1508,7 @@ bool CPBaaSNotarization::NextNotarizationInfo(const CCurrencyDefinition &sourceS // reverting supply and reserves, we end up with what we started, after prelaunch and // before all post launch functions are complete, we use primaryCurrencyIn to accumulate // reserves to enforce maxPreconvert - if (!improvedMinCheck) + if (!newCumulative) { tempState.primaryCurrencyIn = tempState.AddVectors(this->currencyState.primaryCurrencyIn, tempReserves.AsCurrencyVector(tempState.currencies)); } diff --git a/src/pbaas/reserves.cpp b/src/pbaas/reserves.cpp index d997ed0c17e..d099fe8693e 100644 --- a/src/pbaas/reserves.cpp +++ b/src/pbaas/reserves.cpp @@ -2936,16 +2936,19 @@ CReserveTransactionDescriptor::CReserveTransactionDescriptor(const CTransaction // accumulate reserves during pre-conversions import to enforce max pre-convert CCurrencyValueMap tempReserves; auto currencyIdxMap = newState.GetReserveMap(); + bool newCumulative = newState.IsFractional(); for (auto &oneCurrencyID : checkState.currencies) { if (rtxd.currencies.count(oneCurrencyID)) { - int64_t reservesIn = oneCurrencyID == ASSETCHAINS_CHAINID ? - (rtxd.nativeIn - rtxd.nativeOut) : - rtxd.currencies[oneCurrencyID].reserveIn - - (rtxd.currencies[oneCurrencyID].reserveConversionFees + rtxd.currencies[oneCurrencyID].reserveOut); - - if (updatedChecks) + int64_t reservesIn = newCumulative ? + (oneCurrencyID == ASSETCHAINS_CHAINID ? + (rtxd.nativeIn - rtxd.nativeOut) : + rtxd.currencies[oneCurrencyID].reserveIn - + (rtxd.currencies[oneCurrencyID].reserveConversionFees + rtxd.currencies[oneCurrencyID].reserveOut)) : + rtxd.currencies[oneCurrencyID].nativeOutConverted; + + if (newCumulative) { int idx = currencyIdxMap[oneCurrencyID]; if (oneCurrencyID == ASSETCHAINS_CHAINID) @@ -2970,7 +2973,7 @@ CReserveTransactionDescriptor::CReserveTransactionDescriptor(const CTransaction // reverting supply and reserves, we end up with what we started, after prelaunch and // before all post launch functions are complete, we use primaryCurrencyIn to accumulate // reserves to enforce maxPreconvert - if (!updatedChecks) + if (!newCumulative) { newState.primaryCurrencyIn = newState.AddVectors(checkState.primaryCurrencyIn, tempReserves.AsCurrencyVector(newState.currencies)); From 39e53bad6feff7a9afcc2bed5977423e03f6a49d Mon Sep 17 00:00:00 2001 From: miketout Date: Mon, 5 Jun 2023 02:00:50 -0700 Subject: [PATCH 07/12] PBaaS merge mine notarization fix --- src/pbaas/notarization.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/pbaas/notarization.cpp b/src/pbaas/notarization.cpp index aac5820dccf..48606b126fa 100644 --- a/src/pbaas/notarization.cpp +++ b/src/pbaas/notarization.cpp @@ -10304,10 +10304,12 @@ bool PreCheckFinalizeNotarization(const CTransaction &tx, int32_t outNum, CValid return state.Error("Invalid notarization output for finalization"); } - if (!(!txBlockHash.IsNull() && - (notaTxBlockIt = mapBlockIndex.find(txBlockHash)) != mapBlockIndex.end() && - chainActive.Contains(notaTxBlockIt->second)) && - (!PBAAS_TESTMODE || chainActive[height - 1]->nTime >= PBAAS_TESTFORK4_TIME)) + if ((!PBAAS_TESTMODE || chainActive[height - 1]->nTime >= PBAAS_TESTFORK4_TIME) && + currentFinalization.IsConfirmed() && + height != 1 && + !(!txBlockHash.IsNull() && + (notaTxBlockIt = mapBlockIndex.find(txBlockHash)) != mapBlockIndex.end() && + chainActive.Contains(notaTxBlockIt->second))) { return state.Error("Uncommitted notarization output is invalid for finalization"); } From 191d08f0e95db584fb8d2db69dcd50bbdce72aa0 Mon Sep 17 00:00:00 2001 From: miketout Date: Mon, 5 Jun 2023 09:30:58 -0700 Subject: [PATCH 08/12] Set expected testnet/mainnet activation heights --- src/pbaas/pbaas.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pbaas/pbaas.cpp b/src/pbaas/pbaas.cpp index 144fa47e2b1..6d178e9d44a 100644 --- a/src/pbaas/pbaas.cpp +++ b/src/pbaas/pbaas.cpp @@ -5654,7 +5654,7 @@ bool CConnectedChains::CheckZeroViaOnlyPostLaunch(uint32_t height) const { if (IsVerusActive()) { - if ((PBAAS_TESTMODE && height > 186 /* 61982 */) || + if ((PBAAS_TESTMODE && height > 62378) || (!PBAAS_TESTMODE && height > 2570264)) { return true; From 8ce37e6de734b9d204cc9f73d62bbeab2d42dc71 Mon Sep 17 00:00:00 2001 From: miketout Date: Mon, 5 Jun 2023 09:33:37 -0700 Subject: [PATCH 09/12] Later mainnet height --- src/pbaas/pbaas.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pbaas/pbaas.cpp b/src/pbaas/pbaas.cpp index 6d178e9d44a..0672255cf38 100644 --- a/src/pbaas/pbaas.cpp +++ b/src/pbaas/pbaas.cpp @@ -5655,7 +5655,7 @@ bool CConnectedChains::CheckZeroViaOnlyPostLaunch(uint32_t height) const if (IsVerusActive()) { if ((PBAAS_TESTMODE && height > 62378) || - (!PBAAS_TESTMODE && height > 2570264)) + (!PBAAS_TESTMODE && height > 2573055)) { return true; } From 82bcab858578c7da88d938fe81e6e0012409e117 Mon Sep 17 00:00:00 2001 From: miketout Date: Mon, 5 Jun 2023 10:13:24 -0700 Subject: [PATCH 10/12] Set test upgrade enforcement --- src/pbaas/crosschainrpc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pbaas/crosschainrpc.cpp b/src/pbaas/crosschainrpc.cpp index 53e24e45cf5..4f9cba9c847 100644 --- a/src/pbaas/crosschainrpc.cpp +++ b/src/pbaas/crosschainrpc.cpp @@ -53,7 +53,7 @@ extern std::string VERUS_CHAINNAME; uint32_t PBAAS_TESTFORK2_TIME = 1684281600; uint32_t PBAAS_TESTFORK3_TIME = 1685379600; -uint32_t PBAAS_TESTFORK4_TIME = 1685984400; +uint32_t PBAAS_TESTFORK4_TIME = 1699344000; uint32_t PBAAS_MAINDEFI3_HEIGHT = 2553500; uint32_t PBAAS_ENFORCE_CORRECT_EVIDENCE_TIME = 1684359650; From a28958227cd593deb16f77b8c72d5d0ed2a607a1 Mon Sep 17 00:00:00 2001 From: miketout Date: Mon, 5 Jun 2023 11:14:40 -0700 Subject: [PATCH 11/12] Better debug output --- src/pbaas/reserves.cpp | 92 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/src/pbaas/reserves.cpp b/src/pbaas/reserves.cpp index d099fe8693e..a00e1b815d5 100644 --- a/src/pbaas/reserves.cpp +++ b/src/pbaas/reserves.cpp @@ -1782,6 +1782,78 @@ CAmount CalculateReserveOut(CAmount FractionalIn, CAmount Supply, CAmount Normal return reserveOut; } + +void DumpConvertData(const std::vector &_inputReserves, + const std::vector &_inputFractional, + CCurrencyState &_newState, + std::vector> const *pCrossConversions, + std::vector *pViaPrices) +{ + LogPrintf("inputReserves: \n"); + for (int i = 0; i < _inputReserves.size(); i++) + { + LogPrintf("%ld", _inputReserves[i]); + if ((i + 1) == _inputReserves.size()) + { + LogPrintf("\n"); + } + else + { + LogPrintf(", "); + } + } + LogPrintf("inputFractional: \n"); + for (int i = 0; i < _inputFractional.size(); i++) + { + LogPrintf("%ld", _inputFractional[i]); + if ((i + 1) == _inputFractional.size()) + { + LogPrintf("\n"); + } + else + { + LogPrintf(", "); + } + } + if (pViaPrices) + { + LogPrintf("viaPrices: \n"); + for (int i = 0; i < pViaPrices->size(); i++) + { + LogPrintf("%ld", (*pViaPrices)[i]); + if ((i + 1) == pViaPrices->size()) + { + LogPrintf("\n"); + } + else + { + LogPrintf(", "); + } + } + } + if (pCrossConversions) + { + LogPrintf("crossConversions: \n"); + for (int i = 0; i < pCrossConversions->size(); i++) + { + LogPrintf("conversions vector %d:\n", i); + for (int j = 0; j < (*pCrossConversions)[i].size(); j++) + { + LogPrintf("%ld", (*pCrossConversions)[i][j]); + if ((j + 1) == (*pCrossConversions)[i].size()) + { + LogPrintf("\n"); + } + else + { + LogPrintf(", "); + } + } + } + } + LogPrintf("currencystate: %s\n", _newState.ToUniValue().write(1,2).c_str()); +} + // This can handle multiple aggregated, bidirectional conversions in one block of transactions. To determine the conversion price, it // takes both input amounts of any number of reserves and the fractional currencies targeting those reserves to merge the conversion into one // merged calculation with the same price across currencies for all transactions in the block. It returns the newly calculated @@ -2153,15 +2225,35 @@ std::vector CCurrencyState::ConvertAmounts(const std::vector & } supplyAfterSell = supply + addSupply; + if (supplyAfterSell < 0) + { + printf("%s: supplyAfterSell < 0\n", __func__); + DumpConvertData(_inputReserves, _inputFractional, _newState, pCrossConversions, pViaPrices); + } assert(supplyAfterSell >= 0); supplyAfterBuySell = supplyAfterBuy + addSupply; + if (supplyAfterBuySell < 0) + { + printf("%s: supplyAfterBuySell < 0\n", __func__); + DumpConvertData(_inputReserves, _inputFractional, _newState, pCrossConversions, pViaPrices); + } assert(supplyAfterBuySell >= 0); reserveAfterSell = supply + addNormalizedReservesBB; + if (reserveAfterSell < 0) + { + printf("%s: reserveAfterSell < 0\n", __func__); + DumpConvertData(_inputReserves, _inputFractional, _newState, pCrossConversions, pViaPrices); + } assert(reserveAfterSell >= 0); reserveAfterBuySell = reserveAfterBuy + addNormalizedReservesAB; + if (reserveAfterBuySell < 0) + { + printf("%s: reserveAfterBuySell < 0\n", __func__); + DumpConvertData(_inputReserves, _inputFractional, _newState, pCrossConversions, pViaPrices); + } assert(reserveAfterBuySell >= 0); addSupply = 0; From c493fce8bbdb318fb3177ab5c55fd69c3ccebbfb Mon Sep 17 00:00:00 2001 From: miketout Date: Mon, 5 Jun 2023 11:53:25 -0700 Subject: [PATCH 12/12] Convert asserts to errors --- src/pbaas/reserves.cpp | 93 +++++++++++++++++++++++++++++------------- src/pbaas/reserves.h | 4 +- 2 files changed, 65 insertions(+), 32 deletions(-) diff --git a/src/pbaas/reserves.cpp b/src/pbaas/reserves.cpp index a00e1b815d5..a0387745e46 100644 --- a/src/pbaas/reserves.cpp +++ b/src/pbaas/reserves.cpp @@ -1861,6 +1861,7 @@ void DumpConvertData(const std::vector &_inputReserves, std::vector CCurrencyState::ConvertAmounts(const std::vector &_inputReserves, const std::vector &_inputFractional, CCurrencyState &_newState, + CValidationState &state, std::vector> const *pCrossConversions, std::vector *pViaPrices) const { @@ -1951,6 +1952,8 @@ std::vector CCurrencyState::ConvertAmounts(const std::vector & if (failed) { + DumpConvertData(_inputReserves, _inputFractional, _newState, pCrossConversions, pViaPrices); + state.Error(std::string(__func__) + " invalid starting conditions"); return initialRates; } @@ -2127,7 +2130,13 @@ std::vector CCurrencyState::ConvertAmounts(const std::vector & } CAmount curAmt = bigCurAmt.GetLow64(); it->second.first -= curAmt; - assert(it->second.first >= 0); + if (it->second.first < 0) + { + printf("%s: it->second.first < 0\n", __func__); + DumpConvertData(_inputReserves, _inputFractional, _newState, pCrossConversions, pViaPrices); + state.Error(std::string(__func__) + " it->second.first < 0"); + return initialRates; + } fractionalLayersOut[frIdx].first += weight; fractionalLayersOut[frIdx].second.first += curAmt; @@ -2178,10 +2187,22 @@ std::vector CCurrencyState::ConvertAmounts(const std::vector & } supplyAfterBuy = supply + addSupply; - assert(supplyAfterBuy >= 0); + if (supplyAfterBuy < 0) + { + printf("%s: supplyAfterBuy < 0\n", __func__); + DumpConvertData(_inputReserves, _inputFractional, _newState, pCrossConversions, pViaPrices); + state.Error(std::string(__func__) + " supplyAfterBuy < 0"); + return initialRates; + } reserveAfterBuy = supply + addNormalizedReserves; - assert(reserveAfterBuy >= 0); + if (reserveAfterBuy < 0) + { + printf("%s: reserveAfterBuy < 0\n", __func__); + DumpConvertData(_inputReserves, _inputFractional, _newState, pCrossConversions, pViaPrices); + state.Error(std::string(__func__) + " reserveAfterBuy < 0"); + return initialRates; + } addSupply = 0; addNormalizedReserves = 0; @@ -2229,32 +2250,36 @@ std::vector CCurrencyState::ConvertAmounts(const std::vector & { printf("%s: supplyAfterSell < 0\n", __func__); DumpConvertData(_inputReserves, _inputFractional, _newState, pCrossConversions, pViaPrices); + state.Error(std::string(__func__) + " supplyAfterSell < 0"); + return initialRates; } - assert(supplyAfterSell >= 0); supplyAfterBuySell = supplyAfterBuy + addSupply; if (supplyAfterBuySell < 0) { printf("%s: supplyAfterBuySell < 0\n", __func__); DumpConvertData(_inputReserves, _inputFractional, _newState, pCrossConversions, pViaPrices); + state.Error(std::string(__func__) + " supplyAfterBuySell < 0"); + return initialRates; } - assert(supplyAfterBuySell >= 0); reserveAfterSell = supply + addNormalizedReservesBB; if (reserveAfterSell < 0) { printf("%s: reserveAfterSell < 0\n", __func__); DumpConvertData(_inputReserves, _inputFractional, _newState, pCrossConversions, pViaPrices); + state.Error(std::string(__func__) + " reserveAfterSell < 0"); + return initialRates; } - assert(reserveAfterSell >= 0); reserveAfterBuySell = reserveAfterBuy + addNormalizedReservesAB; if (reserveAfterBuySell < 0) { printf("%s: reserveAfterBuySell < 0\n", __func__); DumpConvertData(_inputReserves, _inputFractional, _newState, pCrossConversions, pViaPrices); + state.Error(std::string(__func__) + " reserveAfterBuySell < 0"); + return initialRates; } - assert(reserveAfterBuySell >= 0); addSupply = 0; addNormalizedReserves = 0; @@ -2272,7 +2297,13 @@ std::vector CCurrencyState::ConvertAmounts(const std::vector & { auto idIT = fractionalOutMap.find(id); - assert(idIT != fractionalOutMap.end()); + if (idIT == fractionalOutMap.end()) + { + printf("%s: idIT == fractionalOutMap.end()\n", __func__); + DumpConvertData(_inputReserves, _inputFractional, _newState, pCrossConversions, pViaPrices); + state.Error(std::string(__func__) + " idIT == fractionalOutMap.end()"); + return initialRates; + } idIT->second.second += ((bigNewSupply * weights[reserveMap[id]]) / bigLayerWeight).GetLow64(); } @@ -2303,7 +2334,14 @@ std::vector CCurrencyState::ConvertAmounts(const std::vector & { arith_uint256 bigFractionDelta(fractionalOutIT->second.first); fractionDelta = ((bigFractionDelta + arith_uint256(fractionalOutIT->second.second)) >> 1).GetLow64(); - assert(inputFraction + fractionDelta > 0); + + if (inputFraction + fractionDelta <= 0) + { + printf("%s: inputFraction + fractionDelta <= 0\n", __func__); + DumpConvertData(_inputReserves, _inputFractional, _newState, pCrossConversions, pViaPrices); + state.Error(std::string(__func__) + " inputFraction + fractionDelta <= 0"); + return initialRates; + } fractionalSizes[i] += fractionDelta; rates[i] = ((arith_uint256(inputReserve) * bigSatoshi) / arith_uint256(fractionalSizes[i])).GetLow64(); @@ -2319,7 +2357,14 @@ std::vector CCurrencyState::ConvertAmounts(const std::vector & arith_uint256 bigReserveDelta(fractionalInIT->second.first); CAmount adjustedReserveDelta = NativeToReserve(((bigReserveDelta + arith_uint256(fractionalInIT->second.second)) >> 1).GetLow64(), i); reserveSizes[i] += adjustedReserveDelta; - assert(inputFraction > 0); + + if (inputFraction <= 0) + { + printf("%s: inputFraction <= 0\n", __func__); + DumpConvertData(_inputReserves, _inputFractional, _newState, pCrossConversions, pViaPrices); + state.Error(std::string(__func__) + " inputFraction <= 0"); + return initialRates; + } rates[i] = ((arith_uint256(reserveSizes[i]) * bigSatoshi) / arith_uint256(inputFraction)).GetLow64(); @@ -2377,7 +2422,7 @@ std::vector CCurrencyState::ConvertAmounts(const std::vector & std::vector _viaPrices; std::vector &viaPrices(pViaPrices ? *pViaPrices : _viaPrices); CCurrencyState intermediateState = newState; - viaPrices = intermediateState.ConvertAmounts(scratchValues, fractionsToConvert, newState); + viaPrices = intermediateState.ConvertAmounts(scratchValues, fractionsToConvert, newState, state); } } @@ -2396,24 +2441,6 @@ std::vector CCurrencyState::ConvertAmounts(const std::vector & return rates; } -CAmount CCurrencyState::ConvertAmounts(CAmount inputReserve, CAmount inputFraction, CCurrencyState &newState, int32_t reserveIndex) const -{ - int32_t numCurrencies = currencies.size(); - if (reserveIndex >= numCurrencies) - { - printf("%s: reserve index out of range\n", __func__); - return 0; - } - std::vector inputReserves(numCurrencies); - inputReserves[reserveIndex] = inputReserve; - std::vector inputFractional(numCurrencies); - inputFractional[reserveIndex] = inputFraction; - std::vector retVal = ConvertAmounts(inputReserves, - inputFractional, - newState); - return retVal[reserveIndex]; -} - UniValue CReserveInOuts::ToUniValue() const { UniValue retVal(UniValue::VOBJ); @@ -5530,12 +5557,20 @@ bool CReserveTransactionDescriptor::AddReserveTransferImportOutputs(const CCurre if (adjustedReserveConverted.CanonicalMap().valueMap.size() || fractionalConverted.CanonicalMap().valueMap.size()) { CCurrencyState dummyCurState; + CValidationState state; std::vector newPrices = scratchCurrencyState.ConvertAmounts(adjustedReserveConverted.AsCurrencyVector(importCurrencyState.currencies), fractionalConverted.AsCurrencyVector(importCurrencyState.currencies), dummyCurState, + state, &crossConversions, &newCurrencyState.viaConversionPrice); + if (state.IsError()) + { + printf("%s: Invalid currency conversions for import to %s : %s\n", __func__, importCurrencyDef.name.c_str(), EncodeDestination(CIdentityID(importCurrencyDef.GetID())).c_str()); + LogPrintf("%s: Invalid currency conversions for import to %s : %s\n", __func__, importCurrencyDef.name.c_str(), EncodeDestination(CIdentityID(importCurrencyDef.GetID())).c_str()); + return false; + } bool hasCrossConversions = false; for (auto &oneConversionVec : crossConversions) { diff --git a/src/pbaas/reserves.h b/src/pbaas/reserves.h index a77413ba9c8..007601fe9a0 100644 --- a/src/pbaas/reserves.h +++ b/src/pbaas/reserves.h @@ -1338,15 +1338,13 @@ class CCurrencyState std::vector PricesInReserve(bool roundUp=false) const; - // This considers one currency at a time - CAmount ConvertAmounts(CAmount inputReserve, CAmount inputFractional, CCurrencyState &newState, int32_t reserveIndex=0) const; - // convert amounts for multi-reserve fractional reserve currencies // one entry in the vector for each currency in and one fractional input for each // currency expected as output std::vector ConvertAmounts(const std::vector &inputReserve, // reserves to convert to fractional const std::vector &inputFractional, // fractional to convert to each reserve CCurrencyState &newState, + CValidationState &validationState, const std::vector> *pCrossConversions=nullptr, std::vector *pViaPrices=nullptr) const;