]> Git Repo - VerusCoin.git/commitdiff
Cross chain PBaaS autonotarization
authormiketout <[email protected]>
Tue, 2 Mar 2021 00:18:54 +0000 (16:18 -0800)
committermiketout <[email protected]>
Tue, 2 Mar 2021 00:18:54 +0000 (16:18 -0800)
src/miner.cpp
src/pbaas/crosschainrpc.h
src/pbaas/notarization.cpp
src/pbaas/notarization.h
src/pbaas/pbaas.cpp
src/pbaas/reserves.cpp
src/pbaas/reserves.h
src/rpc/client.cpp
src/rpc/pbaasrpc.cpp

index bc93177ae4b89c6327de3231cf58ad6454300432..2051bc022318db838e46f8d0090bce36d078c314 100644 (file)
@@ -1308,6 +1308,19 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const std::vecto
             currencyState = launchNotarization.currencyState;
         }
 
+        // if we are a notary, notarize
+        if (!VERUS_NOTARYID.IsNull())
+        {
+            CValidationState state;
+            TransactionBuilder notarizationBuilder = TransactionBuilder(consensusParams, nHeight);
+            bool finalized;
+            if (CPBaaSNotarization::ConfirmOrRejectNotarizations(pwalletMain, ConnectedChains.FirstNotaryChain(), state, notarizationBuilder, finalized))
+            {
+                TransactionBuilderResult buildResult = notarizationBuilder.Build();
+
+            }
+        }
+
         if (notaryConnected)
         {
             // if we should make an earned notarization, do so
@@ -1333,6 +1346,8 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const std::vecto
                 }
                 CPBaaSNotarization lastImportNotarization;
                 CUTXORef lastImportNotarizationUTXO;
+
+                CPBaaSNotarization::SubmitFinalizedNotarizations(ConnectedChains.FirstNotaryChain(), state);
                 ProcessNewImports(ConnectedChains.FirstNotaryChain().chainDefinition.GetID(), lastImportNotarization, lastImportNotarizationUTXO, nHeight);
             }
         }
index b19d6b3dfc4cf859f12e47f9dbc930e9cb2b7ed0..0d8df94d18c8035ccc89e22c5b7b7a7409639838 100644 (file)
@@ -980,6 +980,8 @@ public:
         return !systemID.IsNull() && !stateRoot.IsNull() && !blockHash.IsNull();
     }
 
+    friend bool operator==(const CProofRoot &op1, const CProofRoot &op2);
+
     UniValue ToUniValue() const;
 };
 
index d1daa8b83bd91521ed323642930e9f42ea0b2d74..ee19fca2e69eb575b1b18649c13e22bafcba8bfd 100644 (file)
@@ -293,6 +293,17 @@ CPBaaSNotarization::CPBaaSNotarization(const UniValue &obj)
     }
 }
 
