]> Git Repo - VerusCoin.git/commitdiff
Improve fee calculation on import
authormiketout <[email protected]>
Wed, 28 Aug 2019 05:19:47 +0000 (22:19 -0700)
committermiketout <[email protected]>
Wed, 28 Aug 2019 05:19:47 +0000 (22:19 -0700)
src/miner.cpp
src/pbaas/reserves.cpp
src/pbaas/reserves.h
src/rpc/pbaasrpc.cpp

index 0f7fafa31737a95fcfc4ec106e8af059f709df99..fd476aa81db4ef75c5aead12af100cb3dec6b7fa 100644 (file)
@@ -1049,7 +1049,7 @@ CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, int32_t gpucount,
                 dPriority += (double)nValueIn * 1000;  // flat multiplier
             } else {
                 // separate limit orders to be added later, we add them at the end, failed fill or kills are normal transactions, consider them reserve txs
-                if (isReserve && rtxd.IsReserveExchange() && rtxd.IsLimit() && !rtxd.IsFillOrKillFail())
+                if (isReserve && rtxd.IsReserveExchange() && rtxd.IsLimit())
                 {
                     // if we might expire, refresh and check again
                     if (rtxd.IsFillOrKill())
index bac4fbda42b920777dfa6d8ceeaf725b81249d28..a86eab2e4884149576c613f6f34ac59c9ba55f60 100644 (file)
@@ -305,9 +305,12 @@ void CReserveTransactionDescriptor::AddReserveExchange(const CReserveExchange &r
         else
         {
             numBuys += 1;
-            reserveConversionFees += fee;
-            reserveOutConverted += rex.nValue - fee;
-            reserveOut += rex.nValue - fee;
+            if (!(flags & IS_IMPORT))
+            {
+                reserveConversionFees += fee;
+                reserveOutConverted += rex.nValue - fee;
+                reserveOut += rex.nValue - fee;
+            }
         }
     }                        
     vRex.push_back(std::make_pair(outputIndex, rex));
@@ -421,7 +424,6 @@ CReserveTransactionDescriptor::CReserveTransactionDescriptor(const CTransaction
                         flags |= IS_REJECT;
                         return;
                     }
-
                     AddReserveExchange(rex, i, nHeight);
 
                     if (IsReject())
@@ -451,7 +453,35 @@ CReserveTransactionDescriptor::CReserveTransactionDescriptor(const CTransaction
                         chainObjs[0]->objectType == CHAINOBJ_TRANSACTION &&
                         chainObjs[1]->objectType == CHAINOBJ_CROSSCHAINPROOF))
                     {
-                        ccx = CCrossChainExport(((CChainObject<CTransaction> *)chainObjs[0])->object);
+                        CTransaction &exportTx = ((CChainObject<CTransaction> *)chainObjs[0])->object;
+                        std::vector<CBaseChainObject *> exportTransfers;
+                        if ((ccx = CCrossChainExport(exportTx)).IsValid() && 
+                            exportTx.vout.back().scriptPubKey.IsOpReturn() &&
+                            (exportTransfers = RetrieveOpRetArray(exportTx.vout.back().scriptPubKey)).size() &&
+                            exportTransfers[0]->objectType == CHAINOBJ_RESERVETRANSFER)
+                        {
+                            // an import transaction is built from the export list
+                            // we can rebuild it and confirm that it matches exactly
+                            // we can also subtract all pre-converted reserve from input
+                            // and verify that the output matches the proper conversion
+
+                            // get the chain definition of the chain we are importing from
+                            std::vector<CTxOut> checkOutputs;
+
+                            if (!AddReserveTransferImportOutputs(ConnectedChains.ThisChain(), exportTransfers, checkOutputs))
+                            {
+                                flags |= IS_REJECT;
+                            }
+                            // TODO:PBAAS - hardening - validate all the outputs we got back as the same as what is in the transaction
+                        }
+                        else
+                        {
+                            flags |= IS_REJECT;
+                        }
+                    }
+                    else
+                    {
+                        flags |= IS_REJECT;
                     }
                     DeleteOpRetObjects(chainObjs);
                 }
