diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ff8cbafc3a..d0eced3eb4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -7,7 +7,7 @@ stages: ######################################################################################################################## variables: - VERSION: 1.2.3-2 + VERSION: 1.2.3-3 VERUS_CLI_ARM64_LINUX: Verus-CLI-Linux-v${VERSION}-arm64.tar.gz VERUS_CLI_LINUX_X86_64: Verus-CLI-Linux-v${VERSION}-x86_64.tar.gz diff --git a/README.md b/README.md index e513f20fed..fd03927b52 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -## VerusCoin version 1.2.3-2 +## VerusCoin version 1.2.3-3 Arguably the world's most advanced technology, zero knowledge privacy enabled, multi-chain blockchain protocol, Verus Public Blockchains as a Service (PBaaS) combines Sapling zero knowledge technology with an intelligent, multi-chain, provable protocol, using interchain smart transactions. Verus PBaaS also enables merge mining and cross-chain staking with a completely original, combined proof of stake/proof of work consensus algorithm, Proof of Power, that can be mined on CPUs and mobile phones, and also solves the nothing at stake problem. With this and its approach towards CPU mining and ASICs, Verus Coin strives to be one of the most naturally decentralizing and attack resistant blockchain networks in existence. diff --git a/doc/man/verus-cli/linux/README.txt b/doc/man/verus-cli/linux/README.txt index 22d27d87e2..542de30bc2 100644 --- a/doc/man/verus-cli/linux/README.txt +++ b/doc/man/verus-cli/linux/README.txt @@ -1,5 +1,5 @@ -VerusCoin Command Line Tools v1.2.3-2 +VerusCoin Command Line Tools v1.2.3-3 Contents: verusd - VerusCoin daemon diff --git a/doc/man/verus-cli/mac/README.txt b/doc/man/verus-cli/mac/README.txt index d497af0d22..8d594b6d28 100644 --- a/doc/man/verus-cli/mac/README.txt +++ b/doc/man/verus-cli/mac/README.txt @@ -1,5 +1,5 @@ -VerusCoin Command Line Tools v1.2.3-2 +VerusCoin Command Line Tools v1.2.3-3 Contents: verusd - VerusCoin daemon. diff --git a/doc/man/verus-cli/windows/README.txt b/doc/man/verus-cli/windows/README.txt index 664be3d441..5016ac2ea1 100644 --- a/doc/man/verus-cli/windows/README.txt +++ b/doc/man/verus-cli/windows/README.txt @@ -1,5 +1,5 @@ -VerusCoin Command Line Tools v1.2.3-2 +VerusCoin Command Line Tools v1.2.3-3 Contents: verusd.exe - VerusCoin daemon diff --git a/src/deprecation.h b/src/deprecation.h index db468ece5c..a2157b011e 100644 --- a/src/deprecation.h +++ b/src/deprecation.h @@ -9,7 +9,7 @@ // * Shut down 52 weeks' worth of blocks after the estimated release block height. // * A warning is shown during the 2 months' worth of blocks prior to shut down. -static const int APPROX_RELEASE_HEIGHT = 3090000; +static const int APPROX_RELEASE_HEIGHT = 3108000; static const int WEEKS_UNTIL_DEPRECATION = 52; static const int DEPRECATION_HEIGHT = APPROX_RELEASE_HEIGHT + (WEEKS_UNTIL_DEPRECATION * 7 * 60 * 24); diff --git a/src/init.cpp b/src/init.cpp index 99147aaa1b..fb623e6ba1 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -405,6 +405,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-maxconnections=", strprintf(_("Maintain at most connections to peers (default: %u)"), DEFAULT_MAX_PEER_CONNECTIONS)); strUsage += HelpMessageOpt("-maxreceivebuffer=", strprintf(_("Maximum per-connection receive buffer, *1000 bytes (default: %u)"), 5000)); strUsage += HelpMessageOpt("-maxsendbuffer=", strprintf(_("Maximum per-connection send buffer, *1000 bytes (default: %u)"), 1000)); + strUsage += HelpMessageOpt("-maximumimportrange=", strprintf(_("Maximum number of blocks for an import range query or getcurrencystate with volume, (default: unlimited)"))); strUsage += HelpMessageOpt("-onion=", strprintf(_("Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)"), "-proxy")); strUsage += HelpMessageOpt("-onlynet=", _("Only connect to nodes in network (ipv4, ipv6 or onion)")); strUsage += HelpMessageOpt("-permitbaremultisig", strprintf(_("Relay non-P2SH multisig (default: %u)"), 1)); @@ -1362,6 +1363,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // initialization, and this is the first time we can get it. store the Sapling address here extern boost::optional defaultSaplingDest; VERUS_DEFAULT_ZADDR = GetArg("-cheatcatcher", ""); + VERUS_DEFAULT_ZADDR = GetArg("-stakeguard", VERUS_DEFAULT_ZADDR); // TODO: should separate stakeguard/cheatcatcher from the default change address VERUS_DEFAULT_ZADDR = GetArg("-defaultzaddr", VERUS_DEFAULT_ZADDR); libzcash::PaymentAddress addr = DecodePaymentAddress(VERUS_DEFAULT_ZADDR); if (VERUS_DEFAULT_ZADDR.size() > 0 && IsValidPaymentAddress(addr)) diff --git a/src/miner.cpp b/src/miner.cpp index bd07433225..b30724784e 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -4483,7 +4483,7 @@ void static BitcoinMiner_noeq() bool tryAgain = true; int retryCount = 0; - while (tryAgain && retryCount++ < 2) + while (tryAgain && retryCount++ < 5) { tryAgain = false; params.push_back(EncodeHexBlk(*pblock)); @@ -4495,8 +4495,8 @@ void static BitcoinMiner_noeq() { ConnectedChains.lastSubmissionFailed = false; params = RPCCallRoot("addmergedblock", params); - params = find_value(params, "result"); error = find_value(params, "error"); + params = find_value(params, "result"); } catch (std::exception e) { LogPrintf("Failed to connect to %s chain\n", ConnectedChains.FirstNotaryChain().chainDefinition.name.c_str()); diff --git a/src/pbaas/reserves.cpp b/src/pbaas/reserves.cpp index dae9663ea2..8c02447884 100644 --- a/src/pbaas/reserves.cpp +++ b/src/pbaas/reserves.cpp @@ -830,7 +830,7 @@ CCurrencyValueMap CCoinbaseCurrencyState::TargetConversionPrices(const uint160 & } else { - retVal.valueMap[GetID()] = NativeToReserveRaw(SATOSHIDEN, currencyMap.valueMap[targetCurrencyID]); + retVal.valueMap[GetID()] = ReserveToNativeRaw(SATOSHIDEN, currencyMap.valueMap[targetCurrencyID]); for (auto &oneCur : currencies) { @@ -863,7 +863,7 @@ CCurrencyValueMap CCoinbaseCurrencyState::TargetConversionPrices(const uint160 & } else { - retVal.valueMap[GetID()] = NativeToReserveRaw(SATOSHIDEN, prices.valueMap.find(targetCurrencyID)->second); + retVal.valueMap[GetID()] = ReserveToNativeRaw(SATOSHIDEN, prices.valueMap.find(targetCurrencyID)->second); for (auto &oneCur : currencies) { @@ -906,7 +906,7 @@ CCurrencyValueMap CCoinbaseCurrencyState::TargetLastConversionPrices(const uint1 SATOSHIDEN : NativeToReserveRaw(ReserveToNativeRaw(SATOSHIDEN, viaCurrencyMap.valueMap[targetCurrencyID]), currencyMap.valueMap[oneCur]); } - retVal.valueMap[GetID()] = NativeToReserveRaw(SATOSHIDEN, currencyMap.valueMap[targetCurrencyID]); + retVal.valueMap[GetID()] = ReserveToNativeRaw(SATOSHIDEN, currencyMap.valueMap[targetCurrencyID]); } return retVal; } @@ -2789,7 +2789,6 @@ CReserveTransactionDescriptor::CReserveTransactionDescriptor(const CTransaction { if (p.evalCode == EVAL_IDENTITY_ADVANCEDRESERVATION && identity.name == anr.name && identity.parent == anr.parent) { - // TDOD: HARDENING potentially finish validating the fees according to the currency flags |= IS_IDENTITY_DEFINITION + IS_HIGH_FEE; reservationValid = advancedReservationValid = true; } diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 5f5793fe98..3fe9fefbd2 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -107,9 +107,12 @@ UniValue getinfo(const UniValue& params, bool fHelp) proxyType proxy; GetProxy(NET_IPV4, proxy); - notarized_height = komodo_notarized_height(&prevMoMheight,¬arized_hash,¬arized_desttxid); + + //notarized_height = komodo_notarized_height(&prevMoMheight,¬arized_hash,¬arized_desttxid); //fprintf(stderr,"after notarized_height %u\n",(uint32_t)time(NULL)); + CProofRoot confirmedRoot = ConnectedChains.FinalizedChainRoot(); + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("VRSCversion", VERUS_VERSION)); obj.push_back(Pair("version", CLIENT_VERSION)); @@ -120,18 +123,11 @@ UniValue getinfo(const UniValue& params, bool fHelp) obj.push_back(Pair("notarychainid", EncodeDestination(CIdentityID(ConnectedChains.FirstNotaryChain().GetID())))); } obj.push_back(Pair("name", ConnectedChains.GetFriendlyCurrencyName(ASSETCHAINS_CHAINID))); - obj.push_back(Pair("notarized", notarized_height)); - obj.push_back(Pair("prevMoMheight", prevMoMheight)); - obj.push_back(Pair("notarizedhash", notarized_hash.ToString())); - obj.push_back(Pair("notarizedtxid", notarized_desttxid.ToString())); - txid_height = notarizedtxid_height(ASSETCHAINS_SYMBOL[0] != 0 ? (char *)"KMD" : (char *)"BTC",(char *)notarized_desttxid.ToString().c_str(),&kmdnotarized_height); - if ( txid_height > 0 ) - obj.push_back(Pair("notarizedtxid_height", txid_height)); - else obj.push_back(Pair("notarizedtxid_height", "mempool")); - if ( ASSETCHAINS_SYMBOL[0] != 0 ) - obj.push_back(Pair("KMDnotarized_height", kmdnotarized_height)); - obj.push_back(Pair("notarized_confirms", txid_height < kmdnotarized_height ? (kmdnotarized_height - txid_height + 1) : 0)); - //fprintf(stderr,"after notarized_confirms %u\n",(uint32_t)time(NULL)); + if (confirmedRoot.IsValid()) + { + obj.push_back(Pair("notarizedroot", confirmedRoot.ToUniValue())); + } + #ifdef ENABLE_WALLET if (pwalletMain) { obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); diff --git a/src/rpc/pbaasrpc.cpp b/src/rpc/pbaasrpc.cpp index f7c35698b3..46f553029c 100644 --- a/src/rpc/pbaasrpc.cpp +++ b/src/rpc/pbaasrpc.cpp @@ -2756,6 +2756,7 @@ UniValue getimports(const UniValue& params, bool fHelp) uint32_t fromHeight = 0, toHeight = INT32_MAX; uint32_t proofHeight = 0; uint32_t nHeight = chainActive.Height(); + uint32_t maximumImportRange = GetArg("-maximumimportrange", chainActive.Height()); if (params.size() > 1) { @@ -2764,8 +2765,17 @@ UniValue getimports(const UniValue& params, bool fHelp) if (params.size() > 2) { toHeight = uni_get_int64(params[2]); - proofHeight = toHeight < nHeight ? toHeight : nHeight; - toHeight = proofHeight; + } + else if (fromHeight == 0 && maximumImportRange < nHeight) + { + fromHeight = nHeight - maximumImportRange; + } + proofHeight = toHeight < nHeight ? toHeight : nHeight; + toHeight = proofHeight; + + if ((toHeight ? toHeight : nHeight) - fromHeight > maximumImportRange) + { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid range for currency state volume and rate information. Maximum range limited to " + std::to_string(GetArg("-maximportrange", chainActive.Height()))); } if (GetCurrencyDefinition(chainID, chainDef, &defHeight)) @@ -11558,19 +11568,73 @@ UniValue getinitialcurrencystate(const UniValue& params, bool fHelp) return ConnectedChains.GetCurrencyState(chainDef.GetID(), chainDef.startBlock - 1, true).ToUniValue(); } +size_t GetImports(const uint160 ¤cyID, uint32_t fromHeight, uint32_t toHeight, std::map, std::tuple>> &importMap) +{ + // which transaction are we in this block? + std::vector> addressIndex; + uint160 searchKey = CCrossChainRPCData::GetConditionID(currencyID, CCrossChainImport::CurrencyImportKey()); + CBlockIndex *pIndex; + CChainNotarizationData cnd; + + size_t initialSize = importMap.size(); + + // get all import transactions including and since this one up to the confirmed height + if (GetAddressIndex(searchKey, CScript::P2IDX, addressIndex, fromHeight, toHeight)) + { + for (auto &idx : addressIndex) + { + uint256 blkHash; + CTransaction importTx; + if (!idx.first.spending && myGetTransaction(idx.first.txhash, importTx, blkHash)) + { + CCrossChainExport ccx; + CCrossChainImport cci; + int32_t sysCCIOut; + CPBaaSNotarization importNotarization; + int32_t importNotOut; + int32_t evidenceOutStart, evidenceOutEnd; + std::vector reserveTransfers; + uint32_t importHeight = 0; + + auto importBlockIdxIt = mapBlockIndex.find(blkHash); + if (importBlockIdxIt != mapBlockIndex.end() && chainActive.Contains(importBlockIdxIt->second)) + { + importHeight = importBlockIdxIt->second->GetHeight(); + } + else + { + continue; + } + + /* UniValue scrOut(UniValue::VOBJ); + ScriptPubKeyToUniv(importTx.vout[idx.first.index].scriptPubKey, scrOut, false); + printf("%s: scriptOut: %s\n", __func__, scrOut.write(1,2).c_str()); */ + + CCrossChainImport sysCCI; + if ((cci = CCrossChainImport(importTx.vout[idx.first.index].scriptPubKey)).IsValid() && + cci.GetImportInfo(importTx, importHeight, idx.first.index, ccx, sysCCI, sysCCIOut, importNotarization, importNotOut, evidenceOutStart, evidenceOutEnd, reserveTransfers)) + { + importMap[{idx.first.blockHeight, importHeight}] = {importTx, (int)idx.first.index, cci, importNotarization, reserveTransfers}; + } + } + } + } + return importMap.size() - initialSize; +} + UniValue getcurrencystate(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 3) { throw runtime_error( - "getcurrencystate \"currencynameorid\" (\"n\") (\"connectedsystemid\")\n" + "getcurrencystate \"currencynameorid\" (\"n\") (\"conversiondatacurrency\")\n" "\nReturns the currency state(s) on the blockchain for any specified currency, either with all changes on this chain or relative to another system.\n" "\nArguments\n" " \"currencynameorid\" (string) name or i-address of currency in question" " \"n\" or \"m,n\" or \"m,n,o\" (int or string, optional) height or inclusive range with optional step at which to get the currency state\n" " If not specified, the latest currency state and height is returned\n" - " (\"connectedchainid\") (string) optional\n" + " \"conversiondatacurrency\" (string) optional - if present, market data with volumes in given currency are returned\n" "\nResult:\n" " [\n" @@ -11585,7 +11649,23 @@ UniValue getcurrencystate(const UniValue& params, bool fHelp) " \"supply\" : n,\n" " \"reserve\" : n,\n" " \"currentratio\" : n,\n" - " \"}\n" + " }\n" + " \"conversiondata\": {\n" + " \"volumecurrency\": \"reserveorbasket\",\n" + " \"volumethisinterval\": n,\n" + " \"volumepairs\": [\n" + " {\n" + " \"currency\": \"sourcecurrency\", // Currency converting from\n" + " \"convertto\": \"destinationcurrency\", // Currency converting to\n" + " \"volume\": n, // Volume denominated in \"volumecurrency\"\n" + " \"open\": n, // Conversion rates of source currency in destination\n" + " \"high\": n,\n" + " \"low\": n,\n" + " \"close\": n\n" + " },\n" + " ...,\n" + " ]\n" + " },\n" " },\n" " ]\n" @@ -11599,82 +11679,245 @@ UniValue getcurrencystate(const UniValue& params, bool fHelp) CCurrencyDefinition currencyToCheck; std::string currencyStr = uni_get_str(params[0]); - if (currencyStr.empty() || ValidateCurrencyName(currencyStr, true, ¤cyToCheck).IsNull()) - { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid currency specified"); - } - uint160 currencyID = currencyToCheck.GetID(); - - LOCK(cs_main); + uint160 currencyID; uint64_t lStart; uint64_t startEnd[3] = {0}; + uint32_t start = 0, end = 0, step = 0; - lStart = startEnd[1] = startEnd[0] = chainActive.LastTip() ? chainActive.LastTip()->GetHeight() : 1; + // if we're supposed to get market data + uint160 volumePriceCurrencyID; + CCurrencyDefinition volumePriceCurrency; + std::map, std::tuple>> importMap; - if (params.size() > 1) { - if (params[1].isStr()) + LOCK2(cs_main, mempool.cs); + + if (currencyStr.empty() || (currencyID = ValidateCurrencyName(currencyStr, true, ¤cyToCheck)).IsNull()) { - std::vector retNames; - boost::split(retNames, uni_get_str(params[1]), boost::is_any_of(",")); - Split(params[1].get_str(), startEnd, startEnd[0], 3); - if (retNames.size() == 2) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid currency specified"); + } + + uint32_t nHeight = chainActive.Height(); + + lStart = startEnd[1] = startEnd[0] = nHeight; + + if (params.size() > 1) + { + if (params[1].isStr()) { - int64_t step = 1; - int64_t delta = startEnd[1] - startEnd[0]; - while ((delta / step) > 100) + std::vector retNames; + boost::split(retNames, uni_get_str(params[1]), boost::is_any_of(",")); + Split(params[1].get_str(), startEnd, startEnd[0], 3); + if (retNames.size() == 2) { - step *= 10; + int64_t step = 1; + int64_t delta = startEnd[1] - startEnd[0]; + while ((delta / step) > 100) + { + step *= 10; + } + // default to step 1 + startEnd[2] = step; } - // default to step 1 - startEnd[2] = step; + } + else if (uni_get_int(params[1], -1) != -1) + { + lStart = startEnd[1] = startEnd[0] = uni_get_int(params[1], lStart); } } - else if (uni_get_int(params[1], -1) != -1) + + if (startEnd[0] > startEnd[1]) { - lStart = startEnd[1] = startEnd[0] = uni_get_int(params[1], lStart); + startEnd[0] = startEnd[1]; } - } - if (startEnd[0] > startEnd[1]) - { - startEnd[0] = startEnd[1]; - } + if (startEnd[1] > lStart) + { + startEnd[1] = lStart; + } - if (startEnd[1] > lStart) - { - startEnd[1] = lStart; - } + if (startEnd[1] < startEnd[0]) + { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block range for currency state"); + } - if (startEnd[1] < startEnd[0]) - { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block range for currency state"); - } + if (startEnd[2] == 0) + { + startEnd[2] = 1; + } - if (startEnd[2] == 0) - { - startEnd[2] = 1; - } + if (startEnd[2] > INT_MAX) + { + startEnd[2] = INT_MAX; + } - if (startEnd[2] > INT_MAX) - { - startEnd[2] = INT_MAX; - } + start = startEnd[0]; + end = startEnd[1]; + step = startEnd[2]; - uint32_t start = startEnd[0], end = startEnd[1], step = startEnd[2]; + if (params.size() > 2 && currencyToCheck.IsFractional()) + { + if (end - start > GetArg("-maximumimportrange", chainActive.Height())) + { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid range for currency state volume and rate information. Maximum range limited to " + std::to_string(GetArg("-maximumimportrange", chainActive.Height()))); + } + + if (currencyToCheck.systemID != ASSETCHAINS_CHAINID) + { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Can only return conversion data for currencies with a systemID of the current chain."); + } + // get currency parameter + volumePriceCurrencyID = ValidateCurrencyName(uni_get_str(params[2]), true, &volumePriceCurrency); + + // ensure it is a reserve or the basket currency name + if (volumePriceCurrencyID != currencyID && + !currencyToCheck.GetCurrenciesMap().count(volumePriceCurrencyID)) + { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Volume and pricing must be calculated in a reserve or the basket currency itself. " + uni_get_str(params[2]) + " is neither."); + } + + // get all imports + GetImports(currencyID, start, end, importMap); + } + } UniValue ret(UniValue::VARR); - for (int i = start; i <= end; i += step) + // currencySource, currencyDest, volume in volume/price currency, starting price, highest during period, lowest during period, final price (all prices in volume/price currency) + std::map,std::tuple> pairVolumePrice; + CAmount totalVolumeInVolumeCurrency = 0; + CAmount stepVolumeInVolumeCurrency = 0; + int lastEnd = start; + + for (int i = start; i <= end; i += ((i + step <= end || i == end) ? step : end - i)) { LOCK(cs_main); - CCoinbaseCurrencyState currencyState = ConnectedChains.GetCurrencyState(currencyID, i, (i + step) > end); + pairVolumePrice.clear(); + stepVolumeInVolumeCurrency = 0; + + int queryStart = lastEnd; + lastEnd = (i + 1); + + auto importIt = importMap.lower_bound({queryStart, 0}); + auto importNextIt = importIt == importMap.end() ? importMap.end() : importMap.upper_bound({i, 0}); + auto it = importIt; + CCoinbaseCurrencyState currencyState; + if (importIt != importMap.end() && it != importNextIt) + { + // if we have imports, calculate aggregated volumes, pair volumes, and OHLC in specified currency + // last import has final currency state for this interval + for (; it != importNextIt; it++) + { + currencyState = std::get<3>(it->second).currencyState; + + // get volume and price conversion rates + CCurrencyValueMap prices(currencyState.currencies, currencyState.conversionPrice); + CCurrencyValueMap viaPrices(currencyState.currencies, currencyState.viaConversionPrice); + CCurrencyValueMap conversionRates(currencyState.TargetConversionPrices(volumePriceCurrencyID, prices, viaPrices)); + + for (auto &oneRT : std::get<4>(it->second)) + { + if (oneRT.IsConversion()) + { + uint160 sourceCur = oneRT.FirstCurrency(); + uint160 destCur = oneRT.IsReserveToReserve() ? oneRT.secondReserveID : oneRT.destCurrencyID; + + CCurrencyValueMap currentRates(volumePriceCurrencyID == destCur ? conversionRates : currencyState.TargetConversionPrices(destCur, prices, viaPrices)); + + CCurrencyValueMap conversionFee = oneRT.ConversionFee(); + CAmount thisVolume = currencyState.ReserveToNativeRaw(oneRT.FirstValue() - conversionFee.valueMap[sourceCur], conversionRates.valueMap[sourceCur]); + totalVolumeInVolumeCurrency += thisVolume; + stepVolumeInVolumeCurrency += thisVolume; + std::get<0>(pairVolumePrice[{sourceCur,destCur}]) += thisVolume; + + // save open, high, low, close + if (std::get<1>(pairVolumePrice[{sourceCur,destCur}]) == 0) + { + std::get<1>(pairVolumePrice[{sourceCur,destCur}]) = currentRates.valueMap[sourceCur]; + } + std::get<2>(pairVolumePrice[{sourceCur,destCur}]) = std::max(std::get<2>(pairVolumePrice[{sourceCur,destCur}]), currentRates.valueMap[sourceCur]); + if (std::get<3>(pairVolumePrice[{sourceCur,destCur}]) == 0) + { + std::get<3>(pairVolumePrice[{sourceCur,destCur}]) = currentRates.valueMap[sourceCur]; + } + else + { + std::get<3>(pairVolumePrice[{sourceCur,destCur}]) = std::min(std::get<3>(pairVolumePrice[{sourceCur,destCur}]), currentRates.valueMap[sourceCur]); + } + std::get<4>(pairVolumePrice[{sourceCur,destCur}]) = currentRates.valueMap[sourceCur]; + + // conversion fee is converted to native currency, unless source is already native + if (sourceCur != ASSETCHAINS_CHAINID) + { + CAmount feeVolume = currencyState.ReserveToNativeRaw(conversionFee.valueMap[sourceCur], conversionRates.valueMap[sourceCur]); + totalVolumeInVolumeCurrency += feeVolume; + stepVolumeInVolumeCurrency += feeVolume; + + CCurrencyValueMap feeRates(volumePriceCurrencyID == ASSETCHAINS_CHAINID ? conversionRates : (destCur == ASSETCHAINS_CHAINID ? currentRates : currencyState.TargetConversionPrices(ASSETCHAINS_CHAINID, prices, viaPrices))); + + std::get<0>(pairVolumePrice[{sourceCur,ASSETCHAINS_CHAINID}]) += currencyState.ReserveToNativeRaw(conversionFee.valueMap[sourceCur], conversionRates.valueMap[sourceCur]); + + // save open, high, low, close for fees, in case it isn't there + if (std::get<1>(pairVolumePrice[{sourceCur,ASSETCHAINS_CHAINID}]) == 0) + { + std::get<1>(pairVolumePrice[{sourceCur,ASSETCHAINS_CHAINID}]) = feeRates.valueMap[sourceCur]; + } + std::get<2>(pairVolumePrice[{sourceCur,ASSETCHAINS_CHAINID}]) = std::max(std::get<2>(pairVolumePrice[{sourceCur,ASSETCHAINS_CHAINID}]), feeRates.valueMap[sourceCur]); + if (std::get<3>(pairVolumePrice[{sourceCur,ASSETCHAINS_CHAINID}]) == 0) + { + std::get<3>(pairVolumePrice[{sourceCur,ASSETCHAINS_CHAINID}]) = feeRates.valueMap[sourceCur]; + } + else + { + std::get<3>(pairVolumePrice[{sourceCur,ASSETCHAINS_CHAINID}]) = std::min(std::get<3>(pairVolumePrice[{sourceCur,ASSETCHAINS_CHAINID}]), feeRates.valueMap[sourceCur]); + } + std::get<4>(pairVolumePrice[{sourceCur,ASSETCHAINS_CHAINID}]) = feeRates.valueMap[sourceCur]; + } + } + } + } + } + else + { + currencyState = ConnectedChains.GetCurrencyState(currencyID, i, (i + step) > end); + } UniValue entry(UniValue::VOBJ); entry.push_back(Pair("height", i)); entry.push_back(Pair("blocktime", (uint64_t)chainActive.LastTip()->nTime)); - CAmount price; entry.push_back(Pair("currencystate", currencyState.ToUniValue())); + + if (pairVolumePrice.size()) + { + UniValue conversionData(UniValue::VOBJ); + UniValue pairArray(UniValue::VARR); + + conversionData.pushKV("volumecurrency", ConnectedChains.GetFriendlyCurrencyName(volumePriceCurrencyID)); + conversionData.pushKV("volumethisinterval", ValueFromAmount(stepVolumeInVolumeCurrency)); + + // output conversions as source, destination, volume, open, high, low, close + for (auto &oneVolPrice : pairVolumePrice) + { + UniValue onePairEntry(UniValue::VOBJ); + onePairEntry.pushKV("currency", ConnectedChains.GetFriendlyCurrencyName(oneVolPrice.first.first)); + onePairEntry.pushKV("convertto", ConnectedChains.GetFriendlyCurrencyName(oneVolPrice.first.second)); + onePairEntry.pushKV("volume", ValueFromAmount(std::get<0>(oneVolPrice.second))); + onePairEntry.pushKV("open", ValueFromAmount(std::get<1>(oneVolPrice.second))); + onePairEntry.pushKV("high", ValueFromAmount(std::get<2>(oneVolPrice.second))); + onePairEntry.pushKV("low", ValueFromAmount(std::get<3>(oneVolPrice.second))); + onePairEntry.pushKV("close", ValueFromAmount(std::get<4>(oneVolPrice.second))); + pairArray.push_back(onePairEntry); + } + conversionData.pushKV("volumepairs", pairArray); + entry.pushKV("conversiondata",conversionData); + } + + ret.push_back(entry); + } + if (totalVolumeInVolumeCurrency) + { + UniValue entry(UniValue::VOBJ); + entry.pushKV("totalvolume", ValueFromAmount(totalVolumeInVolumeCurrency)); ret.push_back(entry); } return ret; diff --git a/src/version.h b/src/version.h index 2a88651c63..1c5cbdb9e4 100644 --- a/src/version.h +++ b/src/version.h @@ -36,6 +36,6 @@ static const int MEMPOOL_GD_VERSION = 60002; static const int NO_BLOOM_VERSION = 170004; #define KOMODO_VERSION "0.2.1" -#define VERUS_VERSION "1.2.3-2" +#define VERUS_VERSION "1.2.3-3" #endif // BITCOIN_VERSION_H