]> Git Repo - VerusCoin.git/commitdiff
Sync last changes before testnet fork to repo
authorMichael Toutonghi <[email protected]>
Tue, 2 Jul 2019 05:50:24 +0000 (22:50 -0700)
committerMichael Toutonghi <[email protected]>
Tue, 2 Jul 2019 05:50:24 +0000 (22:50 -0700)
13 files changed:
src/Makefile.am
src/cc/CCcustom.cpp
src/cc/eval.cpp
src/cc/eval.h
src/coins.cpp
src/pbaas/notarization.h
src/pbaas/pbaas.h
src/pbaas/reserves.cpp [new file with mode: 0644]
src/pbaas/reserves.h [new file with mode: 0644]
src/rpc/pbaasrpc.cpp
src/rpc/pbaasrpc.h
src/rpc/rawtransaction.cpp
src/util.cpp

index f5a180fdbc525334f707381bb68ef2638832cb38..b0fb0feb468bf867905d607e6e6d297253992295 100644 (file)
@@ -212,6 +212,7 @@ BITCOIN_CORE_H = \
   pbaas/crosschainrpc.h \
   pbaas/notarization.h \
   pbaas/pbaas.h \
+  pbaas/reserves.h \
   policy/fees.h \
   pow.h \
   prevector.h \
@@ -343,6 +344,7 @@ libbitcoin_server_a_SOURCES = \
   pbaas/crosschainrpc.cpp \
   pbaas/notarization.cpp \
   pbaas/pbaas.cpp \
+  pbaas/reserves.cpp \
   policy/fees.cpp \
   pow.cpp \
   primitives/solutiondata.cpp \
index ce8d607fc0183fae0f4e386e4c3f4d66c3e198a7..f051790a4404b8abf0e7f76fed9f973751b86482 100644 (file)
@@ -331,8 +331,8 @@ struct CCcontract_info *CCinit(struct CCcontract_info *cp, uint8_t evalcode)
             break;
 
         case EVAL_INSTANTSPEND:
-        case EVAL_CROSSCHAIN_INPUT:
-        case EVAL_CROSSCHAIN_OUTPUT:
+        case EVAL_RESERVE_INPUT:
+        case EVAL_RESERVE_OUTPUT:
         case EVAL_CROSSCHAIN_IMPORT:
         case EVAL_CROSSCHAIN_EXPORT:
             assert(false);
index 96cb12c25a398d9646ed1bbe6ed36970c62676c3..1084887a4ef0b65a636450909ce75cee9556baa6 100644 (file)
@@ -78,11 +78,11 @@ bool Eval::Dispatch(const CC *cond, const CTransaction &txTo, unsigned int nIn)
         case EVAL_EARNEDNOTARIZATION:
         case EVAL_ACCEPTEDNOTARIZATION:
         case EVAL_FINALIZENOTARIZATION:
-        case EVAL_CROSSCHAIN_OUTPUT:
+        case EVAL_RESERVE_OUTPUT:
         case EVAL_CROSSCHAIN_EXPORT:
         case EVAL_CROSSCHAIN_IMPORT:
         case EVAL_INSTANTSPEND:
-        case EVAL_CROSSCHAIN_INPUT:
+        case EVAL_RESERVE_INPUT:
             if (!chainActive.LastTip() || CConstVerusSolutionVector::activationHeight.ActiveVersion(chainActive.LastTip()->GetHeight()) < CActivationHeight::SOLUTION_VERUSV3)
             {
                 // if chain is not able to process this yet, don't drop through to do so
index 7f34cda65d2c88a2aa16baa469de3a38e33de070..f3b7f0ba22ba41ba66163149aff0b138cb591341 100644 (file)
         EVAL(EVAL_ACCEPTEDNOTARIZATION, 0x5)  \
         EVAL(EVAL_FINALIZENOTARIZATION, 0x6)  \
         EVAL(EVAL_INSTANTSPEND, 0x7)  \
-        EVAL(EVAL_CROSSCHAIN_INPUT, 0x8)  \
-        EVAL(EVAL_CROSSCHAIN_OUTPUT, 0x9)  \
-        EVAL(EVAL_CROSSCHAIN_EXPORT, 0xa)  \
-        EVAL(EVAL_CROSSCHAIN_IMPORT, 0xb)  \
-        EVAL(EVAL_RESERVE_OUTPUT, 0xc)  \
-        EVAL(EVAL_RESERVE_EXCHANGE, 0xd)  \
+        EVAL(EVAL_RESERVE_INPUT, 0x8)  \
+        EVAL(EVAL_RESERVE_OUTPUT, 0x9)  \
+        EVAL(EVAL_RESERVE_EXCHANGE, 0xa)  \
+        EVAL(EVAL_CROSSCHAIN_EXPORT, 0xb)  \
+        EVAL(EVAL_CROSSCHAIN_IMPORT, 0xc)  \
         EVAL(EVAL_IMPORTPAYOUT, 0xe1)  \
         EVAL(EVAL_IMPORTCOIN, 0xe2)  \
         EVAL(EVAL_ASSETS, 0xe3)  \
index 2b2e3edef7841e812976f3c15090394492481cdf..a8662b98d276c5f84c8544fe896339aa802e8926 100644 (file)
@@ -612,7 +612,8 @@ CAmount CCoinsViewCache::GetValueIn(int32_t nHeight,int64_t *interestp,const CTr
                 //printf("nResult %.8f += val %.8f interest %.8f ht.%d lock.%u tip.%u\n",(double)nResult/COIN,(double)value/COIN,(double)interest/COIN,txheight,locktime,tiptime);
                 //fprintf(stderr,"nResult %.8f += val %.8f interest %.8f ht.%d lock.%u tip.%u\n",(double)nResult/COIN,(double)value/COIN,(double)interest/COIN,txheight,locktime,tiptime);
                 nResult += interest;
-                (*interestp) += interest;
+                if (interestp)
+                    (*interestp) += interest;
             }
         }
 #endif
index d2e8ee32a6dc47831d475ae4e7c62c7d530663f8..a53a2b0df774d09482466523040ae4a484bb1082 100644 (file)
@@ -57,8 +57,8 @@
  * 
  */
 
-#ifndef NOTARIZATION_H
-#define NOTARIZATION_H
+#ifndef PBAAS_NOTARIZATION_H
+#define PBAAS_NOTARIZATION_H
 
 #include "pbaas/pbaas.h"
 #include "key_io.h"
index ce44c94da4a55aa194830280b43ee09954f872ed..18a80af87ec8a4a9853ba591cb0ae4bf48f11a08 100644 (file)
@@ -403,7 +403,6 @@ public:
     static const int64_t MIN_BILLING_PERIOD = 480;  // 8 hour minimum billing period for notarization, typically expect days/weeks/months
     static const int64_t DEFAULT_OUTPUT_VALUE = 100000;  // 0.001 VRSC default output value
     static const int32_t OPTION_RESERVE = 1; // allows reserve conversion using base calculations when set