+bool operator==(const CProofRoot &op1, const CProofRoot &op2)
+{
+    return op1.version == op2.version &&
+           op1.type == op2.type &&
+           op1.rootHeight == op2.rootHeight &&
+           op1.stateRoot == op2.stateRoot &&
+           op1.systemID == op2.systemID &&
+           op1.blockHash == op2.blockHash &&
+           op1.compactPower == op2.compactPower;
+}
+
 CProofRoot CProofRoot::GetProofRoot(uint32_t blockHeight)
 {
     if (blockHeight > chainActive.Height())
@@ -1540,6 +1551,156 @@ bool CPBaaSNotarization::ConfirmOrRejectNotarizations(const CWallet *pWallet,
     return retVal;
 }
 
+bool CallNotary(const CRPCChainData &notarySystem, std::string command, const UniValue &params, UniValue &result, UniValue &error);
+
+// look for finalized notarizations either on chain or in the mempool, which are eligible for submission
+// and submit them to the notary chain.
+std::vector<uint256> CPBaaSNotarization::SubmitFinalizedNotarizations(const CRPCChainData &externalSystem,
+                                                                      CValidationState &state)
+{
+    // look for finalized notarizations for our notary chains in recent blocks
+    // if we find any and are connected, submit them
+    std::vector<CAddressIndexDbEntry> finalizedNotarizations;
+    uint160 systemID = externalSystem.chainDefinition.GetID();
+    std::vector<std::pair<CPBaaSNotarization, CNotaryEvidence>> notarizations;
+
+    {
+        LOCK2(cs_main, mempool.cs);
+
+        uint32_t nHeight = chainActive.Height();
+        uint160 finalizeConfirmedKey = 
+            CCrossChainRPCData::GetConditionID(
+                CCrossChainRPCData::GetConditionID(systemID, CObjectFinalization::ObjectFinalizationNotarizationKey()), 
+                CObjectFinalization::ObjectFinalizationConfirmedKey());
+
+        if (GetAddressIndex(finalizeConfirmedKey, CScript::P2IDX, finalizedNotarizations, nHeight-10) && finalizedNotarizations.size())
+        {
+            // get the recent finalized notarizations and submit. the daemon we submit to may early out immediately if
+            // the notarization is already posted or in mempool
+            for (auto &oneFinalization : finalizedNotarizations)
+            {
+                if (oneFinalization.first.spending)
+                {
+                    continue;
+                }
+                // now, we have a finalized notarization for the target network
+                // prepare an accepted notarization and submit
+                CTransaction finTx, nTx;
+                uint256 blkHash;
+                COptCCParams p;
+                CObjectFinalization of;
+                CPBaaSNotarization pbn;
+                if (!myGetTransaction(oneFinalization.first.txhash, finTx, blkHash))
+                {
+                    // set error, but continue processing
+                    state.Error("inaccessible-transaction");
+                }
+                if (!(finTx.vout.size() > oneFinalization.first.index &&
+                      finTx.vout[oneFinalization.first.index].scriptPubKey.IsPayToCryptoCondition(p) &&
+                      p.IsValid() &&
+                      (p.evalCode == EVAL_FINALIZE_NOTARIZATION) &&
+                      p.vData.size() &&
+                      (of = CObjectFinalization(p.vData[0])).IsValid() &&
+                      of.GetOutputTransaction(finTx, nTx, blkHash) &&
+                      nTx.vout.size() > of.output.n &&
+                      nTx.vout[of.output.n].scriptPubKey.IsPayToCryptoCondition(p) &&
+                      p.IsValid() &&
+                      p.evalCode == EVAL_EARNEDNOTARIZATION &&
+                      p.vData.size() &&
+                      (pbn = CPBaaSNotarization(p.vData[0])).IsValid()))
+                {
+                    // this is almost certainly a corrupt local database, so we will start to return errors
+                    // rather than attempt to continue
+                    state.Error("invalid-or-corrupt-notarization");
+                    return std::vector<uint256>();
+                }
+
+                // get all notarization evidence and submit the notarization + evidence
+                CNotaryEvidence allEvidence, scratchEvidence;
+
+                // get all inputs with evidence and add it to our evidence
+                for (auto &oneEvidenceIn : of.evidenceInputs)
+                {
+                    CTransaction evidenceTx;
+                    uint256 eBlkHash;
+                    COptCCParams eP;
+                    if (!(finTx.vin.size() > oneEvidenceIn &&
+                          myGetTransaction(finTx.vin[oneEvidenceIn].prevout.hash, evidenceTx, eBlkHash) &&
+                          evidenceTx.vout.size() > finTx.vin[oneEvidenceIn].prevout.n &&
+                          evidenceTx.vout[finTx.vin[oneEvidenceIn].prevout.n].scriptPubKey.IsPayToCryptoCondition(eP) &&
+                          eP.IsValid() &&
+                          eP.evalCode == EVAL_NOTARY_EVIDENCE &&
+                          eP.vData.size() &&
+                          (scratchEvidence = CNotaryEvidence(eP.vData[0])).IsValid()))
+                    {
+                        state.Error("innaccessible-evidence");
+                        return std::vector<uint256>();
+                    }
+                    allEvidence.evidence.insert(allEvidence.evidence.end(), scratchEvidence.evidence.begin(), scratchEvidence.evidence.end());
+                    for (auto &oneSig : scratchEvidence.signatures)
+                    {
+                        if (oneSig.second.signatures.size())
+                        {
+                            for (auto &oneSigEntry : oneSig.second.signatures)
+                            {
+                                allEvidence.signatures[oneSig.first].signatures.insert(oneSigEntry);
+                            }
+                        }
+                    }
+                }
+                // get all outputs with evidence and add
+                for (auto oneEvidenceOut : of.evidenceOutputs)
+                {
+                    if (!(finTx.vout.size() > oneEvidenceOut &&
+                        finTx.vout[oneEvidenceOut].scriptPubKey.IsPayToCryptoCondition(p) &&
+                        p.IsValid() &&
+                        (p.evalCode == EVAL_NOTARY_EVIDENCE) &&
+                        p.vData.size() &&
+                        (scratchEvidence = CNotaryEvidence(p.vData[0])).IsValid()))
+                    {
+                        state.Error("invalid-evidence");
+                        return std::vector<uint256>();
+                    }
+                    allEvidence.evidence.insert(allEvidence.evidence.end(), scratchEvidence.evidence.begin(), scratchEvidence.evidence.end());
+                    for (auto &oneSig : scratchEvidence.signatures)
+                    {
+                        if (oneSig.second.signatures.size())
+                        {
+                            for (auto &oneSigEntry : oneSig.second.signatures)
+                            {
+                                allEvidence.signatures[oneSig.first].signatures.insert(oneSigEntry);
+                            }
+                        }
+                    }
+                }
+                notarizations.push_back(std::make_pair(pbn, allEvidence));
+            }
+        }
+    }
+
+    std::vector<uint256> retVal;
+    // collect them holding the lock, release it, then call out
+    for (auto &oneNotarization : notarizations)
+    {
+        // now, we should have enough evidence to prove
+        // the notarization. the API call will ensure that we do
+        UniValue params(UniValue::VARR);
+        UniValue result, error;
+        std::string strTxId;
+        params.push_back(oneNotarization.first.ToUniValue());
+        params.push_back(oneNotarization.second.ToUniValue());
+        if (!CallNotary(externalSystem, "submitacceptednotarization", params, result, error) ||
+            !error.isNull() ||
+            (strTxId = uni_get_str(result)).empty() ||
+            !IsHex(strTxId))
+        {
+            continue;
+        }
+        // store the transaction ID and accepted notariation to prevent redundant submits
+        retVal.push_back(uint256S(strTxId));
+    }
+    return retVal;
+}
 
 /*
  * Validates a notarization output spend by ensuring that the spending transaction fulfills all requirements.
index 0a25e5a4c37cbf13b5cb6508909735cea1e9b68b..67d6b978daa1baa79981a4fbb68a295b7c10fdb7 100644 (file)
@@ -283,6 +283,9 @@ public:
                                              TransactionBuilder &txBuilder,
                                              bool &finalized);
 
+    static std::vector<uint256> SubmitFinalizedNotarizations(const CRPCChainData &externalSystem,
+                                                             CValidationState &state);
+
     bool CheckProof(const uint160 &systemID, const CMMRProof &transactionBlockProof, uint256 checkHash)
     {
         auto proofRootIt = proofRoots.find(systemID);
index eb108cddbb262a04294aa4253f3da8295e9bb827..2ce7391afa4ab07e92ba49daaee90e6f731b5edd 100644 (file)
@@ -3747,6 +3747,7 @@ void CConnectedChains::SubmissionThread()
                     sem_submitthread.wait();
                 }
             }
+
             // if this is a PBaaS chain, poll for presence of Verus / root chain and current Verus block and version number
             if (IsNotaryAvailable())
             {
index 91b95925ba06d6e9dc726aed23d83833da9e3d0f..e2ff8de75ab126120412bf0dafde748392ce8b63 100644 (file)
@@ -3345,460 +3345,6 @@ void CCoinbaseCurrencyState::RevertReservesAndSupply()
     ClearForNextBlock();
 }
 
-// From a vector of transaction pointers, match all that are valid orders and can be matched,
-// put them into a vector of reserve transaction descriptors, and return a new fractional reserve state,
-// if pConversionTx is present, this will add one output to it for each transaction included
-// and consider its size wen comparing to maxSerializeSize
-CCoinbaseCurrencyState CCoinbaseCurrencyState::MatchOrders(const std::vector<CReserveTransactionDescriptor> &orders, 
-                                                           std::vector<CReserveTransactionDescriptor> &reserveFills, 
-                                                           std::vector<CReserveTransactionDescriptor> &noFills, 
-                                                           std::vector<const CReserveTransactionDescriptor *> &expiredFillOrKills, 
-                                                           std::vector<const CReserveTransactionDescriptor *> &rejects, 
-                                                           std::vector<CAmount> &prices,
-                                                           int32_t height, std::vector<CInputDescriptor> &conversionInputs,
-                                                           int64_t maxSerializeSize, int64_t *pInOutTotalSerializeSize, CMutableTransaction *pConversionTx,
-                                                           bool feesAsReserve) const
-{
-    // synthetic order book of limitBuys and limitSells sorted by limit, order of preference beyond limit sorting is random
-    std::map<uint160, std::multimap<CAmount, CReserveTransactionDescriptor>> limitBuys;
-    std::map<uint160, std::multimap<CAmount, CReserveTransactionDescriptor>> limitSells;        // limit orders are prioritized by limit
-    std::multimap<CAmount, CReserveTransactionDescriptor> marketOrders;      // prioritized by fee rate
-    CAmount totalNativeConversionFees = 0;
-    CCurrencyValueMap totalReserveConversionFees;
-    std::vector<CAmount> exchangeRates(PricesInReserve());
-    CCurrencyValueMap exchangeRateMap = CCurrencyValueMap(currencies, exchangeRates);
-
-    CMutableTransaction mConversionTx = pConversionTx ? *pConversionTx : CMutableTransaction();
-    std::vector<CInputDescriptor> tmpConversionInputs(conversionInputs);
-
-    int64_t totalSerializedSize = pInOutTotalSerializeSize ? *pInOutTotalSerializeSize + CCurrencyState::CONVERSION_TX_SIZE_MIN : CCurrencyState::CONVERSION_TX_SIZE_MIN;
-    int64_t conversionSizeOverhead = 0;
-
-    if (!(flags & FLAG_FRACTIONAL))
-    {
-        return CCoinbaseCurrencyState();
-    }
-
-    uint32_t tipTime = (chainActive.Height() >= height) ? chainActive[height]->nTime : chainActive.LastTip()->nTime;
-    CCoinsViewCache view(pcoinsTip);
-
-    // organize all valid reserve exchange transactions into multimaps, limitBuys, limitSells, and market orders
-    // orders that should be treated as normal/failed fill or kill will go into refunds and invalid transactions into rejects
-    for (int i = 0; i < orders.size(); i++)
-    {
-        if (orders[i].IsValid() && orders[i].IsReserveExchange())
-        {
-            // if this is a market order, put it in, if limit, put it in an order book, sorted by limit
-            if (orders[i].IsMarket())
-            {
-                CAmount fee = orders[i].AllFeesAsNative(*this) + ReserveToNative(orders[i].ReserveConversionFeesMap()) + orders[i].nativeConversionFees;
-                CFeeRate feeRate = CFeeRate(fee, GetSerializeSize(CDataStream(SER_NETWORK, PROTOCOL_VERSION), *orders[i].ptx));
-                marketOrders.insert(std::make_pair(feeRate.GetFeePerK(), orders[i]));
-            }
-            else
-            {
-                assert(orders[i].IsLimit());
-                // limit order, so put it in buy or sell
-                if (orders[i].numBuys)
-                {
-                    limitBuys[orders[i].vRex[0].second.FirstCurrency()].insert(std::make_pair(orders[i].vRex[0].second.nLimit, orders[i]));
-                }
-                else
-                {
-                    assert(orders[i].numSells);
-                    limitSells[orders[i].vRex[0].second.FirstCurrency()].insert(std::make_pair(orders[i].vRex[0].second.nLimit, orders[i]));
-                }
-            }
-        }
-        else if (orders[i].IsValid())
-        {
-            expiredFillOrKills.push_back(&(orders[i]));
-        }
-        else
-        {
-            rejects.push_back(&(orders[i]));
-        }
-    }
-
-    // now we have all market orders in marketOrders multimap, sorted by feePerK, rejects that are expired or invalid in rejects
-    // first, prune as many market orders as possible up to the maximum storage space available for market orders, which we calculate
-    // as a functoin of the total space available and precentage of total orders that are market orders
-    int64_t numLimitOrders = limitBuys.size() + limitSells.size();
-    int64_t numMarketOrders = marketOrders.size();
-
-    // if nothing to do, we are done, don't update anything
-    if (!(reserveFills.size() + numLimitOrders + numMarketOrders))
-    {
-        return *this;
-    }
-
-    // 1. start from the current state and calculate what the price would be with market orders that fit, leaving room for limit orders
-    // 2. add limit orders, first buys, as many as we can from the highest value and number downward, one at a time, until we run out or
-    //    cannot add any more due to not meeting the price. then we do the same for sells if there are any available, and alternate until
-    //    we either run out or cannot add from either side. within a specific limit, orders are sorted by largest first, which means
-    //    there is no point in retracing if an element fails to be added
-    // 3. calculate a final order price
-    // 4. create and return a new, updated CCoinbaseCurrencyState
-    CCoinbaseCurrencyState newState(*(CCurrencyState *)this);
-
-    conversionSizeOverhead = GetSerializeSize(mConversionTx, SER_NETWORK, PROTOCOL_VERSION);
-
-    int64_t curSpace = maxSerializeSize - (totalSerializedSize + conversionSizeOverhead);
-
-    if (curSpace < 0)
-    {
-        printf("%s: no space available in block to include reserve orders\n", __func__);
-        LogPrintf("%s: no space available in block to include reserve orders\n", __func__);
-        return *this;
-    }
-
-    // the ones that are passed in reserveFills may be any valid reserve related transaction
-    // we need to first process those with the assumption that they are included
-    for (auto it = reserveFills.begin(); it != reserveFills.end(); )
-    {
-        auto &txDesc = *it;
-
-        // add up the starting point for conversions
-        if (txDesc.IsReserveExchange())
-        {
-            CMutableTransaction mtx;
-            mtx = mConversionTx;
-            txDesc.AddConversionInOuts(mtx, tmpConversionInputs, exchangeRateMap);
-            conversionSizeOverhead = GetSerializeSize(mtx, SER_NETWORK, PROTOCOL_VERSION);
-            int64_t tmpSpace = maxSerializeSize - (totalSerializedSize + conversionSizeOverhead);
-
-            if (tmpSpace < 0)
-            {
-                // can't fit, so it's a noFill
-                noFills.push_back(txDesc);
-                it = reserveFills.erase(it);
-            }
-            else
-            {
-                curSpace = tmpSpace;
-
-                totalNativeConversionFees += txDesc.nativeConversionFees;
-                totalReserveConversionFees += txDesc.ReserveConversionFeesMap();
-
-                if (feesAsReserve)
-                {
-                    newState.reserveIn = AddVectors(txDesc.ReserveOutConvertedVec(*this), newState.reserveIn);
-                    newState.nativeIn = AddVectors(txDesc.NativeOutConvertedVec(*this), newState.nativeIn);
-                    newState.nativeIn[0] += txDesc.NativeFees() + txDesc.nativeConversionFees;
-                }
-                else
-                {
-                    newState.reserveIn = AddVectors(
-                                            AddVectors(txDesc.ReserveOutConvertedVec(*this), newState.reserveIn),
-                                            AddVectors(txDesc.ReserveFees().AsCurrencyVector(currencies), txDesc.ReserveConversionFeesVec(*this))
-                                         );
-                    newState.nativeIn = AddVectors(txDesc.NativeOutConvertedVec(*this), newState.nativeIn);
-                }
-
-                mConversionTx = mtx;
-                it++;
-            }
-        }
-        else
-        {
-            if (feesAsReserve && newState.nativeIn.size())
-            {
-                newState.nativeIn[0] += txDesc.NativeFees();
-            }
-            else
-            {
-                newState.reserveIn = AddVectors(newState.reserveIn, txDesc.ReserveFees().AsCurrencyVector(currencies));
-            }
-            it++;
-        }
-    }
-
-    int64_t marketOrdersSizeLimit = curSpace;
-    int64_t limitOrdersSizeLimit = curSpace;
-    if (numLimitOrders + numMarketOrders)
-    {
-        marketOrdersSizeLimit = ((arith_uint256(numMarketOrders) * arith_uint256(curSpace)) / arith_uint256(numLimitOrders + numMarketOrders)).GetLow64();
-        limitOrdersSizeLimit = curSpace - marketOrdersSizeLimit;
-    }
-    
-    if (limitOrdersSizeLimit < 1024 && maxSerializeSize > 2048)
-    {
-        marketOrdersSizeLimit = maxSerializeSize - 1024;
-        limitOrdersSizeLimit = 1024;
-    }
-
-    for (auto marketOrder : marketOrders)
-    {
-        // add as many as we can fit, if we are able to, consider the output transaction overhead as well
-        int64_t thisSerializeSize = GetSerializeSize(*marketOrder.second.ptx, SER_NETWORK, PROTOCOL_VERSION);
-        CMutableTransaction mtx;
-        mtx = mConversionTx;
-        marketOrder.second.AddConversionInOuts(mtx, tmpConversionInputs, exchangeRateMap);
-        conversionSizeOverhead = GetSerializeSize(mtx, SER_NETWORK, PROTOCOL_VERSION);
-        if ((totalSerializedSize + thisSerializeSize + conversionSizeOverhead) <= marketOrdersSizeLimit)
-        {
-            totalNativeConversionFees += marketOrder.second.nativeConversionFees;
-            totalReserveConversionFees += marketOrder.second.ReserveConversionFeesMap();
-            mConversionTx = mtx;
-
-            if (feesAsReserve)
-            {
-                newState.reserveIn = AddVectors(marketOrder.second.ReserveOutConvertedVec(*this), newState.reserveIn);
-                newState.nativeIn = AddVectors(marketOrder.second.NativeOutConvertedVec(*this), newState.nativeIn);
-                newState.nativeIn[0] += marketOrder.second.NativeFees() + marketOrder.second.nativeConversionFees;
-            }
-            else
-            {
-                newState.reserveIn = AddVectors(
-                                        AddVectors(marketOrder.second.ReserveOutConvertedVec(*this), newState.reserveIn),
-                                        AddVectors(marketOrder.second.ReserveFees().AsCurrencyVector(currencies), marketOrder.second.ReserveConversionFeesVec(*this))
-                                        );
-                newState.nativeIn = AddVectors(marketOrder.second.NativeOutConvertedVec(*this), newState.nativeIn);
-            }
-
-            reserveFills.push_back(marketOrder.second);
-            totalSerializedSize += thisSerializeSize;
-        }
-        else
-        {
-            // can't fit, no fill
-            noFills.push_back(marketOrder.second);
-        }
-    }
-
-    // iteratively add limit orders first buy, then sell, until we no longer have anything to add
-    // this must iterate because each time we add a buy, it may put another sell's limit within reach and
-    // vice versa
-    std::map<uint160, std::pair<std::multimap<CAmount, CReserveTransactionDescriptor>::iterator, CAmount>> buyPartial; // valid in loop for partial fill
-    std::map<uint160, std::pair<std::multimap<CAmount, CReserveTransactionDescriptor>::iterator, CAmount>> sellPartial;
-
-    limitOrdersSizeLimit = maxSerializeSize - totalSerializedSize;
-    int64_t buyLimitSizeLimit = numLimitOrders ? totalSerializedSize + ((arith_uint256(limitBuys.size()) * arith_uint256(limitOrdersSizeLimit)) / arith_uint256(numLimitOrders)).GetLow64() : limitOrdersSizeLimit;
-
-    CCurrencyState latestState = newState;
-
-    // TODO - finish limit orders, which are significantly more complex after moving to
-    // multi-reserves. until then, skip limit orders.
-    /*
-    for (bool tryagain = true; tryagain; )
-    {
-        tryagain = false;
-
-        exchangeRates = ConvertAmounts(newState.reserveIn, newState.nativeIn, latestState);
-
-        // starting with that exchange rate, add buys one at a time until we run out of buys to add or reach the limit,
-        // possibly in a partial fill, then see if we can add any sells. we go back and forth until we have stopped being able to add
-        // new orders. it would be possible to recognize a state where we are able to simultaneously fill a buy and a sell that are
-        // the the same or very minimally overlapping limits
-        
-        for (auto limitBuysIt = limitBuys.rbegin(); limitBuysIt != limitBuys.rend() && exchangeRate > limitBuysIt->second.vRex.front().second.nLimit; limitBuysIt = limitBuys.rend())
-        {
-            // any time there are entries above the lower bound, we only actually look at the end, since we mutate the
-            // search space each iteration and remove anything we've already added, making the end always the most in-the-money
-            CReserveTransactionDescriptor &currentBuy = limitBuysIt->second;
-
-            // it must first fit, space-wise
-            int64_t thisSerializeSize = GetSerializeSize(*(currentBuy.ptx), SER_NETWORK, PROTOCOL_VERSION);
-
-            CMutableTransaction mtx;
-            if (pConversionTx)
-            {
-                mtx = *pConversionTx;
-                currentBuy.AddConversionInOuts(mtx, tmpConversionInputs);
-                conversionSizeOverhead = GetSerializeSize(mtx, SER_NETWORK, PROTOCOL_VERSION);
-            }
-            if ((totalSerializedSize + thisSerializeSize + conversionSizeOverhead) <= buyLimitSizeLimit)
-            {
-                CAmount newReserveIn, newNativeIn;
-                if (feesAsReserve)
-                {
-                    newReserveIn = currentBuy.reserveOutConverted;
-                    newNativeIn = currentBuy.nativeOutConverted + currentBuy.NativeFees() + currentBuy.nativeConversionFees;
-                }
-                else
-                {
-                    newReserveIn = currentBuy.reserveOutConverted + currentBuy.ReserveFees() + currentBuy.reserveConversionFees;
-                    newNativeIn = currentBuy.nativeOutConverted;
-                }
-
-                // calculate fresh with all conversions together to see if we still meet the limit
-                CAmount newExchange = ConvertAmounts(newState.ReserveIn + newReserveIn, newState.NativeIn + newNativeIn, latestState);
-
-                if (newExchange <= currentBuy.vRex[0].second.nLimit)
-                {
-                    totalNativeConversionFees += currentBuy.nativeConversionFees;
-                    totalReserveConversionFees += currentBuy.reserveConversionFees;
-
-                    // update conversion transaction if we have one
-                    if (pConversionTx)
-                    {
-                        *pConversionTx = mtx;
-                    }
-
-                    // add to the current buys, we will never do something to disqualify this, since all orders left are either
-                    // the same limit or lower
-                    reserveFills.push_back(currentBuy);
-                    totalSerializedSize += thisSerializeSize;
-
-                    newState.ReserveIn += newReserveIn;
-                    newState.NativeIn += newNativeIn;
-
-                    exchangeRate = newExchange;
-                    limitBuys.erase(--limitBuys.end());
-                }
-                else
-                {
-                    // TODO:PBAAS support partial fills
-                    break;
-                }
-            }
-        }
-
-        // now, iterate from lowest/most qualified sell limit first to highest/least qualified and attempt to put all in
-        // if we can only fill an order partially, then do so
-        for (auto limitSellsIt = limitSells.begin(); limitSellsIt != limitSells.end() && exchangeRate > limitSellsIt->second.vRex.front().second.nLimit; limitSellsIt = limitSells.begin())
-        {
-            CReserveTransactionDescriptor &currentSell = limitSellsIt->second;
-
-            int64_t thisSerializeSize = GetSerializeSize(*currentSell.ptx, SER_NETWORK, PROTOCOL_VERSION);
-
-            CMutableTransaction mtx;
-            if (pConversionTx)
-            {
-                mtx = *pConversionTx;
-                currentSell.AddConversionInOuts(mtx, tmpConversionInputs);
-                conversionSizeOverhead = GetSerializeSize(mtx, SER_NETWORK, PROTOCOL_VERSION);
-            }
-
-            if ((totalSerializedSize + thisSerializeSize + conversionSizeOverhead) <= maxSerializeSize)
-            {
-                CAmount newReserveIn, newNativeIn;
-                if (feesAsReserve)
-                {
-                    newReserveIn = currentSell.reserveOutConverted;
-                    newNativeIn = currentSell.nativeOutConverted + currentSell.NativeFees() + currentSell.nativeConversionFees;
-                }
-                else
-                {
-                    newReserveIn = currentSell.reserveOutConverted + currentSell.ReserveFees() + currentSell.reserveConversionFees;
-                    newNativeIn = currentSell.nativeOutConverted;
-                }
-
-                // calculate fresh with all conversions together to see if we still meet the limit
-                CAmount newExchange = ConvertAmounts(newState.ReserveIn + newReserveIn, newState.NativeIn + newNativeIn, latestState);
-                if (newExchange >= currentSell.vRex.front().second.nLimit)
-                {
-                    totalNativeConversionFees += currentSell.nativeConversionFees;
-                    totalReserveConversionFees += currentSell.reserveConversionFees;
-
-                    // update conversion transaction if we have one
-                    if (pConversionTx)
-                    {
-                        *pConversionTx = mtx;
-                    }
-
-                    // add to the current sells, we will never do something to disqualify this, since all orders left are either
-                    // the same limit or higher
-                    reserveFills.push_back(currentSell);
-                    totalSerializedSize += thisSerializeSize;
-                    exchangeRate = newExchange;
-
-                    newState.ReserveIn += newReserveIn;
-                    newState.NativeIn += newNativeIn;
-
-                    limitSells.erase(limitSellsIt);
-                    tryagain = true;
-                }
-                else
-                {
-                    // we must be done with buys whether we created a partial or not
-                    break;
-                }
-            }
-        }
-        buyLimitSizeLimit = maxSerializeSize - totalSerializedSize;
-    }
-    */
-
-    // we can calculate total fees now, but to avoid a rounding error when converting native to reserve or vice versa on fees, 
-    // we must loop through once more to calculate all fees for the currency state
-    auto curMap = GetReserveMap();
-    CCurrencyValueMap totalReserveFees;
-    CAmount totalNativeFees = 0;
-    CCurrencyValueMap reserveOutVal;
-    CMutableTransaction mtx = pConversionTx ? *pConversionTx : CMutableTransaction();
-    for (auto fill : reserveFills)
-    {
-        fill.AddConversionInOuts(mtx, conversionInputs, exchangeRateMap);
-        reserveOutVal += NativeToReserveRaw(fill.NativeOutConvertedVec(latestState), exchangeRates);
-        if (feesAsReserve)
-        {
-            totalReserveFees += fill.AllFeesAsReserve(newState, exchangeRates);
-        }
-        else
-        {
-            totalNativeFees += fill.AllFeesAsNative(newState, exchangeRates);
-        }
-    }
-    if (pConversionTx)
-    {
-        *pConversionTx = mtx;
-    }
-    if (feesAsReserve)
-    {
-        totalReserveConversionFees.valueMap[currencies[0]] += NativeToReserve(totalNativeConversionFees, exchangeRates[0]);
-        reserveOutVal += totalReserveConversionFees;
-        totalReserveFees += totalReserveConversionFees;
-    }
-    else
-    {
-        totalNativeConversionFees = totalNativeConversionFees + ReserveToNativeRaw(totalReserveConversionFees, exchangeRates);
-        totalNativeFees += totalNativeConversionFees;
-    }
-
-    newState = CCoinbaseCurrencyState(latestState, 0,
-                                      totalNativeFees, totalNativeConversionFees,
-                                      newState.reserveIn,
-                                      newState.nativeIn,
-                                      newState.reserveOut, 
-                                      exchangeRates, 
-                                      totalReserveFees.AsCurrencyVector(currencies), 
-                                      totalReserveConversionFees.AsCurrencyVector(currencies));
-
-    prices = exchangeRates;
-
-    for (auto &curBuys : limitBuys)
-    {
-        for (auto &entry : curBuys.second)
-        {
-            noFills.push_back(entry.second);
-        }
-    }
-
-    for (auto &curSells : limitSells)
-    {
-        for (auto &entry : curSells.second)
-        {
-            noFills.push_back(entry.second);
-        }
-    }
-
-    // if no matches, no state updates
-    if (!reserveFills.size())
-    {
-        return *this;
-    }
-    else
-    {
-        if (pInOutTotalSerializeSize)
-        {
-            *pInOutTotalSerializeSize = totalSerializedSize;
-        }
-        printf("%s: %s\n", __func__, newState.ToUniValue().write(1, 2).c_str());
-        return newState;
-    }
-}
-
 CAmount CCurrencyState::CalculateConversionFee(CAmount inputAmount, bool convertToNative, int currencyIndex) const
 {
     arith_uint256 bigAmount(inputAmount);
index 59f0465816b464545d40d2ff134133f9cc4d0689..2309d2e0e4f9148f09bad255280013335627c2ce 100644 (file)
@@ -1432,16 +1432,6 @@ public:
     // while leaving conversion prices the same
     void RevertReservesAndSupply();
 
-    CCoinbaseCurrencyState MatchOrders(const std::vector<CReserveTransactionDescriptor> &orders, 
-                                       std::vector<CReserveTransactionDescriptor> &reserveFills, 
-                                       std::vector<CReserveTransactionDescriptor> &noFills, 
-                                       std::vector<const CReserveTransactionDescriptor *> &expiredFillOrKills, 
-                                       std::vector<const CReserveTransactionDescriptor *> &rejects, 
-                                       std::vector<CAmount> &exchangeRates, 
-                                       int32_t height, std::vector<CInputDescriptor> &conversionInputs, 
-                                       int64_t maxSerializedSize=LONG_MAX, int64_t *ptotalSerializeSize=NULL, CMutableTransaction *pConversionTx=NULL,
-                                       bool feesAsReserve=false) const;
-    
     template <typename NUMBERVECTOR>
     NUMBERVECTOR AddVectors(const NUMBERVECTOR &a, const NUMBERVECTOR &b) const
     {
index adb70934b8d493f46aab74e141425c571d85d29e..7c2500118ccea9551dd74e09be2f38a8d086b094 100644 (file)
@@ -528,7 +528,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
     // crosschain
     { "assetchainproof", 1},
     { "crosschainproof", 1},
-    { "getproofroot", 2},
+    { "getbestproofroot", 0},
+    { "submitacceptednotarization", 0},
     { "height_MoM", 1},
     { "calc_MoM", 2},
     // pbaas
index 5c7bf538ce629f028d1549e55d6c4c9f072806bc..61cdd81c5bc5f86bed4af20825d25dd8ea2133e3 100644 (file)
@@ -1847,6 +1847,118 @@ UniValue getnotarizationdata(const UniValue& params, bool fHelp)
     }
 }
 