@@ -462,13 +492,12 @@ CReserveTransactionDescriptor::CReserveTransactionDescriptor(const CTransaction
                 case EVAL_CROSSCHAIN_EXPORT:
                 {
                     // cross chain export is incompatible with reserve exchange outputs
-                    if (IsReserveExchange())
+                    if (IsReserveExchange() || (flags & IS_IMPORT))
                     {
                         flags |= IS_REJECT;
                         return;
                     }
                     flags |= IS_EXPORT;
-                    return;
                 }
                 break;
             }
@@ -545,6 +574,142 @@ CReserveTransactionDescriptor::CReserveTransactionDescriptor(const CTransaction
     }
 }
 
+bool CReserveTransactionDescriptor::AddReserveTransferImportOutputs(const CPBaaSChainDefinition &chainDef, const std::vector<CBaseChainObject *> &exportObjects, std::vector<CTxOut> &vOutputs)
+{
+    // we do not change native in or conversion fees, but we define all of these members
+    nativeIn = 0;
+    nativeOut = 0;
+    reserveIn = 0;
+    reserveOut = 0;
+    reserveOutConverted = 0;
+    reserveConversionFees = 0;
+    numTransfers = 0;
+    bool isVerusActive = IsVerusActive();
+
+    CCcontract_info CC;
+    CCcontract_info *cp;
+    CPubKey pk;
+    uint160 chainID = chainDef.GetChainID();
+
+    for (int i = 0; i < exportObjects.size(); i++)
+    {
+        if (exportObjects[i]->objectType == CHAINOBJ_RESERVETRANSFER)
+        {
+            CReserveTransfer &curTransfer = ((CChainObject<CReserveTransfer> *)exportObjects[i])->object;
+
+            if (curTransfer.IsValid())
+            {
+                CTxOut newOut;
+                numTransfers += 1;
+
+                if (curTransfer.flags & curTransfer.FEE_OUTPUT)
+                {
+                    // fee comes after everything else, so we should have all numbers ready to calculate
+                    // check to be sure that the fee output matches the import fee expected
+                    if (i != exportObjects.size() - 1)
+                    {
+                        // invalid
+                        printf("%s: Error with fee output transfer %s\n", __func__, curTransfer.ToUniValue().write().c_str());
+                        LogPrintf("%s: Error with fee output transfer %s\n", __func__, curTransfer.ToUniValue().write().c_str());
+                        return false;
+                    }
+                    CCrossChainExport ccx(chainID, numTransfers - 1, reserveOut, ReserveFees());
+                    if (ccx.CalculateExportFee() < curTransfer.nValue || curTransfer.nFees < 0)
+                    {
+                        // invalid
+                        printf("%s: Too much fee taken for export %s\n", __func__, curTransfer.ToUniValue().write().c_str());
+                        LogPrintf("%s: Too much fee taken for export %s\n", __func__, curTransfer.ToUniValue().write().c_str());
+                        return false;
+                    }
+                }
+
+                if ((curTransfer.flags & curTransfer.CONVERT) && !(curTransfer.flags & curTransfer.PRECONVERT))
+                {
+                    // emit a reserve exchange output
+                    cp = CCinit(&CC, EVAL_RESERVE_EXCHANGE);
+                    pk = CPubKey(ParseHex(CC.CChexstr));
+
+                    std::vector<CTxDestination> dests = std::vector<CTxDestination>({CTxDestination(curTransfer.destination)});
+                    CReserveExchange rex = CReserveExchange(CReserveExchange::VALID, curTransfer.nValue);
+
+                    reserveConversionFees += CalculateConversionFee(curTransfer.nValue);
+                    reserveIn += curTransfer.nValue;
+                    reserveOutConverted += curTransfer.nValue - reserveConversionFees;
+                    reserveOut += curTransfer.nValue - reserveConversionFees;
+                    newOut = MakeCC1of1Vout(EVAL_RESERVE_EXCHANGE, 0, pk, dests, rex);
+                }
+                else if (curTransfer.flags & curTransfer.PRECONVERT)
+                {
+                    // output the amount, minus conversion fees, and generate a normal output that spends the net input of the import as native
+                    // difference between all potential value out and what we took unconverted as a fee in our fee output
+                    CAmount nativeConverted = CCurrencyState::ReserveToNative(curTransfer.nValue, chainDef.conversion);
+                    if (curTransfer.nFees < CalculateConversionFee(curTransfer.nValue + curTransfer.nFees))
+                    {
+                        // invalid
+                        printf("%s: Error insufficient conversion fee in transfer %s\n", __func__, curTransfer.ToUniValue().write().c_str());
+                        LogPrintf("%s: Error insufficient conversion fee in transfer %s\n", __func__, curTransfer.ToUniValue().write().c_str());
+                        return false;
+                    }
+                    reserveIn += curTransfer.nFees;
+                    nativeIn += nativeConverted;
+                    nativeOut += nativeConverted;
+                    newOut = CTxOut(nativeConverted, GetScriptForDestination(curTransfer.destination));
+                }
+                else if ((curTransfer.flags & curTransfer.SEND_BACK) && curTransfer.nValue > (curTransfer.DEFAULT_PER_STEP_FEE << 2))
+                {
+                    // generate a reserve transfer back to the source chain if we have at least double the fee, otherwise leave it on
+                    // this chain to be claimed
+                    cp = CCinit(&CC, EVAL_RESERVE_TRANSFER);
+                    pk = CPubKey(ParseHex(CC.CChexstr));
+
+                    std::vector<CTxDestination> dests = std::vector<CTxDestination>({CKeyID(CCrossChainRPCData::GetConditionID(chainID, EVAL_RESERVE_TRANSFER)), CKeyID(chainID)});
+                    CAmount fees = curTransfer.DEFAULT_PER_STEP_FEE << 1;
+                    CReserveTransfer rt = CReserveTransfer(CReserveExchange::VALID, curTransfer.nValue - fees, fees, curTransfer.destination);
+
+                    reserveIn += curTransfer.nFees + curTransfer.nValue;
+                    reserveOut += curTransfer.nValue;
+                    newOut = MakeCC1of1Vout(EVAL_RESERVE_TRANSFER, 0, pk, dests, rt);                    
+                }
+                else
+                {
+                    // if Verus is active, we are creating a reserve import for a PBaaS reserve chain
+                    if (isVerusActive)
+                    {
+                        // generate a reserve output of the amount indicated, less fees
+                        // emit a reserve exchange output
+                        // we will send using a reserve output, fee will be paid by converting from reserve
+                        cp = CCinit(&CC, EVAL_RESERVE_OUTPUT);
+
+                        std::vector<CTxDestination> dests = std::vector<CTxDestination>({CTxDestination(curTransfer.destination)});
+                        CReserveOutput ro = CReserveOutput(CReserveExchange::VALID, curTransfer.nValue);
+
+                        newOut = MakeCC0of0Vout(EVAL_RESERVE_OUTPUT, 0, dests, ro);
+
+                        reserveIn += curTransfer.nFees + curTransfer.nValue;
+                        reserveOut += curTransfer.nValue;
+                    }
+                    else
+                    {
+                        // we are creating an import for the Verus chain to spend from a PBaaS account of a reserve currency, move the value specified, which will spend from
+                        // the RESERVE_DEPOSIT outputs
+                        newOut = CTxOut(curTransfer.nValue, GetScriptForDestination(curTransfer.destination));
+                        reserveIn += curTransfer.nFees + curTransfer.nValue;
+                        reserveOut += curTransfer.nValue;
+                    }
+                }
+                vOutputs.push_back(newOut);
+            }
+            else
+            {
+                printf("%s: Invalid reserve transfer on export\n", __func__);
+                LogPrintf("%s: Invalid reserve transfer on export\n", __func__);
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
 CMutableTransaction &CReserveTransactionDescriptor::AddConversionInOuts(CMutableTransaction &conversionTx, std::vector<CInputDescriptor> &conversionInputs, CAmount exchangeRate, const CCurrencyState *pCurrencyState) const
 {
     if (!IsReserveExchange() || IsFillOrKillFail())
index c23b0a50577c64f6aef61fbe617e9e08ff2d2c40..baf3b9f884baadb02e33866e1f2af1c5997c3aee 100644 (file)
@@ -21,6 +21,7 @@
 using boost::multiprecision::cpp_dec_float_50;
 class CCoinsViewCache;
 class CInputDescriptor;
+class CBaseChainObject;
 
 // reserve output is a special kind of token output that does not carry it's identifier, as it
 // is always assumed to be the reserve currency of the current chain.
@@ -263,7 +264,10 @@ public:
     void AddReserveOutput(CReserveOutput &ro)
     {
         flags |= IS_RESERVE;
-        reserveOut += ro.nValue;
+        if (!(flags & IS_IMPORT))
+        {
+            reserveOut += ro.nValue;
+        }
     }
 
     // is boolean, since it can fail, which would render the tx invalid
@@ -272,11 +276,15 @@ public:
     void AddReserveTransfer(CReserveTransfer &rt)
     {
         flags |= IS_RESERVE;
-        reserveOut += rt.nValue;
-        numTransfers++;
+        if (!(flags & IS_IMPORT))
+        {
+            reserveOut += rt.nValue;
+            numTransfers++;
+        }
     }
 
     CMutableTransaction &AddConversionInOuts(CMutableTransaction &conversionTx, std::vector<CInputDescriptor> &conversionInputs, CAmount exchangeRate=0, const CCurrencyState *pCurrencyState=NULL) const;
+    bool AddReserveTransferImportOutputs(const CPBaaSChainDefinition &chainDef, const std::vector<CBaseChainObject *> &exportObjects, std::vector<CTxOut> &vOutputs);
 };
 
 class CCurrencyState
index 4c62ee70ecb6a737bf5e62f83e7e1765e88df3af..93bb657d26a21b3040a0c7f3ee4c484a50950864 100644 (file)
@@ -405,8 +405,6 @@ bool CConnectedChains::CreateLatestImports(const CPBaaSChainDefinition &chainDef
             // aixIt has an input from the export thread of last transaction, an optional deposit to the reserve, and an opret of all outputs + 1 fee
             assert(aixIt->second.second.vout.back().scriptPubKey.IsOpReturn());
 
-            std::vector<CBaseChainObject *> exportOutputs = RetrieveOpRetArray(aixIt->second.second.vout.back().scriptPubKey);
-
             CCrossChainExport ccx(aixIt->second.second);
             lastCCI = CCrossChainImport(lastImport);
             if (!lastCCI.IsValid() || !ccx.IsValid())
@@ -430,9 +428,6 @@ bool CConnectedChains::CreateLatestImports(const CPBaaSChainDefinition &chainDef
             CCcontract_info *cp;
             CPubKey pk;
 
-            CAmount totalNativeOut = 0;
-            CAmount totalReserveOut = 0;
-            CAmount totalImport = 0;
             bool isVerusActive = IsVerusActive();
 
             CAmount availableNative = lastImport.vout[newImportTx.vin[0].prevout.n].nValue;
@@ -441,106 +436,17 @@ bool CConnectedChains::CreateLatestImports(const CPBaaSChainDefinition &chainDef
             CAmount importFees = ccx.CalculateImportFee();
             CAmount feesOut = 0;
 
-            for (auto pRT : exportOutputs)
-            {
-                if (pRT->objectType != CHAINOBJ_RESERVETRANSFER)
-                {
-                    LogPrintf("%s: POSSIBLE CORRUPTION bad export opret in transaction %s\n", __func__, aixIt->second.second.GetHash().GetHex().c_str());
-                    printf("%s: POSSIBLE CORRUPTION bad export opret in transaction %s\n", __func__, aixIt->second.second.GetHash().GetHex().c_str());
-                    return false;
-                }
-                CReserveTransfer &curTransfer = ((CChainObject<CReserveTransfer> *)pRT)->object;
-
-                // DEBUGGING
-                printf("%s\n", curTransfer.ToUniValue().write().c_str());
-                LogPrintf("%s\n", curTransfer.ToUniValue().write().c_str());
-
-                if (curTransfer.IsValid())
-                {
-                    CTxOut newOut;
+            CReserveTransactionDescriptor rtxd;
 
-                    totalImport += curTransfer.nValue;
+            std::vector<CBaseChainObject *> exportOutputs = RetrieveOpRetArray(aixIt->second.second.vout.back().scriptPubKey);
 
-                    if (curTransfer.flags & curTransfer.FEE_OUTPUT)
-                    {
-                        feesOut += curTransfer.nValue;
-                    }
-                    if (curTransfer.flags & curTransfer.CONVERT)
-                    {
-                        // emit a reserve exchange output
-                        // we will send using a reserve output, fee will be paid when converting from reserve
-                        cp = CCinit(&CC, EVAL_RESERVE_EXCHANGE);
-                        pk = CPubKey(ParseHex(CC.CChexstr));
-
-                        std::vector<CTxDestination> dests = std::vector<CTxDestination>({CTxDestination(curTransfer.destination)});
-                        CReserveExchange rex = CReserveExchange(CReserveExchange::VALID, curTransfer.nValue);
-
-                        newOut = MakeCC1of1Vout(EVAL_RESERVE_EXCHANGE, 0, pk, dests, rex);
-                        totalReserveOut += rex.nValue;
-                        printf("%s: Outputting reserve exchange conversion %s\n", __func__, rex.ToUniValue().write().c_str());
-                        LogPrintf("%s: Outputting reserve exchange conversion %s\n", __func__, rex.ToUniValue().write().c_str());
-                    }
-                    else if (curTransfer.flags & curTransfer.PRECONVERT)
-                    {
-                        // output the amount, minus conversion fees, and generate a normal output that spends the net input of the import as native
-                        // difference between all potential value out and what we took unconverted as a fee in our fee output
-                        CAmount nativeConverted = CCurrencyState::ReserveToNative(curTransfer.nValue, chainDef.conversion);
-                        newOut = CTxOut(nativeConverted, GetScriptForDestination(curTransfer.destination));
-                        totalNativeOut += nativeConverted;
-                        printf("%s: Outputting native output pre-conversion %s\n", __func__, curTransfer.ToUniValue().write().c_str());
-                        LogPrintf("%s: Outputting native output pre-conversion %s\n", __func__, curTransfer.ToUniValue().write().c_str());
-                    }
-                    else if ((curTransfer.flags & curTransfer.SEND_BACK) && curTransfer.nValue > (curTransfer.DEFAULT_PER_STEP_FEE << 2))
-                    {
-                        // generate a reserve transfer back to the source chain if we have at least double the fee, otherwise leave it on
-                        // this chain to be claimed
-                        cp = CCinit(&CC, EVAL_RESERVE_TRANSFER);
-                        pk = CPubKey(ParseHex(CC.CChexstr));
-
-                        std::vector<CTxDestination> dests = std::vector<CTxDestination>({CKeyID(CCrossChainRPCData::GetConditionID(chainID, EVAL_RESERVE_TRANSFER)), CKeyID(lastCCI.chainID)});
-                        CAmount fees = curTransfer.DEFAULT_PER_STEP_FEE << 1;
-                        CReserveTransfer rt = CReserveTransfer(CReserveExchange::VALID, curTransfer.nValue - fees, fees, curTransfer.destination);
-
-                        newOut = MakeCC1of1Vout(EVAL_RESERVE_TRANSFER, 0, pk, dests, rt);
-                        totalReserveOut += curTransfer.nValue;
-                        printf("%s: Outputting reserve to send back %s\n", __func__, rt.ToUniValue().write().c_str());
-                        LogPrintf("%s: Outputting reserve to send back %s\n", __func__, rt.ToUniValue().write().c_str());
-                    }
-                    else
-                    {
-                        // if Verus is active, we are creating a reserve import for a PBaaS reserve chain
-                        if (isVerusActive)
-                        {
-                            // generate a reserve output of the amount indicated, less fees
-                            // emit a reserve exchange output
-                            // we will send using a reserve output, fee will be paid by converting from reserve
-                            cp = CCinit(&CC, EVAL_RESERVE_OUTPUT);
-
-                            std::vector<CTxDestination> dests = std::vector<CTxDestination>({CTxDestination(curTransfer.destination)});
-                            CReserveOutput ro = CReserveOutput(CReserveExchange::VALID, curTransfer.nValue);
-
-                            newOut = MakeCC0of0Vout(EVAL_RESERVE_OUTPUT, 0, dests, ro);
-                            totalReserveOut += curTransfer.nValue;
-                            printf("%s: Outputting reserve import from Verus chain %s\n", __func__, ro.ToUniValue().write().c_str());
-                            LogPrintf("%s: Outputting reserve import from Verus chain %s\n", __func__, ro.ToUniValue().write().c_str());
-                        }
-                        else
-                        {
-                            // we are creating an import for the Verus chain to spend from a PBaaS account of a reserve currency, move the value specified, which will spend from
-                            // the RESERVE_DEPOSIT outputs
-                            newOut = CTxOut(curTransfer.nValue, GetScriptForDestination(curTransfer.destination));
-                            totalNativeOut += newOut.nValue;
-                            printf("%s: Outputting reserve import back to Verus chain %s\n", __func__, curTransfer.ToUniValue().write().c_str());
-                            LogPrintf("%s: Outputting reserve import back to Verus chain %s\n", __func__, curTransfer.ToUniValue().write().c_str());
-                        }
-                    }
-                    newImportTx.vout.push_back(newOut);
-                }
-                else
-                {
-                    printf("%s: Invalid reserve transfer on export\n", __func__);
-                    LogPrintf("%s: Invalid reserve transfer on export\n", __func__);
-                }
+            if (!rtxd.AddReserveTransferImportOutputs(chainDef, exportOutputs, newImportTx.vout))
+            {
+                LogPrintf("%s: POSSIBLE CORRUPTION bad export opret in transaction %s\n", __func__, aixIt->second.second.GetHash().GetHex().c_str());
+                printf("%s: POSSIBLE CORRUPTION bad export opret in transaction %s\n", __func__, aixIt->second.second.GetHash().GetHex().c_str());
+                // free the memory
+                DeleteOpRetObjects(exportOutputs);
+                return false;
             }
 
             // free the memory
@@ -551,16 +457,16 @@ bool CConnectedChains::CreateLatestImports(const CPBaaSChainDefinition &chainDef
 
             pk = CPubKey(ParseHex(CC.CChexstr));
 
-            if (totalImport + importFees != ccx.totalAmount + ccx.totalFees)
+            if (rtxd.ReserveFees() != (ccx.totalFees - exportFees))
             {
-                LogPrintf("%s: ERROR - import does not match amount, totalImport=%lu, importFees=%lu, ccx.totalAmount=%lu, ccx.totalFees=%lu\n", __func__, totalImport, importFees, ccx.totalAmount, ccx.totalFees);
-                printf("%s: ERROR - import does not match amount, totalImport=%lu, importFees=%lu, ccx.totalAmount=%lu, ccx.totalFees=%lu\n", __func__, totalImport, importFees, ccx.totalAmount, ccx.totalFees);
+                LogPrintf("%s: ERROR - import does not match amount, totalImport=%lu, importFees=%lu, ccx.totalAmount=%lu, ccx.totalFees=%lu\n", __func__, ccx.totalAmount + ccx.totalFees, importFees, ccx.totalAmount, ccx.totalFees);
+                printf("%s: ERROR - import does not match amount, totalImport=%lu, importFees=%lu, ccx.totalAmount=%lu, ccx.totalFees=%lu\n", __func__, ccx.totalAmount + ccx.totalFees, importFees, ccx.totalAmount, ccx.totalFees);
             }
 
             std::vector<CTxDestination> dests = std::vector<CTxDestination>({CTxDestination(CKeyID(CCrossChainRPCData::GetConditionID(ConnectedChains.ThisChain().GetChainID(), EVAL_CROSSCHAIN_IMPORT)))});
             CCrossChainImport cci = CCrossChainImport(ConnectedChains.ThisChain().GetChainID(), ccx.totalAmount + ccx.totalFees);
 
-            newImportTx.vout[0] = MakeCC1of1Vout(EVAL_CROSSCHAIN_IMPORT, availableNative - totalNativeOut, pk, dests, cci);
+            newImportTx.vout[0] = MakeCC1of1Vout(EVAL_CROSSCHAIN_IMPORT, availableNative - rtxd.nativeIn, pk, dests, cci);
 
             if (newImportTx.vout[0].nValue < 0)
             {
This page took 0.049927 seconds and 4 git commands to generate.