-    static const int32_t OPTION_CONVERT = 2; // allows conversion to the currency from Verus if set
 
     uint32_t nVersion;                      // version of this chain definition data structure to allow for extensions (not daemon version)
     std::string name;                       // chain name, maximum 64 characters
@@ -802,49 +801,6 @@ public:
     }
 };
 
-// convert from $VRSC to fractional reserve coin or vice versa. coinID determines which``
-class CReserveExchange
-{
-public:
-    uint32_t flags;                         // control of direction and constraints
-    CScript scriptPubKey;                   // output script for resulting coinbase output
-    CAmount nLimit;                         // lowest or highest price to sell or buy coin output, may fail if including this tx in block makes price out of range
-    uint32_t nValidBefore;                  // if not filled in this block, mine tx, but refund input
-    uint160 chainID;                        // currently supports convert from or to reserve according to conversion rules, this is ouput type
-
-    CReserveExchange(const std::vector<unsigned char> &asVector)
-    {
-        FromVector(asVector, *this);
-    }
-
-    CReserveExchange() : flags(0), nLimit(0), nValidBefore(0) { }
-
-    CReserveExchange(uint32_t Flags, const CScript &rScrOut, const CAmount Limit, uint32_t ValidBefore, uint160 ChainID) : 
-        flags(Flags), scriptPubKey(rScrOut), nLimit(Limit), nValidBefore(ValidBefore), chainID(ChainID) { }
-
-    ADD_SERIALIZE_METHODS;
-
-    template <typename Stream, typename Operation>
-    inline void SerializationOp(Stream& s, Operation ser_action) {
-        READWRITE(flags);
-        READWRITE(*(CScriptBase*)(&scriptPubKey));
-        READWRITE(VARINT(nLimit));
-        READWRITE(nValidBefore);
-        READWRITE(chainID);
-    }
-
-    std::vector<unsigned char> AsVector()
-    {
-        return ::AsVector(*this);
-    }
-
-    bool IsValid()
-    {
-        // this needs an actual check
-        return nValidBefore != 0 && scriptPubKey.size() != 0 && !chainID.IsNull();
-    }
-};
-
 class CRPCChainData
 {
 public:
diff --git a/src/pbaas/reserves.cpp b/src/pbaas/reserves.cpp
new file mode 100644 (file)
index 0000000..3439d8c
--- /dev/null
@@ -0,0 +1,343 @@
+/********************************************************************
+ * (C) 2019 Michael Toutonghi
+ * 
+ * Distributed under the MIT software license, see the accompanying
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.
+ * 
+ * This provides reserve currency functions, leveraging the multi-precision boost libraries to calculate reserve currency conversions.
+ * 
+ */
+
+#include "main.h"
+#include "pbaas/reserves.h"
+
+CReserveExchange::CReserveExchange(const CTransaction &tx, bool validate)
+{
+    bool orderFound = false;
+    version = PBAAS_VERSION_INVALID;
+    for (auto out : tx.vout)
+    {
+        COptCCParams p;
+        if (IsPayToCryptoCondition(out.scriptPubKey, p))
+        {
+            if (p.evalCode == EVAL_RESERVE_EXCHANGE)
+            {
+                if (orderFound)
+                {
+                    version = PBAAS_VERSION_INVALID;
+                }
+                else
+                {
+                    FromVector(p.vData[0], *this);
+                    orderFound = true;
+                }
+            }
+        }
+    }
+    if (!orderFound)
+    {
+        version = VERSION_INVALID;
+    }
+
+    if (validate)
+    {
+        
+    }
+}
+
+CFractionalReserveState::CFractionalReserveState(const UniValue &obj)
+{
+    int32_t initialRatio = uni_get_int(find_value(obj, "initialratio"));
+    if (initialRatio > CReserveExchange::SATOSHIDEN)
+    {
+        initialRatio = CReserveExchange::SATOSHIDEN;
+    }
+    else if (initialRatio < MIN_RESERVE_RATIO)
+    {
+        initialRatio = MIN_RESERVE_RATIO;
+    }
+    InitialRatio = initialRatio;
+
+    InitialSupply = uni_get_int64(find_value(obj, "initialsupply"));
+    Emitted = uni_get_int64(find_value(obj, "emitted"));
+    Supply = uni_get_int64(find_value(obj, "supply"));
+    Reserve = uni_get_int64(find_value(obj, "reserve"));
+}
+
+UniValue CFractionalReserveState::ToUniValue() const
+{
+    UniValue ret(UniValue::VOBJ);
+    ret.push_back(Pair("initialratio", (int32_t)InitialRatio));
+    ret.push_back(Pair("initialsupply", (int64_t)InitialSupply));
+    ret.push_back(Pair("emitted", (int64_t)Emitted));
+    ret.push_back(Pair("supply", (int64_t)Supply));
+    ret.push_back(Pair("reserve", (int64_t)Reserve));
+    ret.push_back(Pair("currentratio", GetReserveRatio().convert_to<float>()));
+    return ret;
+}
+
+bool to_int64(const cpp_dec_float_50 &input, int64_t &outval)
+{
+    std::stringstream ss(input.str(0));
+    try
+    {
+        ss >> outval;
+        return true;
+    }
+    catch(const std::exception& e)
+    {
+        return false;
+    }
+}
+
+// This can handle multiple aggregated, bidirectional conversions in one block of transactions. To determine the conversion price, it 
+// takes both input amounts of the reserve and the fractional currency to merge the conversion into one calculation
+// with the same price for all transactions in the block. It returns the newly calculated conversion price of the fractional 
+// reserve in the reserve currency.
+CAmount CFractionalReserveState::ConvertAmounts(CAmount inputReserve, CAmount inputFractional, CFractionalReserveState &newState) const
+{
+    newState = *this;
+
+    // if both conversions are zero, nothing to do but return current price
+    if (!inputReserve && !inputFractional)
+    {
+        return 0;
+    }
+
+    cpp_dec_float_50 reservein(inputReserve);
+    cpp_dec_float_50 fractionalin(inputFractional);
+    cpp_dec_float_50 supply(Supply);
+    cpp_dec_float_50 reserve(Reserve);
+    cpp_dec_float_50 ratio = GetReserveRatio();
+
+    // first buy if anything to buy
+    if (inputReserve)
+    {
+        supply = supply + (supply * (pow((reservein / reserve + 1.0), ratio) - 1));
+
+        int64_t newSupply;
+        if (!to_int64(supply, newSupply))
+        {
+            assert(false);
+        }
+        newState.Supply = newSupply;
+        newState.Reserve += inputReserve;
+        reserve = reserve + reservein;
+    }
+
+    // now sell if anything to sell
+    if (inputFractional)
+    {
+        cpp_dec_float_50 reserveout;
+        int64_t reserveOut;
+        reserveout = reserve * (pow((fractionalin / supply + 1.0), (1 / ratio)) - 1);
+        if (!to_int64(reserveout, reserveOut))
+        {
+            assert(false);
+        }
+
+        newState.Supply -= inputFractional;
+        newState.Reserve -= reserveOut;
+    }
+
+    // determine the change in both supply and reserve and return the execution price in reserve by calculating it from
+    // the actual conversion numbers
+    return (newState.Supply - Supply) / (newState.Reserve - Reserve);
+}
+
+struct CReserveExchangeData
+{
+    CTransaction *ptx;
+    uint32_t flags;
+    CAmount nLimit;
+    CAmount nInputValue;
+};
+
+// From a vector of reserve exchange transactions, match all that can be matched and return a new fractional reserve state,
+// a vector of transactions that are all executable, and the price that they executed at only qualified transactions 
+// based on their limits and the transaction price will be included.
+CFractionalReserveState CFractionalReserveState::MatchOrders(const std::vector<CTransaction *> &orders, 
+                                                             std::vector<CTransaction *> &matches, 
+                                                             std::vector<CTransaction *> &refunds, 
+                                                             std::vector<CTransaction *> &nofill, 
+                                                             std::vector<CTransaction *> &rejects, 
+                                                             CAmount &price, int32_t height) const
+{
+    // synthetic order book of limitBuys and limitSells sorted by limit, order of preference beyond limit sorting is random
+    std::multimap<CAmount, CReserveExchangeData> limitBuys;
+    std::multimap<CAmount, CReserveExchangeData> limitSells;
+    std::vector<int> ret;
+    CAmount marketBuy = 0;
+    CAmount marketSell = 0;
+
+    uint32_t tipTime = (chainActive.Height() >= height) ? chainActive[height]->nTime : chainActive.LastTip()->nTime;
+
+    for (int i = 0; i < orders.size(); i++)
+    {
+        CReserveExchange orderParams(*(orders[i]));
+        if (orderParams.IsValid() && !orderParams.IsExpired(height))
+        {
+            // if this is a market order, put it in, if limit, put it in an order book, sorted by limit
+            // get input value
+            CCoinsViewCache coins(pcoinsTip);
+            int64_t interest;           // unused for now
+            CReserveExchangeData rxd = {orders[i], orderParams.flags, orderParams.nLimit, coins.GetValueIn(height, &interest, *(orders[i]), tipTime)};
+
+            if (rxd.flags & CReserveExchange::TO_FRACTIONAL)
+            {
+                if (rxd.flags & CReserveExchange::LIMIT)
+                {
+                    // this is a limit buy, and we add orders from highest limit and move downwards
+                    limitBuys.insert(std::make_pair(rxd.nLimit, rxd));
+                }
+                else
+                {
+                    // convert the total input to fractional, fee is calculated after
+                    marketBuy += rxd.nInputValue;
+                    matches.push_back(orders[i]);
+                }
+            }
+            else
+            {
+                if (rxd.flags & CReserveExchange::LIMIT)
+                {
+                    // limit sell, we add orders from the lowest limit and move upwards
+                    limitSells.insert(std::make_pair(rxd.nLimit, rxd));
+                }
+                else
+                {
+                    // calculate fee and subtract, it won't be converted
+                    CAmount adjustedInput = 
+                        rxd.nInputValue - 
+                        ((arith_uint256(rxd.nInputValue) * arith_uint256(CReserveExchange::SUCCESS_FEE)) / arith_uint256(CReserveExchange::SATOSHIDEN)).GetLow64();
+                    marketSell += adjustedInput;
+                    matches.push_back(orders[i]);
+                }
+            }
+        }
+        else
+        {
+            if (orderParams.IsValid())
+            {
+                refunds.push_back(orders[i]);
+            }
+            else
+            {
+                rejects.push_back(orders[i]);
+            }
+        }
+    }
+
+    // now we have all market orders in matches vector, rejects that are expired or invalid in rejects, and market order input totals calculated
+    // 1. start from the current state and calculate what the price would be with market orders
+    // 2. add 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.5
+    // 4. create and return a new, updated CFractionalReserveState
+    CAmount reserveIn = marketBuy;
+    CAmount fractionalIn = marketSell;
+    CFractionalReserveState newState(*this);
+
+    // 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::pair<std::multimap<CAmount, CReserveExchangeData>::iterator, CAmount> buyPartial = make_pair(limitBuys.end(), 0); // valid in loop for partial fill
+    std::pair<std::multimap<CAmount, CReserveExchangeData>::iterator, CAmount> sellPartial = make_pair(limitSells.end(), 0);
+    for (bool tryagain = true; tryagain; )
+    {
+        tryagain = false;
+
+        CAmount exchangeRate = ConvertAmounts(reserveIn, fractionalIn, newState);
+
+        // 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.lower_bound(exchangeRate); limitBuysIt != limitBuys.end(); limitBuysIt = limitBuys.lower_bound(exchangeRate))
+        {
+            // any time there are entries above the lower bound, we only actually look at the end, since we mutate the
+            // multimap and remove anything we've already added
+            CFractionalReserveState rState;
+
+            // the last is most qualified
+            auto it = limitBuys.end();
+            CReserveExchangeData &currentBuy = (--it)->second;
+
+            // calculate fresh with all conversions together to see if we still meet the limit
+            CAmount newExchange = ConvertAmounts(reserveIn + currentBuy.nInputValue, fractionalIn, rState);
+            if (newExchange <= currentBuy.nLimit)
+            {
+                // add to the current buys, we will never do something to disqualify this, since all orders left are either
+                // the same limit or lower
+                matches.push_back(currentBuy.ptx);
+                reserveIn += currentBuy.nInputValue;
+                newState = rState;
+                exchangeRate = newExchange;
+                limitBuys.erase(it);
+            }
+            else
+            {
+                // get ratio of how much above the current exchange price we were on the limit and how much over we are
+                // use that ratio as a linear interpolation of the input amount to hit that limit and try again for a partial fill. if we can't fill
+                // the minimum, give up on this order. if we can, record a partial
+                cpp_dec_float_50 distanceTarget(limitBuysIt->second.nLimit - exchangeRate);
+                cpp_dec_float_50 actualDistance(newExchange - exchangeRate);
+                int64_t partialAttempt;
+                for (int j = 0; j < CReserveExchange::INTERPOLATE_ROUNDS; j++)
+                {
+                    if (to_int64((distanceTarget / actualDistance) * cpp_dec_float_50(currentBuy.nInputValue), partialAttempt) && 
+                        partialAttempt >= CReserveExchange::MIN_PARTIAL)
+                    {
+                        // TODO: check limit and if still out of bounds, iterate, otherwise, make a partial fill
+                        // initially, fail partials
+                    }
+                }
+
+                // we must be done with buys whether we created a partial or not
+                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 != limitBuys.end() && exchangeRate > limitSellsIt->second.nLimit; limitSellsIt = limitSells.begin())
+        {
+            CFractionalReserveState rState;
+            CReserveExchangeData &currentSell = limitSellsIt->second;
+
+            // calculate fresh with all conversions together to see if we still meet the limit
+            CAmount newExchange = ConvertAmounts(reserveIn, fractionalIn + currentSell.nInputValue, rState);
+            if (newExchange >= currentSell.nLimit)
+            {
+                // add to the current sells, we will never do something to disqualify this, since all orders left are either
+                // the same limit or higher
+                matches.push_back(currentSell.ptx);
+                fractionalIn += currentSell.nInputValue;
+                newState = rState;
+                limitSells.erase(limitSellsIt);
+                tryagain = true;
+            }
+            else
+            {
+                // we must be done with buys whether we created a partial or not
+                break;
+            }
+        }
+    }
+
+    for (auto entry : limitBuys)
+    {
+        nofill.push_back(entry.second.ptx);
+    }
+
+    for (auto entry : limitSells)
+    {
+        nofill.push_back(entry.second.ptx);
+    }
+
+    return newState;
+}
+
diff --git a/src/pbaas/reserves.h b/src/pbaas/reserves.h
new file mode 100644 (file)
index 0000000..552c22d
--- /dev/null
@@ -0,0 +1,258 @@
+/********************************************************************
+ * (C) 2019 Michael Toutonghi
+ * 
+ * Distributed under the MIT software license, see the accompanying
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.
+ * 
+ * This provides reserve currency functions, leveraging the multi-precision boost libraries to calculate reserve currency conversions
+ * in a predictable manner that can achieve consensus.
+ * 
+ */
+
+#ifndef PBAAS_RESERVES_H
+#define PBAAS_RESERVES_H
+
+#include <sstream>
+
+#include "pbaas/pbaas.h"
+#include <boost/multiprecision/cpp_dec_float.hpp>
+
+using boost::multiprecision::cpp_dec_float_50;
+
+class CReserveSend
+{
+public:
+    static const uint32_t VALID = 1;            // convert automatically when sending
+    static const uint32_t CONVERT = 2;          // convert automatically when sending
+    static const uint32_t PRECONVERT = 4;       // considered converted before sending according to before sending
+
+    static const CAmount DEFAULT_PER_STEP_FEE = 10000; // default fee for each step of each transfer (initial mining, transfer, mining on new chain)
+
+    uint32_t flags;     // conversion, etc.
+    CAmount nValue;     // nValue for an auto-conversion must include conversion fee and be (desired nValue + (desired nValue * (50000 / 100000000)))
+    CAmount nFees;      // network fees only, must be 2x standard network fees for the tx, pays for aggregation and mining payout into other chain
+
+    CReserveSend(const std::vector<unsigned char> &asVector)
+    {
+        FromVector(asVector, *this);
+    }
+
+    CReserveSend() : flags(0), nValue(0), nFees(0) { }
+
+    CReserveSend(uint32_t Flags, CAmount value, CAmount fees) : flags(Flags), nValue(value), nFees(fees) { }
+
+    ADD_SERIALIZE_METHODS;
+
+    template <typename Stream, typename Operation>
+    inline void SerializationOp(Stream& s, Operation ser_action) {
+        READWRITE(flags);
+        READWRITE(VARINT(nValue));
+        READWRITE(VARINT(nFees));
+    }
+
+    std::vector<unsigned char> AsVector()
+    {
+        return ::AsVector(*this);
+    }
+
+    bool IsValid()
+    {
+        return (flags & VALID) && nValue > 0 && nFees > 0;
+    }
+};
+
+// an output that carries a primary value of the native coin's reserve, not the native coin itself
+// there is no need to pay gas in the native coin because reserve can be used and converted to pay fees
+// this uses the destination controls of crypto conditions
+class CReserveOutput
+{
+public:
+    CAmount nValue;                         // lowest or highest price to sell or buy coin output, may fail if including this tx in block makes price out of range
+
+    CReserveOutput(const std::vector<unsigned char> &asVector)
+    {
+        FromVector(asVector, *this);
+    }
+
+    CReserveOutput() : nValue(0) { }
+
+    CReserveOutput(CAmount value) : nValue(value) { }
+
+    ADD_SERIALIZE_METHODS;
+
+    template <typename Stream, typename Operation>
+    inline void SerializationOp(Stream& s, Operation ser_action) {
+        READWRITE(VARINT(nValue));
+    }
+
+    std::vector<unsigned char> AsVector()
+    {
+        return ::AsVector(*this);
+    }
+
+    bool IsValid()
+    {
+        // we don't support op returns
+        return nValue != 0;
+    }
+};
+
+// convert from $VRSC to fractional reserve coin or vice versa. coinID determines which
+// in either direction, this is burned in the block. if burned, the block must contain less than a
+// maximum reasonable number of exchange outputs, which must be sorted, hashed, and used to validate
+// the outputs that must match exactly on any transaction spending the output. since fees are not
+// included in outputs, it is assumed that a miner will spend the output in the same block to recover
+// exchange fees
+class CReserveExchange
+{
+public:
+    static const int32_t VERSION_INVALID = 0;
+    static const int32_t VERSION1 = 1;
+
+    // flags
+    static const int32_t TO_RESERVE = 1;    // from fractional currency to reserve
+    static const int32_t TO_FRACTIONAL = 2; // to fractional currency from reserve
+    static const int32_t LIMIT = 4;         // after conversion, send output to the destination recipient on the other chain
+    static const int32_t FILL_OR_KILL = 8;  // if not filled before nValidBefore but before expiry, no execution, mined with maxfee, output pass through
+    static const int32_t ALL_OR_NONE = 0x10; // will not execute partial order
+
+    // success fee is calculated by multiplying the amount by this number and dividing by satoshis (100,000,000), not less than 10x the absolute SUCCESS_FEE
+    // failure fee, meaning the valid before block is past but it is not expired is the standard fee
+    static const CAmount SUCCESS_FEE = 5000;
+    static const CAmount MIN_PARTIAL = 10000000;        // making partial fill minimum the number at which minimum fee meets standard percent fee,
+    static const int INTERPOLATE_ROUNDS = 4;            // we ensures that there is no peverse motive to partially fill in order to increase fees
+    static const CAmount FILLORKILL_FEE = 10000;
+    static const CAmount SATOSHIDEN = 100000000;
+
+    int32_t version;                        // version of order
+    uint32_t flags;                         // control of direction and constraints
+    CAmount nLimit;                         // lowest or highest price to sell or buy coin output, may fail if including this tx in block makes price out of range
+    uint32_t nValidBefore;                  // if not filled before this block and not expired, can mine tx, but refund input
+
+    CReserveExchange(const std::vector<unsigned char> &asVector)
+    {
+        FromVector(asVector, *this);
+    }
+
+    CReserveExchange() : version(VERSION_INVALID), flags(0), nLimit(0), nValidBefore(0) { }
+
+    CReserveExchange(uint32_t Flags, CAmount Limit, uint32_t ValidBefore) : 
+        version(VERSION1), flags(Flags), nLimit(Limit), nValidBefore(ValidBefore) { }
+
+    CReserveExchange(const CTransaction &tx, bool validate=false);
+
+    ADD_SERIALIZE_METHODS;
+
+    template <typename Stream, typename Operation>
+    inline void SerializationOp(Stream& s, Operation ser_action) {
+        READWRITE(version);
+        READWRITE(flags);
+        READWRITE(VARINT(nLimit));
+        READWRITE(nValidBefore);
+    }
+
+    std::vector<unsigned char> AsVector()
+    {
+        return ::AsVector(*this);
+    }
+
+    bool IsValid()
+    {
+        // this needs an actual check
+        return version == VERSION1;
+    }
+
+    bool IsExpired(int32_t height)
+    {
+        return height >= nValidBefore;
+    }
+};
+
+bool to_int64(const cpp_dec_float_50 &input, int64_t &outval);
+
+class CFractionalReserveState
+{
+public:
+    static const int32_t MIN_RESERVE_RATIO = 1000000;
+    int32_t InitialRatio;   // starting point reserve percent for initial currency and emission, over SATOSHIs
+    CAmount InitialSupply;  // starting point for reserve currency, baseline for 100% reserve and used to calculate current reserve
+    CAmount Emitted;        // unlike other supply variations, emitted coins reduce the reserve ratio and are used to calculate current ratio
+    CAmount Supply;         // current supply
+    CAmount Reserve;        // current reserve controlled by fractional chain
+
+    CFractionalReserveState() : InitialSupply(0), Emitted(0), Supply(0), Reserve(0) {}
+
+    CFractionalReserveState(int32_t initialRatio, CAmount supply, CAmount initialSupply, CAmount emitted, CAmount reserve) : 
+        InitialSupply(initialSupply), Emitted(emitted), Supply(supply), Reserve(reserve)
+    {
+        if (initialRatio > CReserveExchange::SATOSHIDEN)
+        {
+            initialRatio = CReserveExchange::SATOSHIDEN;
+        }
+        else if (initialRatio < MIN_RESERVE_RATIO)
+        {
+            initialRatio = MIN_RESERVE_RATIO;
+        }
+        InitialRatio = initialRatio;
+    }
+    CFractionalReserveState(const UniValue &uni);
+
+    ADD_SERIALIZE_METHODS;
+
+    template <typename Stream, typename Operation>
+    inline void SerializationOp(Stream& s, Operation ser_action) {
+        READWRITE(VARINT(InitialRatio));
+        READWRITE(VARINT(InitialSupply));
+        READWRITE(VARINT(Emitted));
+        READWRITE(VARINT(Supply));
+        READWRITE(VARINT(Reserve));        
+    }
+
+    std::vector<unsigned char> AsVector() const
+    {
+        return ::AsVector(*this);
+    }
+
+    cpp_dec_float_50 GetReserveRatio() const
+    {
+        cpp_dec_float_50 one(1);
+        if (Emitted == 0)
+        {
+            return one;
+        }
+        cpp_dec_float_50 ratio(one / ((one + (cpp_dec_float_50(Emitted) / cpp_dec_float_50(InitialSupply))) * cpp_dec_float_50(InitialRatio)));
+    }
+
+    // return the current price of the fractional reserve in the reserve currency.
+    cpp_dec_float_50 GetPriceInReserve() const
+    {
+        cpp_dec_float_50 supply(Supply);
+        cpp_dec_float_50 reserve(Reserve);
+        cpp_dec_float_50 ratio = GetReserveRatio();
+        return reserve / (supply * ratio);
+    }
+
+    // This can handle multiple aggregated, bidirectional conversions in one block of transactions. To determine the conversion price, it 
+    // takes both input amounts of the reserve and the fractional currency to merge the conversion into one calculation
+    // with the same price for all transactions in the block. It returns the newly calculated conversion price of the fractional 
+    // reserve in the reserve currency.
+    CAmount ConvertAmounts(CAmount inputReserve, CAmount inputFractional, CFractionalReserveState &newState) const;
+
+    CFractionalReserveState MatchOrders(const std::vector<CTransaction *> &orders, 
+                                        std::vector<CTransaction *> &matches, 
+                                        std::vector<CTransaction *> &refunds, 
+                                        std::vector<CTransaction *> &nofill, 
+                                        std::vector<CTransaction *> &rejects, 
+                                        CAmount &price, int32_t height) const;
+
+    UniValue ToUniValue() const;
+
+    bool IsValid() const
+    {
+        return InitialRatio >= MIN_RESERVE_RATIO && InitialRatio <= CReserveExchange::SATOSHIDEN && 
+                Supply >= 0 && 
+                ((Reserve > 0 && InitialSupply > 0) || (Reserve == 0 && InitialSupply == 0));
+    }
+};
+
+#endif // PBAAS_RESERVES_H
index 18024b912660f30e19338a1ea3221d248c59aee0..85f835058c94eb66250598119e810c4b472f0534 100644 (file)
@@ -700,28 +700,6 @@ CAmount AddNewNotarizationRewards(CPBaaSChainDefinition &chainDef, vector<CInput
     return newIn;
 }
 
-UniValue submitnotarizationpayment(const UniValue& params, bool fHelp)
-{
-    if (fHelp || params.size() != 1)
-    {
-        throw runtime_error(
-            "submitnotarizationpayment \"chainid\" \"amount\" \"billingperiod\"\n"
-            "\nAdds some amount of funds to a specific billing period of a PBaaS chain, which will be released\n"
-            "\nin the form of payments to notaries whose notarizations are confirmed.\n"
-
-            "\nArguments\n"
-
-            "\nResult:\n"
-
-            "\nExamples:\n"
-            + HelpExampleCli("submitnotarizationpayment", "\"hextx\"")
-            + HelpExampleRpc("submitnotarizationpayment", "\"hextx\"")
-        );
-    }
-    CheckPBaaSAPIsValid();
-
-}
-
 UniValue submitacceptednotarization(const UniValue& params, bool fHelp)
 {
     if (fHelp || params.size() != 1)
@@ -1429,29 +1407,163 @@ UniValue getcrossnotarization(const UniValue& params, bool fHelp)
     return ret;
 }
 
-UniValue sendtochain(const UniValue& params, bool fHelp)
+UniValue paynotarizationrewards(const UniValue& params, bool fHelp)
+{
+    if (fHelp || params.size() != 1)
+    {
+        throw runtime_error(
+            "paynotarizationrewards \"chainid\" \"amount\" \"billingperiod\"\n"
+            "\nAdds some amount of funds to a specific billing period of a PBaaS chain, which will be released\n"
+            "\nin the form of payments to notaries whose notarizations are confirmed.\n"
+
+            "\nArguments\n"
+
+            "\nResult:\n"
+
+            "\nExamples:\n"
+            + HelpExampleCli("paynotarizationrewards", "\"hextx\"")
+            + HelpExampleRpc("paynotarizationrewards", "\"hextx\"")
+        );
+    }
+    CheckPBaaSAPIsValid();
+
+}
+
+UniValue getreserveinfo(const UniValue& params, bool fHelp)
+{
+    if (fHelp || params.size() > 1 || (params.size() == 1 || !params[0].isStr()))
+        throw runtime_error(
+            "getreserveinfo\n"
+            "\nReturns the reserve balance of a particular chain or the current chain if this is a fractional reserve"
+            "currency and the chain name is not specified. If info is requested from the reserve chain for a fractional"
+            "reserve currency, this does not attempt to provide a real-time breakdown of the distribution between"
+            "value under control of users on the chain or in the actual currency reserves and under control of the chain itself, "
+            "as that may change from block to block.\n"
+            "\nArguments:\n"
+            "\"name\"                           (string, optional) chain name symbol. if absent, reserve info for the current chain is returned\n"
+            "\nResult:\n"
+            "{\n"
+            "  \"initialreserveratio\"          (int)   number over satoshis is starting reserve ratio\n"
+            "  \"preminecontributions\"         (int64) total number of satoshis contributed\n"
+            "  \"launchfee\"                    (int)   number over satoshis times contribution is launch fee to organization or person launching chain\n"
+            "  \"premine\"                      (int64) total number of satoshis distributed in premine\n"
+            "  \"eras\"                         (object) emission and other properties for each era\n"
+            "  \"currentreserveratio\"          (int)   (*) most current reserve ratio\n"
+            "  \"currentreserve\"               (int)   (*) current amount of reserve\n"
+            "  \"currentsupply\"                (int)   (*) current amount of supply\n"
+            "  \"priceinreserve\"               (int)   (*) current price in reserve to convert to one supply\n"
+            "  * - information returned only when called on fractional reserve chain\n"
+            "}\n"
+            "\nExamples:\n"
+            + HelpExampleCli("getreserveinfo", "(chainname)")
+            + HelpExampleRpc("getreserveinfo", "(chainname)")
+        );
+
+    std::string name = params.size() ? std::string(ASSETCHAINS_SYMBOL) : uni_get_str(params[0]);
+
+    if (name.size() == 0 || name.size() >= KOMODO_ASSETCHAIN_MAXLEN)
+    {
+        throw JSONRPCError(RPC_INVALID_PARAMETER, "PBaaS blockchain names must be greater than zero characters and less than " + std::to_string(KOMODO_ASSETCHAIN_MAXLEN));
+    }
+
+    std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
+    uint160 chainID = CCrossChainRPCData::GetChainID(name);
+
+    // validate the chain definition
+    CPBaaSChainDefinition chainDef;
+    if (!GetChainDefinition(chainID, chainDef))
+    {
+        throw JSONRPCError(RPC_INVALID_PARAMETER, "No information available for chain " + name);
+    }
+
+    CKeyID conditionID = CCrossChainRPCData::GetConditionID(name, EVAL_CROSSCHAIN_EXPORT);
+    CAmount premineContributions = 0;
+
+    // if we are on the reserve chain, we get the starting info
+    if (IsVerusActive())
+    {
+        // get all outputs to the cross chain export that could have been sent before chain start
+        if (GetAddressIndex(conditionID, 1, addressIndex, 0, chainDef.startBlock)) {
+            // loop through and include only valid cc outs
+            for (auto txIndex : addressIndex)
+            {
+                CTransaction tx;
+                uint256 hashBlock;
+                if (!myGetTransaction(txIndex.first.txhash, tx, hashBlock))
+                {
+                    throw JSONRPCError(RPC_DATABASE_ERROR, "Could not retrieve reserve transactions found in index from blockchain. Local database is likely corrupt.");
+                }
+                // any cross chain export that happens before chain launch with convert converts to premine contributions
+                COptCCParams p;
+                if (::IsPayToCryptoCondition(tx.vout[txIndex.first.index].scriptPubKey, p) && p.evalCode == EVAL_CROSSCHAIN_EXPORT)
+                {
+                    CCrossChainExport cce(p.vData[0]);
+                    if (cce.exportType == CCrossChainExport::EXPORT_CONVERSION)
+                    {
+                        premineContributions += txIndex.second;
+                    }
+                }
+            }
+        }
+    }
+    else if (chainDef.conversion > 0)
+    {
+        // determine the initial premine contributions by dividing premine with
+        // the conversion rate and adding back in the fee if applicable
+        arith_uint256 premine256(chainDef.premine);
+        arith_uint256 satoshiden(CReserveExchange::SATOSHIDEN);
+        premineContributions = ((premine256 * satoshiden) / arith_uint256(chainDef.conversion)).GetLow64();
+        // TODO : finish
+    }
+    
+    UniValue result(UniValue::VOBJ);
+    return result;
+}
+
+UniValue listreservetransactions(const UniValue& params, bool fHelp)
+{
+    if (fHelp || params.size() != 1)
+    {
+        throw runtime_error(
+            "listreservetransactions (maxnumber) (minconfirmations)\n"
+            "\nLists all reserve coin transactions sent to/from the current wallet.\n"
+
+            "\nArguments\n"
+
+            "\nResult:\n"
+
+            "\nExamples:\n"
+            + HelpExampleCli("listreservetransactions", "100 0")
+            + HelpExampleRpc("listreservetransactions", "100 0")
+        );
+    }
+    // lists all transactions in a wallet that are 
+}
+
+UniValue sendreserve(const UniValue& params, bool fHelp)
 {
     if (fHelp || params.size() != 1)
     {
         throw runtime_error(
-            "sendtochain '[{\"name\": \"PBAASCHAIN\", \"paymentaddress\": \"RRehdmUV7oEAqoZnzEGBH34XysnWaBatct\", \"amount\": 5.0}]'\n"
-            "\nThis sends a Verus output as a JSON object or lists of Verus outputs as a list of objects to multiple chains or back.\n"
+            "sendreserve '[{\"name\": \"PBAASCHAIN\", \"paymentaddress\": \"RRehdmUV7oEAqoZnzEGBH34XysnWaBatct\", \"amount\": 5.0, \"convert\": 1}]'\n"
+            "\nThis sends a Verus output as a JSON object or lists of Verus outputs as a list of objects to an address on the same or another chain.\n"
             "\nFunds are sourced automatically from the current wallet, which must be present, as in sendtoaddress.\n"
 
             "\nArguments\n"
             "       {\n"
-            "           \"chain\"          : \"xxxx\",  (string, required) unique Verus ecosystem-wide name/symbol of this PBaaS chain\n"
+            "           \"chain\"          : \"xxxx\",  (string, optional) Verus ecosystem-wide name/symbol of this PBaaS chain, if absent, current chain is assumed\n"
+            //"           \"sourceaddress\"  : \"zsxxx\", \"Rxxx\" (string, optional) source address, uses available transparent addresses in wallet if absent"
             "           \"paymentaddress\" : \"Rxxx\",  (string, required) premine and launch fee recipient\n"
-            "           \"amount\"         : \"n\",     (int64,  required) amount of coins that will be premined and distributed to premine address\n"
-            "           \"convert\"        : \"false\", (bool,   optional) auto-convert to PBaaS currency at current price\n"
+            "           \"amount\"         : \"n\",     (int64,  required) amount of coins that will be moved and sent to address on PBaaS chain, network and conversion fees additional\n"
+            "           \"convert\"        : \"false\", (bool,   optional) auto-convert to PBaaS currency at market price\n"
             "       }\n"
 
             "\nResult:\n"
             "       \"txid\" : \"transactionid\" (string) The transaction id.\n"
 
             "\nExamples:\n"
-            + HelpExampleCli("sendtochain", "'[{\"name\": \"PBAASCHAIN\", \"paymentaddress\": \"RRehdmUV7oEAqoZnzEGBH34XysnWaBatct\", \"amount\": 5.0}]'")
-            + HelpExampleRpc("sendtochain", "'[{\"name\": \"PBAASCHAIN\", \"paymentaddress\": \"RRehdmUV7oEAqoZnzEGBH34XysnWaBatct\", \"amount\": 5.0}]'")
+            + HelpExampleCli("sendreserve", "'[{\"name\": \"PBAASCHAIN\", \"paymentaddress\": \"RRehdmUV7oEAqoZnzEGBH34XysnWaBatct\", \"amount\": 5.0}]'")
+            + HelpExampleRpc("sendreserve", "'[{\"name\": \"PBAASCHAIN\", \"paymentaddress\": \"RRehdmUV7oEAqoZnzEGBH34XysnWaBatct\", \"amount\": 5.0}]'")
         );
     }
 
@@ -1467,9 +1579,9 @@ UniValue sendtochain(const UniValue& params, bool fHelp)
     vector<CRecipient> outputs;
     vector<bool> vConvert;
 
-    if (params.size() != 1 || (!params[0].isArray() && !params[0].isObject()))
+    if (params.size() != 1 || (!params[0].isObject()))
     {
-        throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameters. Must provide a single object or single list of objects that represent valid outputs. see help.");
+        throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameters. Must provide a single object that represents valid outputs. see help.");
     }
 
     const UniValue *pOutputArr = &params[0];
@@ -1481,6 +1593,12 @@ UniValue sendtochain(const UniValue& params, bool fHelp)
     }
     const UniValue &objArr = *pOutputArr;
 
+    bool isVerusActive = IsVerusActive();
+    uint160 thisChainID = ConnectedChains.ThisChain().GetChainID();
+
+    CAmount inputNeeded;
+    CTxOut newOutput;
+
     // convert all entries to CRecipient
     // any failure fails all
     for (int i = 0; i < objArr.size(); i++)
@@ -1489,9 +1607,17 @@ UniValue sendtochain(const UniValue& params, bool fHelp)
         // one output for definition, one for finalization
         string name = uni_get_str(find_value(params[0], "chain"), "");
         string paymentAddr = uni_get_str(find_value(params[0], "paymentaddress"), "");
+        //string sourceAddr = uni_get_str(find_value(params[0], "sourceaddress"), "");
         CAmount amount = uni_get_int64(find_value(params[0], "amount"), -1);
         bool convert = uni_get_int(find_value(params[0], "convert"), false);
 
+        bool sameChain = false;
+        if (name == "")
+        {
+            name = ASSETCHAINS_SYMBOL;
+            sameChain = true;
+        }
+
         if (name == "" || paymentAddr == "" || amount < 0)
         {
             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameters for object #" + to_string(i));
@@ -1506,6 +1632,7 @@ UniValue sendtochain(const UniValue& params, bool fHelp)
         }
 
         uint160 chainID = CCrossChainRPCData::GetChainID(name);
+
         CPBaaSChainDefinition chainDef;
         // validate that the target chain is still running
         if (!GetChainDefinition(chainID, chainDef) || !chainDef.IsValid())
@@ -1513,9 +1640,84 @@ UniValue sendtochain(const UniValue& params, bool fHelp)
             throw JSONRPCError(RPC_INVALID_PARAMETER, "Chain specified in object #" + to_string(i) + " is not a valid chain");
         }
 
+        bool isReserve = (chainDef.eraOptions.size() && (chainDef.eraOptions[0] & CPBaaSChainDefinition::OPTION_RESERVE));
+
+        // non-reserve conversions only work before the chain launches, then they determine the premine allocation
+        // premine claim transactions are basically export transactions of a pre-converted amount of native coin with a neutral
+        // impact on the already accounted for supply based on conversion conditions and contributions to the blockchain before
+        // the start block
+        bool beforeStart = chainDef.startBlock > chainActive.Height();
+
+        if (isVerusActive)
+        {
+            if (chainID == thisChainID)
+            {
+                throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot send reserve on a reserve chain that is not a fractional reserve of another currency. Use sendtoaddress or z_sendmany.");
+            }
+            else if (true) // ensure the PBaaS chain is a fractional reserve or that it's convertible and this is a conversion
+            {
+                // send Verus to a PBaaS chain
+                if (convert)
+                {
+                    // if chain hasn't started yet, we must use the conversion as a ratio over satoshis to participate in the pre-mine
+                    // up to a maximum
+                    if (beforeStart)
+                    {
+                        if (chainDef.conversion <= 0)
+                        {
+                            throw JSONRPCError(RPC_INVALID_PARAMETER, std::string(ASSETCHAINS_SYMBOL) + " is not convertible to " + chainDef.name + (isReserve ? " before the chain starts." : "."));
+                        }
+                        // we need to calculate the required fees and include them in the input we will need for the transaction
+                        // each step takes a default per step fee, and there are 3 steps
+                        inputNeeded = amount + (CReserveSend::DEFAULT_PER_STEP_FEE << 1) + CReserveSend::DEFAULT_PER_STEP_FEE;
+
+                        // make sure we do not exceed the maximum amount of contribution for this chain
+
+                    } else if (!isReserve)
+                    {
+                        throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot convert " + std::string(ASSETCHAINS_SYMBOL) + " after chain launch");
+                    }
+                    else
+                    {
+                        /* code */
+                    }
+                }
+            }
+            else
+            {
+                throw JSONRPCError(RPC_INVALID_PARAMETER, "Chain specified in object #" + to_string(i) + " is not a known reserve or fractional reserve chain");
+            }
+        }
+        else
+        {
+            if (chainID == thisChainID)
+            {
+                // it is a reserve token send. reserve token send must take reserve token as inputs only and will only convert
+                // automatically between inputs and outputs if explicitly requested with the convert parameter. if conversion occurs,
+                // it will be at market price. any mining fee required to process this transaction will be calculated from the current price 
+                // before this block and included as a corresponding reduction in the reserve token. exchange fees will be subtracted from 
+                // the total returned at the current blochchain rate. fees are put into the total exchange as purchase of the native coin 
+                // at market, which is then taken by the block validator as a fee
+                if (convert)
+                {
+                }
+            }
+            else if (chainID == ConnectedChains.NotaryChain().GetChainID())
+            {
+                // send Verus from this PBaaS chain to the Verus chain
+                if (convert)
+                {
+                }
+            }
+            else
+            {
+                throw JSONRPCError(RPC_INVALID_PARAMETER, "Chain specified in object #" + to_string(i) + " is not the current chain or this chain's reserve");
+            }
+        }
+
         // validate that the entry is a valid chain being notarized
         CChainNotarizationData nData;
-        if (GetNotarizationData(chainID, IsVerusActive() ? EVAL_ACCEPTEDNOTARIZATION : EVAL_ACCEPTEDNOTARIZATION, nData))
+        if (isVerusActive && GetNotarizationData(chainID, EVAL_EARNEDNOTARIZATION, nData))
         {
             // if the chain is being notarized and cannot confirm before its end, refuse to send
             // also, if it hasn't been notarized as recently as the active notarization threshold, refuse as well
@@ -1526,7 +1728,7 @@ UniValue sendtochain(const UniValue& params, bool fHelp)
                     chainDef.endBlock)) ||
                 (!chainDef.eraOptions.size() || !(chainDef.eraOptions[0] & CPBaaSChainDefinition::OPTION_RESERVE)))
             {
-                throw JSONRPCError(RPC_INVALID_PARAMETER, "Chain specified in object #" + to_string(i) + " is not a valid chain");
+                throw JSONRPCError(RPC_INVALID_PARAMETER, "Chain specified in object #" + to_string(i) + " is not a valid fractional reserve chain");
             }
         }
         else