+UniValue getbestproofroot(const UniValue& params, bool fHelp)
+{
+    if (fHelp || params.size() != 1 || params[0].getKeys().size() < 2)
+    {
+        throw runtime_error(
+            "getbestproofroot '{\"proofroots\":[\"version\":n,\"type\":n,\"systemid\":\"currencyidorname\",\"height\":n,\n"
+            "                   \"stateroot\":\"hex\",\"blockhash\":\"hex\",\"power\":\"hex\"],\"lastconfirmed\":n}'\n"
+            "\nDetermines and returns the index of the best (most recent, valid, qualified) proof root in the list of proof roots,\n"
+            "and the most recent, valid proof root.\n"
+
+            "\nArguments\n"
+            "{\n"
+            "  \"proofroots\":                  (array, required/may be empty) ordered array of proof roots, indexed on return\n"
+            "  [\n"
+            "    {\n"
+            "      \"version\":n                (int, required) version of this proof root data structure\n"
+            "      \"type\":n                   (int, required) type of proof root (chain or system specific)\n"
+            "      \"systemid\":\"hexstr\"      (hexstr, required) system the proof root is for\n"
+            "      \"height\":n                 (uint32_t, required) height of this proof root\n"
+            "      \"stateroot\":\"hexstr\"     (hexstr, required) Merkle or merkle-style tree root for the specified block/sequence\n"
+            "      \"blockhash\":\"hexstr\"     (hexstr, required) hash identifier for the specified block/sequence\n"
+            "      \"power\":\"hexstr\"         (hexstr, required) work, stake, or combination of the two for most-work/most-power rule\n"
+            "    }\n"
+            "  .\n"
+            "  .\n"
+            "  .\n"
+            "  ]\n"
+            "  \"currencies\":[\"id1\"]         (array, optional) currencies to query for currency states\n"
+            "  \"lastconfirmed\":n              (int, required) index into the proof root array indicating the last confirmed root"
+            "}\n"
+
+            "\nResult:\n"
+            "\"bestproofrootindex\"             (int) index of best proof root not confirmed that is provided, confirmed index, or -1"
+            "\"latestproofroot\"                (object) latest valid proof root of chain"
+            "\"currencystates\"                 (int) currency states of target currency and published bridges"
+
+            "\nExamples:\n"
+            + HelpExampleCli("getbestproofroot", "\"{\"proofroots\":[\"version\":n,\"type\":n,\"systemid\":\"currencyidorname\",\"height\":n,\"stateroot\":\"hex\",\"blockhash\":\"hex\",\"power\":\"hex\"],\"lastconfirmed\":n}\"")
+            + HelpExampleRpc("getbestproofroot", "\"{\"proofroots\":[\"version\":n,\"type\":n,\"systemid\":\"currencyidorname\",\"height\":n,\"stateroot\":\"hex\",\"blockhash\":\"hex\",\"power\":\"hex\"],\"lastconfirmed\":n}\"")
+        );
+    }
+
+    CheckPBaaSAPIsValid();
+
+    std::vector<std::string> paramKeys = params[0].getKeys();
+    UniValue currenciesUni;
+    if (paramKeys.size() > 3 ||
+        (paramKeys.size() == 3) && !(currenciesUni = find_value(params[0], "currencies")).isArray())
+    {
+        throw JSONRPCError(RPC_INVALID_PARAMETER, "too many members in object or invalid currencies array");
+    }
+
+    int lastConfirmed = uni_get_int(find_value(params[0], "lastconfirmed"), -1);
+    if (lastConfirmed == -1)
+    {
+        throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid lastconfirmed");
+    }
+
+    std::vector<CProofRoot> proofRootArr;
+    UniValue uniProofRoots = find_value(params[0], "proofroots");
+    if (!uniProofRoots.isArray())
+    {
+        throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid proof root array parameter");
+    }
+
+    LOCK(cs_main);
+
+    uint32_t nHeight = chainActive.Height();
+
+    uint32_t curHeight = 0;
+    std::map<uint32_t, int32_t> validRoots;       // height, index (only return the first valid at each height)
+    for (int i = 0; i < proofRootArr.size(); i++)
+    {
+        CProofRoot checkRoot = CProofRoot(proofRootArr[i]);
+        // proof roots must be valid and in height order, though heights can overlap
+        if (!checkRoot.IsValid() ||
+            checkRoot.rootHeight < curHeight ||
+            checkRoot.systemID != ASSETCHAINS_CHAINID)
+        {
+            throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("invalid proof root array parameter for %s", EncodeDestination(CIdentityID(ASSETCHAINS_CHAINID))));
+        }
+        // ignore potential dups
+        if (validRoots.count(checkRoot.rootHeight))
+        {
+            continue;
+        }
+        if (checkRoot == checkRoot.GetProofRoot(checkRoot.rootHeight))
+        {
+            validRoots.insert(std::make_pair(checkRoot.rootHeight, i));
+        }
+    }
+
+    UniValue retVal(UniValue::VOBJ);
+
+    // get the latest proof root and currency states
+    retVal.pushKV("latestproofroot", CProofRoot::GetProofRoot(nHeight).ToUniValue());
+
+    std::vector<UniValue> currencyStatesUni;
+    for (int i = 0; i < currenciesUni.size(); i++)
+    {
+        CCurrencyDefinition targetCur;
+        uint160 targetCurID;
+        if ((targetCurID = ValidateCurrencyName(uni_get_str(currenciesUni[i]), true, &targetCur)).IsNull())
+        {
+            throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("invalid currency state request for %s", uni_get_str(currenciesUni[i])));
+        }
+        currencyStatesUni.push_back(ConnectedChains.GetCurrencyState(targetCur, nHeight).ToUniValue());
+    }
+
+    return NullUniValue;
+}
+
 UniValue submitacceptednotarization(const UniValue& params, bool fHelp)
 {
     if (fHelp || params.size() != 2)
@@ -1857,8 +1969,8 @@ UniValue submitacceptednotarization(const UniValue& params, bool fHelp)
             "\nIf successful in submitting the transaction based on all rules, a transaction ID is returned, otherwise, NULL.\n"
 
             "\nArguments\n"
-            "\"earnednotarizaton\"              (object, required) notarization earned on the other system, which is the basis for this"
-            "\"notaryevidence\"                 (object, required) evidence and notary signatures validating the notarization"
+            "\"earnednotarization\"             (object, required) notarization earned on the other system, which is the basis for this\n"
+            "\"notaryevidence\"                 (object, required) evidence and notary signatures validating the notarization\n"
 
             "\nResult:\n"
             "txid                               (hexstring) transaction ID of submitted transaction\n"
@@ -5523,6 +5635,7 @@ static const CRPCCommand commands[] =
     { "multichain",   "getcurrencyconverters",        &getcurrencyconverters,  true  },
     { "multichain",   "getcurrency",                  &getcurrency,            true  },
     { "multichain",   "getnotarizationdata",          &getnotarizationdata,    true  },
+    { "multichain",   "getbestproofroot",             &getbestproofroot,       true  },
     { "multichain",   "submitacceptednotarization",   &submitacceptednotarization, true },
     { "multichain",   "getinitialcurrencystate",      &getinitialcurrencystate, true  },
     { "multichain",   "getcurrencystate",             &getcurrencystate,       true  },
This page took 0.057532 seconds and 4 git commands to generate.