@@ -1538,16 +1740,16 @@ UniValue sendtochain(const UniValue& params, bool fHelp)
 
         CCcontract_info CC;
         CCcontract_info *cp;
-        cp = CCinit(&CC, EVAL_CROSSCHAIN_INPUT);
+        cp = CCinit(&CC, EVAL_RESERVE_INPUT);
 
         CPubKey pk = CPubKey(ParseHex(CC.CChexstr));
         // TODO: determine dests properly
-        std::vector<CTxDestination> dests = std::vector<CTxDestination>({CKeyID(chainDef.GetConditionID(EVAL_CROSSCHAIN_INPUT))});
+        std::vector<CTxDestination> dests = std::vector<CTxDestination>({CKeyID(chainDef.GetConditionID(EVAL_RESERVE_INPUT))});
         CCrossChainInput cci; // TODO fill with payment script and amount (adjust amount for fees)
-        CTxOut ccOut = MakeCC1of1Vout(EVAL_CROSSCHAIN_INPUT, amount, pk, dests, cci);
+        CTxOut ccOut = MakeCC1of1Vout(EVAL_RESERVE_INPUT, amount, pk, dests, cci);
         outputs.push_back(CRecipient({ccOut.scriptPubKey, amount, false}));
     }
-    // send the specified amount to chain ID as an EVAL_CROSSCHAIN_INPUT to the chain ID
+    // send the specified amount to chain ID as an EVAL_RESERVE_INPUT to the chain ID
     // the transaction holds the ultimate destination address, and until the transaction
     // is packaged into an EVAL_CROSSCHAIN_EXPORT bundle, the output can be spent by
     // the original sender
@@ -2233,7 +2435,7 @@ static const CRPCCommand commands[] =
     { "pbaas",        "getcrossnotarization",         &getcrossnotarization,   true  },
     { "pbaas",        "definechain",                  &definechain,            true  },
     { "pbaas",        "submitacceptednotarization",   &submitacceptednotarization, true  },
-    { "pbaas",        "submitnotarizationpayment",    &submitnotarizationpayment, true  },
+    { "pbaas",        "paynotarizationrewards",       &paynotarizationrewards, true  },
     { "pbaas",        "addmergedblock",               &addmergedblock,         true  }
 };
 
index 96e19ff9546dd994b1c1c7a76e79a799959782b8..552ca6bd2eb0d3eb84baf1070ad3ee092bf3ceb4 100644 (file)
@@ -10,6 +10,7 @@
 #include "sync.h"
 #include <stdint.h>
 #include "pbaas/notarization.h"
+#include "pbaas/reserves.h"
 
 #include <boost/assign/list_of.hpp>
 
index 51391782c209c69c1d05ce4829e510d50c0697ec..85c854f947fa7c2bccd048b82bbea43a031148b5 100644 (file)
@@ -390,8 +390,8 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
                 }
 
                 case EVAL_INSTANTSPEND:
-                case EVAL_CROSSCHAIN_INPUT:
-                case EVAL_CROSSCHAIN_OUTPUT:
+                case EVAL_RESERVE_INPUT:
+                case EVAL_RESERVE_OUTPUT:
                 case EVAL_CROSSCHAIN_EXPORT:
                 case EVAL_CROSSCHAIN_IMPORT:
                 case EVAL_STAKEGUARD:
index 42a20e91ce971795be5f14a992c09389e4add04d..7ab3d42b1c993b11c2bf9be0d72ac1c6cfc11b7a 100644 (file)
@@ -396,7 +396,7 @@ void Split(const std::string& strVal, uint64_t *outVals, const uint64_t nDefault
     while ( ss.peek() == ' ' )
         ss.ignore();
 
-    while ( ss >> i )
+    while ( numVals < ASSETCHAINS_MAX_ERAS && ss >> i )
     {
         outVals[numVals] = i;
         numVals += 1;
This page took 0.067176 seconds and 4 git commands to generate.