Verus Coin - this coin was backdoored by it's lead dev and should not be trusted!
https://git.hush.is/duke/backdoors/src/branch/master/vrsc.md
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1773 lines
60 KiB
1773 lines
60 KiB
// Copyright (c) 2010 Satoshi Nakamoto
|
|
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
|
|
|
#include <univalue.h>
|
|
#include "rpc/protocol.h"
|
|
#include "pbaas/crosschainrpc.h"
|
|
#include "pbaas/identity.h"
|
|
#include "rpc/client.h"
|
|
#include "util.h"
|
|
|
|
using namespace std;
|
|
extern std::string VERUS_CHAINNAME;
|
|
|
|
class CRPCConvertParam
|
|
{
|
|
public:
|
|
std::string methodName; //!< method whose params want conversion
|
|
int paramIdx; //!< 0-based idx of param to convert
|
|
};
|
|
|
|
// DUMMY for compile - only used in server
|
|
UniValue RPCCallRoot(const string& strMethod, const UniValue& params, int timeout)
|
|
{
|
|
printf("%s: Unable to communicate with specified blockchain network\n", __func__);
|
|
return NullUniValue;
|
|
}
|
|
|
|
bool SetThisChain(const UniValue &chainDefinition, CCurrencyDefinition *retDef) {
|
|
return true; // (?) pbaas/pbaas.h
|
|
}
|
|
|
|
CAmount AmountFromValueNoErr(const UniValue& value)
|
|
{
|
|
try
|
|
{
|
|
CAmount amount;
|
|
if (!value.isNum() && !value.isStr())
|
|
{
|
|
amount = 0;
|
|
}
|
|
else if (!ParseFixedPoint(value.getValStr(), 8, &amount))
|
|
{
|
|
amount = 0;
|
|
}
|
|
else if (!MoneyRange(amount))
|
|
{
|
|
amount = 0;
|
|
}
|
|
return amount;
|
|
}
|
|
catch(const std::exception& e)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
|
|
std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)
|
|
{
|
|
// Skip & count leading zeroes.
|
|
int zeroes = 0;
|
|
while (pbegin != pend && *pbegin == 0) {
|
|
pbegin++;
|
|
zeroes++;
|
|
}
|
|
// Allocate enough space in big-endian base58 representation.
|
|
std::vector<unsigned char> b58((pend - pbegin) * 138 / 100 + 1); // log(256) / log(58), rounded up.
|
|
// Process the bytes.
|
|
while (pbegin != pend) {
|
|
int carry = *pbegin;
|
|
// Apply "b58 = b58 * 256 + ch".
|
|
for (std::vector<unsigned char>::reverse_iterator it = b58.rbegin(); it != b58.rend(); it++) {
|
|
carry += 256 * (*it);
|
|
*it = carry % 58;
|
|
carry /= 58;
|
|
}
|
|
assert(carry == 0);
|
|
pbegin++;
|
|
}
|
|
// Skip leading zeroes in base58 result.
|
|
std::vector<unsigned char>::iterator it = b58.begin();
|
|
while (it != b58.end() && *it == 0)
|
|
it++;
|
|
// Translate the result into a string.
|
|
std::string str;
|
|
str.reserve(zeroes + (b58.end() - it));
|
|
str.assign(zeroes, '1');
|
|
while (it != b58.end())
|
|
str += pszBase58[*(it++)];
|
|
return str;
|
|
}
|
|
|
|
std::string EncodeBase58(const std::vector<unsigned char>& vch)
|
|
{
|
|
return EncodeBase58(vch.data(), vch.data() + vch.size());
|
|
}
|
|
|
|
std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn)
|
|
{
|
|
// add 4-byte hash check to the end
|
|
std::vector<unsigned char> vch(vchIn);
|
|
uint256 hash = Hash(vch.begin(), vch.end());
|
|
vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4);
|
|
return EncodeBase58(vch);
|
|
}
|
|
|
|
bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch)
|
|
{
|
|
// Skip leading spaces.
|
|
while (*psz && isspace(*psz))
|
|
psz++;
|
|
// Skip and count leading '1's.
|
|
int zeroes = 0;
|
|
while (*psz == '1') {
|
|
zeroes++;
|
|
psz++;
|
|
}
|
|
// Allocate enough space in big-endian base256 representation.
|
|
std::vector<unsigned char> b256(strlen(psz) * 733 / 1000 + 1); // log(58) / log(256), rounded up.
|
|
// Process the characters.
|
|
while (*psz && !isspace(*psz)) {
|
|
// Decode base58 character
|
|
const char* ch = strchr(pszBase58, *psz);
|
|
if (ch == NULL)
|
|
return false;
|
|
// Apply "b256 = b256 * 58 + ch".
|
|
int carry = ch - pszBase58;
|
|
for (std::vector<unsigned char>::reverse_iterator it = b256.rbegin(); it != b256.rend(); it++) {
|
|
carry += 58 * (*it);
|
|
*it = carry % 256;
|
|
carry /= 256;
|
|
}
|
|
assert(carry == 0);
|
|
psz++;
|
|
}
|
|
// Skip trailing spaces.
|
|
while (isspace(*psz))
|
|
psz++;
|
|
if (*psz != 0)
|
|
return false;
|
|
// Skip leading zeroes in b256.
|
|
std::vector<unsigned char>::iterator it = b256.begin();
|
|
while (it != b256.end() && *it == 0)
|
|
it++;
|
|
// Copy result into output vector.
|
|
vch.reserve(zeroes + (b256.end() - it));
|
|
vch.assign(zeroes, 0x00);
|
|
while (it != b256.end())
|
|
vch.push_back(*(it++));
|
|
return true;
|
|
}
|
|
|
|
bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet)
|
|
{
|
|
return DecodeBase58(str.c_str(), vchRet);
|
|
}
|
|
|
|
bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet)
|
|
{
|
|
if (!DecodeBase58(psz, vchRet) ||
|
|
(vchRet.size() < 4)) {
|
|
vchRet.clear();
|
|
return false;
|
|
}
|
|
// re-calculate the checksum, insure it matches the included 4-byte checksum
|
|
uint256 hash = Hash(vchRet.begin(), vchRet.end() - 4);
|
|
if (memcmp(&hash, &vchRet.end()[-4], 4) != 0) {
|
|
vchRet.clear();
|
|
return false;
|
|
}
|
|
vchRet.resize(vchRet.size() - 4);
|
|
return true;
|
|
}
|
|
|
|
bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet)
|
|
{
|
|
return DecodeBase58Check(str.c_str(), vchRet);
|
|
}
|
|
|
|
class DestinationEncoder : public boost::static_visitor<std::string>
|
|
{
|
|
public:
|
|
std::vector<std::vector<unsigned char>> base58Prefixes;
|
|
|
|
enum Base58Type {
|
|
PUBKEY_ADDRESS,
|
|
SCRIPT_ADDRESS,
|
|
IDENTITY_ADDRESS,
|
|
INDEX_ADDRESS,
|
|
QUANTUM_ADDRESS,
|
|
SECRET_KEY,
|
|
EXT_PUBLIC_KEY,
|
|
EXT_SECRET_KEY,
|
|
|
|
ZCPAYMENT_ADDRRESS,
|
|
ZCSPENDING_KEY,
|
|
ZCVIEWING_KEY,
|
|
|
|
MAX_BASE58_TYPES
|
|
};
|
|
|
|
DestinationEncoder() :
|
|
base58Prefixes({{60}, {85}, {102}, {137}, {58}, {188}, {0x04, 0x88, 0xB2, 0x1E}, {0x04, 0x88, 0xAD, 0xE4}, {22,154}, {0xA8,0xAB,0xD3}, {171,54}})
|
|
{
|
|
}
|
|
|
|
std::string operator()(const CKeyID& id) const
|
|
{
|
|
std::vector<unsigned char> data = base58Prefixes[CChainParams::PUBKEY_ADDRESS];
|
|
data.insert(data.end(), id.begin(), id.end());
|
|
return EncodeBase58Check(data);
|
|
}
|
|
|
|
std::string operator()(const CPubKey& key) const
|
|
{
|
|
std::vector<unsigned char> data = base58Prefixes[CChainParams::PUBKEY_ADDRESS];
|
|
CKeyID id = key.GetID();
|
|
data.insert(data.end(), id.begin(), id.end());
|
|
return EncodeBase58Check(data);
|
|
}
|
|
|
|
std::string operator()(const CScriptID& id) const
|
|
{
|
|
std::vector<unsigned char> data = base58Prefixes[CChainParams::SCRIPT_ADDRESS];
|
|
data.insert(data.end(), id.begin(), id.end());
|
|
return EncodeBase58Check(data);
|
|
}
|
|
|
|
std::string operator()(const CIdentityID& id) const
|
|
{
|
|
std::vector<unsigned char> data = base58Prefixes[CChainParams::IDENTITY_ADDRESS];
|
|
data.insert(data.end(), id.begin(), id.end());
|
|
return EncodeBase58Check(data);
|
|
}
|
|
|
|
std::string operator()(const CIndexID& id) const
|
|
{
|
|
std::vector<unsigned char> data = base58Prefixes[CChainParams::INDEX_ADDRESS];
|
|
data.insert(data.end(), id.begin(), id.end());
|
|
return EncodeBase58Check(data);
|
|
}
|
|
|
|
std::string operator()(const CQuantumID& id) const
|
|
{
|
|
std::vector<unsigned char> data = base58Prefixes[CChainParams::QUANTUM_ADDRESS];
|
|
data.insert(data.end(), id.begin(), id.end());
|
|
return EncodeBase58Check(data);
|
|
}
|
|
|
|
std::string operator()(const CNoDestination& no) const { return {}; }
|
|
};
|
|
|
|
std::string EncodeDestination(const CTxDestination& dest)
|
|
{
|
|
return boost::apply_visitor(DestinationEncoder(), dest);
|
|
}
|
|
|
|
CTxDestination DecodeDestination(const std::string& str)
|
|
{
|
|
DestinationEncoder encoder;
|
|
std::vector<unsigned char> data;
|
|
uint160 hash;
|
|
if (DecodeBase58Check(str, data)) {
|
|
// base58-encoded Bitcoin addresses.
|
|
// The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
|
|
const std::vector<unsigned char>& pubkey_prefix = encoder.base58Prefixes[CChainParams::PUBKEY_ADDRESS];
|
|
if (data.size() == hash.size() + pubkey_prefix.size() && std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin())) {
|
|
std::copy(data.begin() + pubkey_prefix.size(), data.end(), hash.begin());
|
|
return CKeyID(hash);
|
|
}
|
|
|
|
// The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script.
|
|
const std::vector<unsigned char>& script_prefix = encoder.base58Prefixes[CChainParams::SCRIPT_ADDRESS];
|
|
if (data.size() == hash.size() + script_prefix.size() && std::equal(script_prefix.begin(), script_prefix.end(), data.begin())) {
|
|
std::copy(data.begin() + script_prefix.size(), data.end(), hash.begin());
|
|
return CScriptID(hash);
|
|
}
|
|
|
|
const std::vector<unsigned char>& identity_prefix = encoder.base58Prefixes[CChainParams::IDENTITY_ADDRESS];
|
|
if (data.size() == hash.size() + identity_prefix.size() && std::equal(identity_prefix.begin(), identity_prefix.end(), data.begin())) {
|
|
std::copy(data.begin() + identity_prefix.size(), data.end(), hash.begin());
|
|
return CIdentityID(hash);
|
|
}
|
|
|
|
const std::vector<unsigned char>& index_prefix = encoder.base58Prefixes[CChainParams::INDEX_ADDRESS];
|
|
if (data.size() == hash.size() + index_prefix.size() && std::equal(index_prefix.begin(), index_prefix.end(), data.begin())) {
|
|
std::copy(data.begin() + index_prefix.size(), data.end(), hash.begin());
|
|
return CIndexID(hash);
|
|
}
|
|
|
|
const std::vector<unsigned char>& quantum_prefix = encoder.base58Prefixes[CChainParams::QUANTUM_ADDRESS];
|
|
if (data.size() == hash.size() + quantum_prefix.size() && std::equal(quantum_prefix.begin(), quantum_prefix.end(), data.begin())) {
|
|
std::copy(data.begin() + quantum_prefix.size(), data.end(), hash.begin());
|
|
return CQuantumID(hash);
|
|
}
|
|
}
|
|
else if (std::count(str.begin(), str.end(), '@') == 1)
|
|
{
|
|
uint160 parent;
|
|
std::string cleanName = CleanName(str, parent);
|
|
if (cleanName != "")
|
|
{
|
|
parent.SetNull();
|
|
return CIdentityID(CIdentity::GetID(str, parent));
|
|
}
|
|
}
|
|
|
|
return CNoDestination();
|
|
}
|
|
|
|
class DestinationID : public boost::static_visitor<uint160>
|
|
{
|
|
public:
|
|
DestinationID() {}
|
|
|
|
uint160 operator()(const CKeyID& id) const
|
|
{
|
|
return (uint160)id;
|
|
}
|
|
|
|
uint160 operator()(const CPubKey& key) const
|
|
{
|
|
return (uint160)key.GetID();
|
|
}
|
|
|
|
uint160 operator()(const CScriptID& id) const
|
|
{
|
|
return (uint160)id;
|
|
}
|
|
|
|
uint160 operator()(const CIdentityID& id) const
|
|
{
|
|
return (uint160)id;
|
|
}
|
|
|
|
uint160 operator()(const CIndexID& id) const
|
|
{
|
|
return (uint160)id;
|
|
}
|
|
|
|
uint160 operator()(const CQuantumID& id) const
|
|
{
|
|
return (uint160)id;
|
|
}
|
|
|
|
uint160 operator()(const CNoDestination& no) const { return CKeyID(); }
|
|
};
|
|
|
|
uint160 GetDestinationID(const CTxDestination dest)
|
|
{
|
|
return boost::apply_visitor(DestinationID(), dest);
|
|
}
|
|
|
|
uint160 DecodeCurrencyName(std::string currencyStr)
|
|
{
|
|
uint160 retVal;
|
|
if (!currencyStr.size())
|
|
{
|
|
return retVal;
|
|
}
|
|
if (currencyStr.back() == '@')
|
|
{
|
|
return retVal;
|
|
}
|
|
std::string copyStr = currencyStr;
|
|
|
|
uint160 parent;
|
|
|
|
currencyStr = CleanName(currencyStr, parent, true, currencyStr.back() != '.');
|
|
|
|
if (!parent.IsNull() && CCurrencyDefinition::GetID(currencyStr, parent) == ASSETCHAINS_CHAINID)
|
|
{
|
|
return ASSETCHAINS_CHAINID;
|
|
}
|
|
|
|
CTxDestination currencyDest = DecodeDestination(currencyStr);
|
|
|
|
if (currencyDest.which() == COptCCParams::ADDRTYPE_INVALID)
|
|
{
|
|
currencyDest = DecodeDestination(copyStr + "@");
|
|
}
|
|
if (currencyDest.which() != COptCCParams::ADDRTYPE_INVALID)
|
|
{
|
|
return GetDestinationID(currencyDest);
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
uint160 CCurrencyDefinition::GetID(const std::string &Name, uint160 &Parent)
|
|
{
|
|
return CIdentity::GetID(Name, Parent);
|
|
}
|
|
|
|
CCurrencyDefinition::CCurrencyDefinition(const UniValue &obj) :
|
|
initialFractionalSupply(0),
|
|
gatewayConverterIssuance(0),
|
|
preLaunchDiscount(0),
|
|
preLaunchCarveOut(0),
|
|
minNotariesConfirm(0),
|
|
idRegistrationFees(IDENTITY_REGISTRATION_FEE),
|
|
idReferralLevels(DEFAULT_ID_REFERRAL_LEVELS),
|
|
idImportFees(IDENTITY_IMPORT_FEE),
|
|
currencyRegistrationFee(CURRENCY_REGISTRATION_FEE),
|
|
pbaasSystemLaunchFee(PBAAS_SYSTEM_LAUNCH_FEE),
|
|
currencyImportFee(CURRENCY_IMPORT_FEE),
|
|
transactionImportFee(TRANSACTION_CROSSCHAIN_FEE >> 1),
|
|
transactionExportFee(TRANSACTION_CROSSCHAIN_FEE >> 1),
|
|
initialBits(DEFAULT_START_TARGET)
|
|
{
|
|
try
|
|
{
|
|
nVersion = uni_get_int64(find_value(obj, "version"), VERSION_CURRENT);
|
|
options = (uint32_t)uni_get_int64(find_value(obj, "options"));
|
|
name = std::string(uni_get_str(find_value(obj, "name")), 0, (KOMODO_ASSETCHAIN_MAXLEN - 1));
|
|
|
|
std::string parentStr = uni_get_str(find_value(obj, "parent"));
|
|
if (parentStr != "")
|
|
{
|
|
parent = DecodeCurrencyName(parentStr);
|
|
if (parent.IsNull())
|
|
{
|
|
LogPrintf("%s: invalid parent for currency: %s\n", __func__, parentStr.c_str());
|
|
nVersion = PBAAS_VERSION_INVALID;
|
|
return;
|
|
}
|
|
}
|
|
|
|
name = CleanName(name, parent);
|
|
|
|
std::string systemIDStr = uni_get_str(find_value(obj, "systemid"));
|
|
if (systemIDStr != "")
|
|
{
|
|
systemID = DecodeCurrencyName(systemIDStr);
|
|
// if we have a system, but it is invalid, the json for this definition cannot be valid
|
|
if (systemID.IsNull())
|
|
{
|
|
nVersion = PBAAS_VERSION_INVALID;
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
systemID = parent;
|
|
}
|
|
|
|
gatewayConverterName = uni_get_str(find_value(obj, "gatewayconvertername"));
|
|
if (!gatewayConverterName.empty())
|
|
{
|
|
if (!(IsPBaaSChain() || IsGateway()) || (IsPBaaSChain() && IsGateway()))
|
|
{
|
|
LogPrintf("%s: a gateway converter currency may only be defined as part of a gateway or PBaaS system definition\n", __func__);
|
|
nVersion = PBAAS_VERSION_INVALID;
|
|
return;
|
|
}
|
|
else if (IsGateway())
|
|
{
|
|
gatewayID = GetID();
|
|
}
|
|
uint160 parent = GetID();
|
|
std::string cleanGatewayName = CleanName(gatewayConverterName, parent, true);
|
|
uint160 converterID = GetID(cleanGatewayName, parent);
|
|
if (parent != GetID())
|
|
{
|
|
LogPrintf("%s: invalid name for gateway converter %s\n", __func__, cleanGatewayName.c_str());
|
|
nVersion = PBAAS_VERSION_INVALID;
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (IsPBaaSChain() || IsGateway() || IsGatewayConverter())
|
|
{
|
|
gatewayConverterIssuance = AmountFromValueNoErr(find_value(obj, "gatewayconverterissuance"));
|
|
}
|
|
|
|
notarizationProtocol = (ENotarizationProtocol)uni_get_int(find_value(obj, "notarizationprotocol"), (int32_t)NOTARIZATION_AUTO);
|
|
if (notarizationProtocol != NOTARIZATION_AUTO && notarizationProtocol != NOTARIZATION_NOTARY_CONFIRM)
|
|
{
|
|
LogPrintf("%s: notarization protocol for PBaaS chains must be %d (NOTARIZATION_AUTO) or %d (NOTARIZATION_NOTARY_CONFIRM)\n", __func__, (int)NOTARIZATION_NOTARY_CONFIRM);
|
|
nVersion = PBAAS_VERSION_INVALID;
|
|
return;
|
|
}
|
|
proofProtocol = (EProofProtocol)uni_get_int(find_value(obj, "proofprotocol"), (int32_t)PROOF_PBAASMMR);
|
|
if (proofProtocol != PROOF_PBAASMMR && proofProtocol != PROOF_CHAINID && proofProtocol != PROOF_ETHNOTARIZATION)
|
|
{
|
|
LogPrintf("%s: proofprotocol must be %d, %d, or %d\n", __func__, (int)PROOF_PBAASMMR, (int)PROOF_CHAINID, (int)PROOF_ETHNOTARIZATION);
|
|
nVersion = PBAAS_VERSION_INVALID;
|
|
return;
|
|
}
|
|
|
|
// TODO: HARDENING - ensure that it makes sense for a chain to have PROOF_CHAINID still or disallow
|
|
// to enable it, we will need to ensure that all imports and notarizations are spendable to the chain ID and are
|
|
// considered valid by definition
|
|
if (proofProtocol == PROOF_CHAINID && IsPBaaSChain())
|
|
{
|
|
LogPrintf("%s: proofprotocol %d not yet implemented\n", __func__, (int)PROOF_CHAINID);
|
|
nVersion = PBAAS_VERSION_INVALID;
|
|
return;
|
|
}
|
|
|
|
nativeCurrencyID = CTransferDestination();
|
|
|
|
std::string launchIDStr = uni_get_str(find_value(obj, "launchsystemid"));
|
|
if (launchIDStr != "")
|
|
{
|
|
launchSystemID = DecodeCurrencyName(launchIDStr);
|
|
// if we have a system, but it is invalid, the json for this definition cannot be valid
|
|
if (launchSystemID.IsNull())
|
|
{
|
|
nVersion = PBAAS_VERSION_INVALID;
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
launchSystemID = parent;
|
|
}
|
|
|
|
startBlock = (uint32_t)uni_get_int64(find_value(obj, "startblock"));
|
|
endBlock = (uint32_t)uni_get_int64(find_value(obj, "endblock"));
|
|
|
|
int32_t totalReserveWeight = IsFractional() ? SATOSHIDEN : 0;
|
|
UniValue currencyArr = find_value(obj, "currencies");
|
|
UniValue weightArr = find_value(obj, "weights");
|
|
UniValue conversionArr = find_value(obj, "conversions");
|
|
UniValue minPreconvertArr = find_value(obj, "minpreconversion");
|
|
UniValue maxPreconvertArr = find_value(obj, "maxpreconversion");
|
|
UniValue initialContributionArr = find_value(obj, "initialcontributions");
|
|
|
|
if (currencyArr.isArray() && currencyArr.size())
|
|
{
|
|
contributions = preconverted = std::vector<int64_t>(currencyArr.size());
|
|
|
|
if (initialContributionArr.isNull())
|
|
{
|
|
initialContributionArr = UniValue(UniValue::VARR);
|
|
for (int i = 0; i < currencyArr.size(); i++)
|
|
{
|
|
initialContributionArr.push_back((CAmount)0);
|
|
}
|
|
}
|
|
|
|
if (IsFractional())
|
|
{
|
|
preLaunchDiscount = AmountFromValueNoErr(find_value(obj, "prelaunchdiscount"));
|
|
initialFractionalSupply = AmountFromValueNoErr(find_value(obj, "initialsupply"));
|
|
|
|
if (!initialFractionalSupply)
|
|
{
|
|
LogPrintf("%s: cannot specify zero initial supply for fractional currency\n", __func__);
|
|
printf("%s: cannot specify zero initial supply for fractional currency\n", __func__);
|
|
nVersion = PBAAS_VERSION_INVALID;
|
|
}
|
|
|
|
preLaunchCarveOut = AmountFromValueNoErr(find_value(obj, "prelaunchcarveout"));
|
|
|
|
// if weights are defined, use them as relative ratios of each member currency
|
|
if (weightArr.isArray() && weightArr.size())
|
|
{
|
|
if (weightArr.size() != currencyArr.size())
|
|
{
|
|
LogPrintf("%s: reserve currency weights must be specified for all currencies\n", __func__);
|
|
nVersion = PBAAS_VERSION_INVALID;
|
|
}
|
|
else
|
|
{
|
|
CAmount total = 0;
|
|
for (int i = 0; i < currencyArr.size(); i++)
|
|
{
|
|
int32_t weight = (int32_t)AmountFromValueNoErr(weightArr[i]);
|
|
if (weight <= 0)
|
|
{
|
|
nVersion = PBAAS_VERSION_INVALID;
|
|
total = 0;
|
|
break;
|
|
}
|
|
total += weight;
|
|
weights.push_back(weight);
|
|
}
|
|
if (nVersion != PBAAS_VERSION_INVALID)
|
|
{
|
|
// calculate each weight as a relative part of the total
|
|
// reserve weight
|
|
int64_t totalRelativeWeight = 0;
|
|
for (auto &onew : weights)
|
|
{
|
|
totalRelativeWeight += onew;
|
|
}
|
|
|
|
int weightIdx;
|
|
arith_uint256 bigReserveWeight(totalReserveWeight);
|
|
int32_t reserveLeft = totalReserveWeight;
|
|
for (weightIdx = 0; weightIdx < weights.size(); weightIdx++)
|
|
{
|
|
CAmount amount = (bigReserveWeight * arith_uint256(weights[weightIdx]) / arith_uint256(totalRelativeWeight)).GetLow64();
|
|
if (reserveLeft <= amount || (weightIdx + 1) == weights.size())
|
|
{
|
|
amount = reserveLeft;
|
|
}
|
|
reserveLeft -= amount;
|
|
weights[weightIdx] = amount;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (totalReserveWeight)
|
|
{
|
|
uint32_t oneWeight = totalReserveWeight / currencyArr.size();
|
|
uint32_t mod = totalReserveWeight % currencyArr.size();
|
|
for (int i = 0; i < currencyArr.size(); i++)
|
|
{
|
|
// distribute remainder of weight among first come currencies
|
|
int32_t weight = oneWeight;
|
|
if (mod > 0)
|
|
{
|
|
weight++;
|
|
mod--;
|
|
}
|
|
weights.push_back(weight);
|
|
}
|
|
}
|
|
}
|
|
|
|
// if we have weights, we can be a fractional currency
|
|
if (weights.size())
|
|
{
|
|
// if we are fractional, explicit conversion values are not valid
|
|
// and are based on non-zero, initial contributions relative to supply
|
|
if ((conversionArr.isArray() && conversionArr.size() != currencyArr.size()) ||
|
|
!initialContributionArr.isArray() ||
|
|
initialContributionArr.size() != currencyArr.size() ||
|
|
weights.size() != currencyArr.size() ||
|
|
!IsFractional())
|
|
{
|
|
LogPrintf("%s: fractional currencies must have weights, initial contributions in at least one currency\n", __func__);
|
|
nVersion = PBAAS_VERSION_INVALID;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if we are not a reserve currency, we either have a conversion vector, or we are not convertible at all
|
|
if (IsFractional())
|
|
{
|
|
LogPrintf("%s: reserve currencies must define currency weight\n", __func__);
|
|
nVersion = PBAAS_VERSION_INVALID;
|
|
}
|
|
else if (conversionArr.isArray() && conversionArr.size() && conversionArr.size() != currencyArr.size())
|
|
{
|
|
LogPrintf("%s: non-reserve currencies must define all conversion rates for supported currencies if they define any\n", __func__);
|
|
nVersion = PBAAS_VERSION_INVALID;
|
|
}
|
|
else if (initialContributionArr.isArray() && initialContributionArr.size() != currencyArr.size())
|
|
{
|
|
LogPrintf("%s: initial contributions for currencies must all be specified if any are specified\n", __func__);
|
|
nVersion = PBAAS_VERSION_INVALID;
|
|
}
|
|
}
|
|
|
|
if (nVersion != PBAAS_VERSION_INVALID && IsFractional())
|
|
{
|
|
if (minPreconvertArr.isArray() && minPreconvertArr.size() && minPreconvertArr.size() != currencyArr.size())
|
|
{
|
|
LogPrintf("%s: currencies with minimum conversion required must define all minimums if they define any\n", __func__);
|
|
nVersion = PBAAS_VERSION_INVALID;
|
|
}
|
|
if (maxPreconvertArr.isArray() && maxPreconvertArr.size() && maxPreconvertArr.size() != currencyArr.size())
|
|
{
|
|
LogPrintf("%s: currencies that include maximum conversions on pre-launch must specify all maximums\n", __func__);
|
|
nVersion = PBAAS_VERSION_INVALID;
|
|
}
|
|
if (initialContributionArr.isArray() && initialContributionArr.size() && initialContributionArr.size() != currencyArr.size())
|
|
{
|
|
LogPrintf("%s: currencies that include initial contributions in one currency on pre-launch must specify all currency amounts\n", __func__);
|
|
nVersion = PBAAS_VERSION_INVALID;
|
|
}
|
|
}
|
|
|
|
bool isInitialContributions = initialContributionArr.isArray() && initialContributionArr.size();
|
|
bool isPreconvertMin = minPreconvertArr.isArray() && minPreconvertArr.size();
|
|
bool isPreconvertMax = maxPreconvertArr.isArray() && maxPreconvertArr.size();
|
|
bool explicitConversions = (!IsFractional() && conversionArr.isArray()) && conversionArr.size();
|
|
|
|
for (int i = 0; nVersion != PBAAS_VERSION_INVALID && i < currencyArr.size(); i++)
|
|
{
|
|
uint160 currencyID = DecodeCurrencyName(uni_get_str(currencyArr[i]));
|
|
// if we have a destination, but it is invalid, the json for this definition cannot be valid
|
|
if (currencyID.IsNull())
|
|
{
|
|
nVersion = PBAAS_VERSION_INVALID;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
currencies.push_back(currencyID);
|
|
}
|
|
|
|
if (isInitialContributions && i < initialContributionArr.size())
|
|
{
|
|
int64_t contrib = AmountFromValueNoErr(initialContributionArr[i]);
|
|
contributions[i] = contrib;
|
|
preconverted[i] = contrib;
|
|
}
|
|
|
|
int64_t minPre = 0;
|
|
if (isPreconvertMin)
|
|
{
|
|
minPre = AmountFromValueNoErr(minPreconvertArr[i]);
|
|
if (minPre < 0)
|
|
{
|
|
LogPrintf("%s: minimum preconversions for any currency may not be less than 0\n", __func__);
|
|
nVersion = PBAAS_VERSION_INVALID;
|
|
break;
|
|
}
|
|
minPreconvert.push_back(minPre);
|
|
}
|
|
if (isPreconvertMax)
|
|
{
|
|
int64_t maxPre = AmountFromValueNoErr(maxPreconvertArr[i]);
|
|
if (maxPre < 0 || maxPre < minPre)
|
|
{
|
|
LogPrintf("%s: maximum preconversions for any currency may not be less than 0 or minimum\n", __func__);
|
|
nVersion = PBAAS_VERSION_INVALID;
|
|
break;
|
|
}
|
|
maxPreconvert.push_back(maxPre);
|
|
}
|
|
if (explicitConversions)
|
|
{
|
|
int64_t conversion = AmountFromValueNoErr(conversionArr[i]);
|
|
if (conversion < 0)
|
|
{
|
|
LogPrintf("%s: conversions for any currency must be greater than 0\n", __func__);
|
|
nVersion = PBAAS_VERSION_INVALID;
|
|
break;
|
|
}
|
|
conversions.push_back(conversion);
|
|
}
|
|
else
|
|
{
|
|
conversions.push_back(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
UniValue preallocationArr = find_value(obj, "preallocations");
|
|
if (preallocationArr.isArray())
|
|
{
|
|
for (int i = 0; i < preallocationArr.size(); i++)
|
|
{
|
|
std::vector<std::string> preallocationKey = preallocationArr[i].getKeys();
|
|
std::vector<UniValue> preallocationValue = preallocationArr[i].getValues();
|
|
if (preallocationKey.size() != 1 || preallocationValue.size() != 1)
|
|
{
|
|
LogPrintf("%s: each preallocation entry must contain one destination identity and one amount\n", __func__);
|
|
printf("%s: each preallocation entry must contain one destination identity and one amount\n", __func__);
|
|
nVersion = PBAAS_VERSION_INVALID;
|
|
break;
|
|
}
|
|
|
|
CTxDestination preallocDest = DecodeDestination(preallocationKey[0]);
|
|
|
|
if (preallocDest.which() != COptCCParams::ADDRTYPE_ID && preallocDest.which() != COptCCParams::ADDRTYPE_INVALID)
|
|
{
|
|
LogPrintf("%s: preallocation destination must be an identity\n", __func__);
|
|
nVersion = PBAAS_VERSION_INVALID;
|
|
break;
|
|
}
|
|
|
|
CAmount preAllocAmount = AmountFromValueNoErr(preallocationValue[0]);
|
|
if (preAllocAmount <= 0)
|
|
{
|
|
LogPrintf("%s: preallocation values must be greater than zero\n", __func__);
|
|
nVersion = PBAAS_VERSION_INVALID;
|
|
break;
|
|
}
|
|
preAllocation.push_back(make_pair(CIdentityID(GetDestinationID(preallocDest)), preAllocAmount));
|
|
}
|
|
}
|
|
|
|
UniValue notaryArr = find_value(obj, "notaries");
|
|
minNotariesConfirm = 0;
|
|
if (notaryArr.isArray())
|
|
{
|
|
for (int i = 0; i < notaryArr.size(); i++)
|
|
{
|
|
CIdentityID notaryID;
|
|
CTxDestination notaryDest = DecodeDestination(uni_get_str(notaryArr[i]));
|
|
notaryID = GetDestinationID(notaryDest);
|
|
// if we have a destination, but it is invalid, the json for this definition cannot be valid
|
|
if (notaryID.IsNull())
|
|
{
|
|
nVersion = PBAAS_VERSION_INVALID;
|
|
}
|
|
else
|
|
{
|
|
notaries.push_back(notaryID);
|
|
}
|
|
}
|
|
minNotariesConfirm = uni_get_int(find_value(obj, "minnotariesconfirm"));
|
|
}
|
|
|
|
UniValue registrationFeeValue = find_value(obj, "idregistrationfees");
|
|
idRegistrationFees = registrationFeeValue.isNull() ? idRegistrationFees : AmountFromValueNoErr(registrationFeeValue);
|
|
|
|
idReferralLevels = uni_get_int(find_value(obj, "idreferrallevels"), idReferralLevels);
|
|
|
|
registrationFeeValue = find_value(obj, "idimportfees");
|
|
idImportFees = registrationFeeValue.isNull() ? idImportFees : AmountFromValueNoErr(registrationFeeValue);
|
|
|
|
registrationFeeValue = find_value(obj, "currencyregistrationfee");
|
|
currencyRegistrationFee = registrationFeeValue.isNull() ? currencyRegistrationFee : AmountFromValueNoErr(registrationFeeValue);
|
|
|
|
registrationFeeValue = find_value(obj, "pbaassystemregistrationfee");
|
|
pbaasSystemLaunchFee = registrationFeeValue.isNull() ? pbaasSystemLaunchFee : AmountFromValueNoErr(registrationFeeValue);
|
|
|
|
registrationFeeValue = find_value(obj, "currencyimportfee");
|
|
currencyImportFee = registrationFeeValue.isNull() ? currencyImportFee : AmountFromValueNoErr(registrationFeeValue);
|
|
|
|
registrationFeeValue = find_value(obj, "transactionimportfee");
|
|
transactionImportFee = registrationFeeValue.isNull() ? transactionImportFee : AmountFromValueNoErr(registrationFeeValue);
|
|
|
|
registrationFeeValue = find_value(obj, "transactionexportfee");
|
|
transactionExportFee = registrationFeeValue.isNull() ? transactionExportFee : AmountFromValueNoErr(registrationFeeValue);
|
|
|
|
if (!gatewayID.IsNull())
|
|
{
|
|
gatewayConverterIssuance = AmountFromValueNoErr(find_value(obj, "gatewayconverterissuance"));
|
|
}
|
|
|
|
auto vEras = uni_getValues(find_value(obj, "eras"));
|
|
if (vEras.size() > ASSETCHAINS_MAX_ERAS)
|
|
{
|
|
vEras.resize(ASSETCHAINS_MAX_ERAS);
|
|
}
|
|
|
|
if (vEras.size())
|
|
{
|
|
try
|
|
{
|
|
uint32_t newInitialBits = UintToArith256(uint256S(uni_get_str(find_value(obj, "initialtarget")))).GetCompact();
|
|
if (newInitialBits)
|
|
{
|
|
initialBits = newInitialBits;
|
|
}
|
|
}
|
|
catch(const std::exception& e)
|
|
{
|
|
LogPrintf("%s: Invalid initial target, must be 256 bit hex target\n", __func__);
|
|
throw e;
|
|
}
|
|
|
|
for (auto era : vEras)
|
|
{
|
|
rewards.push_back(uni_get_int64(find_value(era, "reward")));
|
|
rewardsDecay.push_back(uni_get_int64(find_value(era, "decay")));
|
|
halving.push_back(uni_get_int64(find_value(era, "halving")));
|
|
eraEnd.push_back(uni_get_int64(find_value(era, "eraend")));
|
|
}
|
|
|
|
if (!rewards.size())
|
|
{
|
|
LogPrintf("%s: PBaaS chain does not have valid rewards eras");
|
|
nVersion = PBAAS_VERSION_INVALID;
|
|
}
|
|
}
|
|
}
|
|
catch (exception e)
|
|
{
|
|
LogPrintf("%s: exception reading currency definition JSON\n", __func__, e.what());
|
|
nVersion = PBAAS_VERSION_INVALID;
|
|
}
|
|
}
|
|
|
|
CCurrencyDefinition::CCurrencyDefinition(const std::string ¤cyName, bool testMode) :
|
|
nVersion(VERSION_CURRENT),
|
|
preLaunchDiscount(0),
|
|
initialFractionalSupply(0),
|
|
gatewayConverterIssuance(0),
|
|
minNotariesConfirm(0),
|
|
idRegistrationFees(IDENTITY_REGISTRATION_FEE),
|
|
idReferralLevels(DEFAULT_ID_REFERRAL_LEVELS),
|
|
idImportFees(IDENTITY_IMPORT_FEE),
|
|
currencyRegistrationFee(CURRENCY_REGISTRATION_FEE),
|
|
pbaasSystemLaunchFee(PBAAS_SYSTEM_LAUNCH_FEE),
|
|
currencyImportFee(CURRENCY_IMPORT_FEE),
|
|
transactionImportFee(TRANSACTION_CROSSCHAIN_FEE >> 1),
|
|
transactionExportFee(TRANSACTION_CROSSCHAIN_FEE >> 1),
|
|
initialBits(DEFAULT_START_TARGET)
|
|
{
|
|
name = boost::to_upper_copy(CleanName(currencyName, parent));
|
|
if (parent.IsNull())
|
|
{
|
|
UniValue uniCurrency(UniValue::VOBJ);
|
|
uint160 thisCurrencyID = GetID();
|
|
|
|
uniCurrency.pushKV("options", CCurrencyDefinition::OPTION_PBAAS + CCurrencyDefinition::OPTION_ID_REFERRALS);
|
|
uniCurrency.pushKV("name", name);
|
|
uniCurrency.pushKV("systemid", EncodeDestination(CIdentityID(thisCurrencyID)));
|
|
uniCurrency.pushKV("notarizationprotocol", (int32_t)NOTARIZATION_AUTO);
|
|
uniCurrency.pushKV("proofprotocol", (int32_t)PROOF_PBAASMMR);
|
|
|
|
if (name == "VRSC" && !testMode)
|
|
{
|
|
UniValue uniEras(UniValue::VARR);
|
|
UniValue uniEra1(UniValue::VARR);
|
|
uniEra1.pushKV("reward", 0);
|
|
uniEra1.pushKV("decay", 100000000);
|
|
uniEra1.pushKV("halving", 1);
|
|
uniEra1.pushKV("eraend", 10080);
|
|
uniEras.push_back(uniEra1);
|
|
|
|
UniValue uniEra2(UniValue::VARR);
|
|
uniEra2.pushKV("reward", (int64_t)38400000000);
|
|
uniEra2.pushKV("decay", 0);
|
|
uniEra2.pushKV("halving", 43200);
|
|
uniEra2.pushKV("eraend", 226080);
|
|
uniEras.push_back(uniEra2);
|
|
|
|
UniValue uniEra3(UniValue::VARR);
|
|
uniEra2.pushKV("reward", (int64_t)2400000000);
|
|
uniEra2.pushKV("decay", 0);
|
|
uniEra2.pushKV("halving", 1051920);
|
|
uniEra2.pushKV("eraend", 0);
|
|
uniEras.push_back(uniEra2);
|
|
|
|
uniCurrency.pushKV("eras", uniEras);
|
|
|
|
*this = CCurrencyDefinition(uniCurrency);
|
|
}
|
|
else if (name == "VRSCTEST" || (testMode && name == "VRSC"))
|
|
{
|
|
name = "VRSCTEST";
|
|
|
|
UniValue preAllocUni(UniValue::VOBJ);
|
|
preAllocUni.pushKV(EncodeDestination(CIdentityID()), (int64_t)5000000000000000);
|
|
|
|
UniValue uniEras(UniValue::VARR);
|
|
UniValue uniEra1(UniValue::VARR);
|
|
uniEra1.pushKV("reward", 1200000000);
|
|
uniEra1.pushKV("decay", 0);
|
|
uniEra1.pushKV("halving", 1174000);
|
|
uniEra1.pushKV("eraend", 0);
|
|
uniEras.push_back(uniEra1);
|
|
|
|
uniCurrency.pushKV("eras", uniEras);
|
|
|
|
*this = CCurrencyDefinition(uniCurrency);
|
|
}
|
|
else
|
|
{
|
|
nVersion = VERSION_INVALID;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nVersion = VERSION_INVALID;
|
|
}
|
|
}
|
|
|
|
UniValue CCurrencyDefinition::ToUniValue() const
|
|
{
|
|
UniValue obj(UniValue::VOBJ);
|
|
|
|
obj.push_back(Pair("version", (int64_t)nVersion));
|
|
obj.push_back(Pair("options", (int64_t)options));
|
|
obj.push_back(Pair("name", name));
|
|
obj.push_back(Pair("currencyid", EncodeDestination(CIdentityID(GetID()))));
|
|
if (!parent.IsNull())
|
|
{
|
|
obj.push_back(Pair("parent", EncodeDestination(CIdentityID(parent))));
|
|
}
|
|
|
|
obj.push_back(Pair("systemid", EncodeDestination(CIdentityID(systemID))));
|
|
obj.push_back(Pair("notarizationprotocol", (int)notarizationProtocol));
|
|
obj.push_back(Pair("proofprotocol", (int)proofProtocol));
|
|
|
|
if (nativeCurrencyID.IsValid())
|
|
{
|
|
//obj.push_back(Pair("nativecurrencyid", nativeCurrencyID.ToUniValue()));
|
|
}
|
|
|
|
if (!launchSystemID.IsNull())
|
|
{
|
|
obj.push_back(Pair("launchsystemid", EncodeDestination(CIdentityID(launchSystemID))));
|
|
}
|
|
obj.push_back(Pair("startblock", (int64_t)startBlock));
|
|
obj.push_back(Pair("endblock", (int64_t)endBlock));
|
|
|
|
// currencies that can be converted for pre-launch or fractional usage
|
|
if (currencies.size())
|
|
{
|
|
UniValue currencyArr(UniValue::VARR);
|
|
for (auto ¤cy : currencies)
|
|
{
|
|
currencyArr.push_back(EncodeDestination(CIdentityID(currency)));
|
|
}
|
|
obj.push_back(Pair("currencies", currencyArr));
|
|
}
|
|
|
|
if (weights.size())
|
|
{
|
|
UniValue weightArr(UniValue::VARR);
|
|
for (auto &weight : weights)
|
|
{
|
|
weightArr.push_back(ValueFromAmount(weight));
|
|
}
|
|
obj.push_back(Pair("weights", weightArr));
|
|
}
|
|
|
|
if (conversions.size())
|
|
{
|
|
UniValue conversionArr(UniValue::VARR);
|
|
for (auto &conversion : conversions)
|
|
{
|
|
conversionArr.push_back(ValueFromAmount(conversion));
|
|
}
|
|
obj.push_back(Pair("conversions", conversionArr));
|
|
}
|
|
|
|
if (minPreconvert.size())
|
|
{
|
|
UniValue minPreconvertArr(UniValue::VARR);
|
|
for (auto &oneMin : minPreconvert)
|
|
{
|
|
minPreconvertArr.push_back(ValueFromAmount(oneMin));
|
|
}
|
|
obj.push_back(Pair("minpreconversion", minPreconvertArr));
|
|
}
|
|
|
|
if (maxPreconvert.size())
|
|
{
|
|
UniValue maxPreconvertArr(UniValue::VARR);
|
|
for (auto &oneMax : maxPreconvert)
|
|
{
|
|
maxPreconvertArr.push_back(ValueFromAmount(oneMax));
|
|
}
|
|
obj.push_back(Pair("maxpreconversion", maxPreconvertArr));
|
|
}
|
|
|
|
if (preLaunchDiscount)
|
|
{
|
|
obj.push_back(Pair("prelaunchdiscount", ValueFromAmount(preLaunchDiscount)));
|
|
}
|
|
|
|
if (IsFractional())
|
|
{
|
|
obj.push_back(Pair("initialsupply", ValueFromAmount(initialFractionalSupply)));
|
|
obj.push_back(Pair("prelaunchcarveout", ValueFromAmount(preLaunchCarveOut)));
|
|
}
|
|
|
|
if (preAllocation.size())
|
|
{
|
|
UniValue preAllocationArr(UniValue::VARR);
|
|
for (auto &onePreAllocation : preAllocation)
|
|
{
|
|
UniValue onePreAlloc(UniValue::VOBJ);
|
|
onePreAlloc.push_back(Pair(onePreAllocation.first.IsNull() ? "blockoneminer" : EncodeDestination(CIdentityID(onePreAllocation.first)),
|
|
ValueFromAmount(onePreAllocation.second)));
|
|
preAllocationArr.push_back(onePreAlloc);
|
|
}
|
|
obj.push_back(Pair("preallocations", preAllocationArr));
|
|
}
|
|
|
|
if (!gatewayID.IsNull())
|
|
{
|
|
obj.push_back(Pair("gateway", EncodeDestination(CIdentityID(gatewayID))));
|
|
}
|
|
|
|
if (contributions.size())
|
|
{
|
|
UniValue initialContributionArr(UniValue::VARR);
|
|
for (auto &oneCurContributions : contributions)
|
|
{
|
|
initialContributionArr.push_back(ValueFromAmount(oneCurContributions));
|
|
}
|
|
obj.push_back(Pair("initialcontributions", initialContributionArr));
|
|
}
|
|
|
|
if (IsGateway() || IsGatewayConverter() || IsPBaaSChain())
|
|
{
|
|
obj.push_back(Pair("gatewayconverterissuance", ValueFromAmount(gatewayConverterIssuance)));
|
|
}
|
|
|
|
obj.push_back(Pair("idregistrationfees", ValueFromAmount(idRegistrationFees)));
|
|
obj.push_back(Pair("idreferrallevels", idReferralLevels));
|
|
obj.push_back(Pair("idimportfees", ValueFromAmount(idImportFees)));
|
|
|
|
if (IsGateway() || IsPBaaSChain())
|
|
{
|
|
// notaries are identities that perform specific functions for the currency's operation
|
|
// related to notarizing an external currency source, as well as proving imports
|
|
if (notaries.size())
|
|
{
|
|
UniValue notaryArr(UniValue::VARR);
|
|
for (auto ¬ary : notaries)
|
|
{
|
|
notaryArr.push_back(EncodeDestination(CIdentityID(notary)));
|
|
}
|
|
obj.push_back(Pair("notaries", notaryArr));
|
|
}
|
|
obj.push_back(Pair("minnotariesconfirm", minNotariesConfirm));
|
|
|
|
obj.push_back(Pair("currencyregistrationfee", ValueFromAmount(currencyRegistrationFee)));
|
|
obj.push_back(Pair("pbaassystemregistrationfee", ValueFromAmount(pbaasSystemLaunchFee)));
|
|
obj.push_back(Pair("currencyimportfee", ValueFromAmount(currencyImportFee)));
|
|
obj.push_back(Pair("transactionimportfee", ValueFromAmount(transactionImportFee)));
|
|
obj.push_back(Pair("transactionexportfee", ValueFromAmount(transactionExportFee)));
|
|
|
|
if (!gatewayConverterName.empty())
|
|
{
|
|
obj.push_back(Pair("gatewayconverterid", EncodeDestination(CIdentityID(GatewayConverterID()))));
|
|
obj.push_back(Pair("gatewayconvertername", gatewayConverterName));
|
|
}
|
|
|
|
if (IsPBaaSChain())
|
|
{
|
|
arith_uint256 target;
|
|
target.SetCompact(initialBits);
|
|
obj.push_back(Pair("initialtarget", ArithToUint256(target).GetHex()));
|
|
UniValue eraArr(UniValue::VARR);
|
|
for (int i = 0; i < rewards.size(); i++)
|
|
{
|
|
UniValue era(UniValue::VOBJ);
|
|
era.push_back(Pair("reward", rewards.size() > i ? rewards[i] : (int64_t)0));
|
|
era.push_back(Pair("decay", rewardsDecay.size() > i ? rewardsDecay[i] : (int64_t)0));
|
|
era.push_back(Pair("halving", halving.size() > i ? (int32_t)halving[i] : (int32_t)0));
|
|
era.push_back(Pair("eraend", eraEnd.size() > i ? (int32_t)eraEnd[i] : (int32_t)0));
|
|
eraArr.push_back(era);
|
|
}
|
|
obj.push_back(Pair("eras", eraArr));
|
|
}
|
|
}
|
|
|
|
return obj;
|
|
}
|
|
|
|
CTransferDestination CTransferDestination::GetAuxDest(int destNum) const
|
|
{
|
|
CTransferDestination retVal;
|
|
if (auxDests.size() < destNum)
|
|
{
|
|
::FromVector(auxDests[destNum], retVal);
|
|
if (retVal.type & FLAG_DEST_AUX || retVal.auxDests.size())
|
|
{
|
|
retVal.type = DEST_INVALID;
|
|
}
|
|
// no gateways or flags, only simple destinations work
|
|
switch (retVal.type)
|
|
{
|
|
case DEST_ID:
|
|
case DEST_PK:
|
|
case DEST_PKH:
|
|
case DEST_ETH:
|
|
case DEST_SH:
|
|
break;
|
|
default:
|
|
retVal.type = DEST_INVALID;
|
|
}
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
int64_t CCurrencyDefinition::GetTotalPreallocation() const
|
|
{
|
|
CAmount totalPreallocatedNative = 0;
|
|
for (auto &onePreallocation : preAllocation)
|
|
{
|
|
totalPreallocatedNative += onePreallocation.second;
|
|
}
|
|
return totalPreallocatedNative;
|
|
}
|
|
|
|
bool uni_get_bool(UniValue uv, bool def)
|
|
{
|
|
try
|
|
{
|
|
if (uv.isStr())
|
|
{
|
|
std::string boolStr;
|
|
if ((boolStr = uni_get_str(uv, def ? "true" : "false")) == "true" || boolStr == "1")
|
|
{
|
|
return true;
|
|
}
|
|
else if (boolStr == "false" || boolStr == "0")
|
|
{
|
|
return false;
|
|
}
|
|
return def;
|
|
}
|
|
else if (uv.isNum())
|
|
{
|
|
return uv.get_int() != 0;
|
|
}
|
|
else
|
|
{
|
|
return uv.get_bool();
|
|
}
|
|
return false;
|
|
}
|
|
catch(const std::exception& e)
|
|
{
|
|
return def;
|
|
}
|
|
}
|
|
|
|
int32_t uni_get_int(UniValue uv, int32_t def)
|
|
{
|
|
try
|
|
{
|
|
if (uv.isStr())
|
|
{
|
|
return atoi(uv.get_str());
|
|
}
|
|
return uv.get_int();
|
|
}
|
|
catch(const std::exception& e)
|
|
{
|
|
return def;
|
|
}
|
|
}
|
|
|
|
int64_t uni_get_int64(UniValue uv, int64_t def)
|
|
{
|
|
try
|
|
{
|
|
if (uv.isStr())
|
|
{
|
|
return atoi64(uv.get_str());
|
|
}
|
|
return uv.get_int64();
|
|
}
|
|
catch(const std::exception& e)
|
|
{
|
|
return def;
|
|
}
|
|
}
|
|
|
|
std::string uni_get_str(UniValue uv, std::string def)
|
|
{
|
|
try
|
|
{
|
|
return uv.get_str();
|
|
}
|
|
catch(const std::exception& e)
|
|
{
|
|
return def;
|
|
}
|
|
}
|
|
|
|
std::vector<UniValue> uni_getValues(UniValue uv, std::vector<UniValue> def)
|
|
{
|
|
try
|
|
{
|
|
return uv.getValues();
|
|
}
|
|
catch(const std::exception& e)
|
|
{
|
|
return def;
|
|
}
|
|
}
|
|
|
|
uint160 CCrossChainRPCData::GetConditionID(const uint160 &cid, uint32_t condition)
|
|
{
|
|
CHashWriter hw(SER_GETHASH, PROTOCOL_VERSION);
|
|
hw << condition;
|
|
hw << cid;
|
|
uint256 chainHash = hw.GetHash();
|
|
return Hash160(chainHash.begin(), chainHash.end());
|
|
}
|
|
|
|
uint160 GetConditionID(const uint160 &cid, const uint160 &condition)
|
|
{
|
|
CHashWriter hw(SER_GETHASH, PROTOCOL_VERSION);
|
|
hw << condition;
|
|
hw << cid;
|
|
uint256 chainHash = hw.GetHash();
|
|
return Hash160(chainHash.begin(), chainHash.end());
|
|
}
|
|
|
|
uint160 GetConditionID(const uint160 &cid, const uint160 &condition, const uint256 &txid, int32_t voutNum)
|
|
{
|
|
CHashWriter hw(SER_GETHASH, PROTOCOL_VERSION);
|
|
hw << condition;
|
|
hw << cid;
|
|
hw << txid;
|
|
hw << voutNum;
|
|
uint256 chainHash = hw.GetHash();
|
|
return Hash160(chainHash.begin(), chainHash.end());
|
|
}
|
|
|
|
uint160 CCrossChainRPCData::GetConditionID(std::string name, uint32_t condition)
|
|
{
|
|
uint160 parent;
|
|
uint160 cid = CIdentity::GetID(name, parent);
|
|
|
|
CHashWriter hw(SER_GETHASH, PROTOCOL_VERSION);
|
|
hw << condition;
|
|
hw << cid;
|
|
uint256 chainHash = hw.GetHash();
|
|
return Hash160(chainHash.begin(), chainHash.end());
|
|
}
|
|
|
|
std::string TrimLeading(const std::string &Name, unsigned char ch)
|
|
{
|
|
std::string nameCopy = Name;
|
|
int removeSpaces;
|
|
for (removeSpaces = 0; removeSpaces < nameCopy.size(); removeSpaces++)
|
|
{
|
|
if (nameCopy[removeSpaces] != ch)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (removeSpaces)
|
|
{
|
|
nameCopy.erase(nameCopy.begin(), nameCopy.begin() + removeSpaces);
|
|
}
|
|
return nameCopy;
|
|
}
|
|
|
|
std::string TrimTrailing(const std::string &Name, unsigned char ch)
|
|
{
|
|
std::string nameCopy = Name;
|
|
int removeSpaces;
|
|
for (removeSpaces = nameCopy.size() - 1; removeSpaces >= 0; removeSpaces--)
|
|
{
|
|
if (nameCopy[removeSpaces] != ch)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
nameCopy.resize(nameCopy.size() - ((nameCopy.size() - 1) - removeSpaces));
|
|
return nameCopy;
|
|
}
|
|
|
|
// this will add the current Verus chain name to subnames if it is not present
|
|
// on both id and chain names
|
|
std::vector<std::string> ParseSubNames(const std::string &Name, std::string &ChainOut, bool displayfilter, bool addVerus)
|
|
{
|
|
std::string nameCopy = Name;
|
|
std::string invalidChars = "\\/:*?\"<>|";
|
|
if (displayfilter)
|
|
{
|
|
invalidChars += "\n\t\r\b\t\v\f\x1B";
|
|
}
|
|
for (int i = 0; i < nameCopy.size(); i++)
|
|
{
|
|
if (invalidChars.find(nameCopy[i]) != std::string::npos)
|
|
{
|
|
return std::vector<std::string>();
|
|
}
|
|
}
|
|
|
|
std::vector<std::string> retNames;
|
|
boost::split(retNames, nameCopy, boost::is_any_of("@"));
|
|
if (!retNames.size() || retNames.size() > 2)
|
|
{
|
|
return std::vector<std::string>();
|
|
}
|
|
|
|
bool explicitChain = false;
|
|
if (retNames.size() == 2)
|
|
{
|
|
ChainOut = retNames[1];
|
|
explicitChain = true;
|
|
}
|
|
|
|
nameCopy = retNames[0];
|
|
boost::split(retNames, nameCopy, boost::is_any_of("."));
|
|
|
|
int numRetNames = retNames.size();
|
|
|
|
std::string verusChainName = boost::to_lower_copy(VERUS_CHAINNAME);
|
|
|
|
if (addVerus)
|
|
{
|
|
if (explicitChain)
|
|
{
|
|
std::vector<std::string> chainOutNames;
|
|
boost::split(chainOutNames, ChainOut, boost::is_any_of("."));
|
|
std::string lastChainOut = boost::to_lower_copy(chainOutNames.back());
|
|
|
|
if (lastChainOut != "" && lastChainOut != verusChainName)
|
|
{
|
|
chainOutNames.push_back(verusChainName);
|
|
}
|
|
else if (lastChainOut == "")
|
|
{
|
|
chainOutNames.pop_back();
|
|
}
|
|
}
|
|
|
|
std::string lastRetName = boost::to_lower_copy(retNames.back());
|
|
if (lastRetName != "" && lastRetName != verusChainName)
|
|
{
|
|
retNames.push_back(verusChainName);
|
|
}
|
|
else if (lastRetName == "")
|
|
{
|
|
retNames.pop_back();
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < retNames.size(); i++)
|
|
{
|
|
if (retNames[i].size() > KOMODO_ASSETCHAIN_MAXLEN - 1)
|
|
{
|
|
retNames[i] = std::string(retNames[i], 0, (KOMODO_ASSETCHAIN_MAXLEN - 1));
|
|
}
|
|
// spaces are allowed, but no sub-name can have leading or trailing spaces
|
|
if (!retNames[i].size() || retNames[i] != TrimTrailing(TrimLeading(retNames[i], ' '), ' '))
|
|
{
|
|
return std::vector<std::string>();
|
|
}
|
|
}
|
|
|
|
return retNames;
|
|
}
|
|
|
|
// takes a multipart name, either complete or partially processed with a Parent hash,
|
|
// hash its parent names into a parent ID and return the parent hash and cleaned, single name
|
|
// takes a multipart name, either complete or partially processed with a Parent hash,
|
|
// hash its parent names into a parent ID and return the parent hash and cleaned, single name
|
|
std::string CleanName(const std::string &Name, uint160 &Parent, bool displayfilter, bool addVerus)
|
|
{
|
|
std::string chainName;
|
|
std::vector<std::string> subNames = ParseSubNames(Name, chainName, displayfilter, addVerus);
|
|
|
|
if (!subNames.size())
|
|
{
|
|
return "";
|
|
}
|
|
|
|
if (!Parent.IsNull() &&
|
|
boost::to_lower_copy(subNames.back()) == boost::to_lower_copy(VERUS_CHAINNAME))
|
|
{
|
|
subNames.pop_back();
|
|
}
|
|
|
|
for (int i = subNames.size() - 1; i > 0; i--)
|
|
{
|
|
std::string parentNameStr = boost::algorithm::to_lower_copy(subNames[i]);
|
|
const char *parentName = parentNameStr.c_str();
|
|
uint256 idHash;
|
|
|
|
if (Parent.IsNull())
|
|
{
|
|
idHash = Hash(parentName, parentName + parentNameStr.size());
|
|
}
|
|
else
|
|
{
|
|
idHash = Hash(parentName, parentName + strlen(parentName));
|
|
idHash = Hash(Parent.begin(), Parent.end(), idHash.begin(), idHash.end());
|
|
}
|
|
Parent = Hash160(idHash.begin(), idHash.end());
|
|
//printf("uint160 for parent %s: %s\n", parentName, Parent.GetHex().c_str());
|
|
}
|
|
return subNames[0];
|
|
}
|
|
|
|
UniValue CNodeData::ToUniValue() const
|
|
{
|
|
UniValue obj(UniValue::VOBJ);
|
|
obj.push_back(Pair("networkaddress", networkAddress));
|
|
obj.push_back(Pair("nodeidentity", ""));
|
|
return obj;
|
|
}
|
|
|
|
CNodeData::CNodeData(std::string netAddr, std::string paymentAddr) :
|
|
networkAddress(netAddr)
|
|
{
|
|
}
|
|
|
|
CIdentityID CIdentity::GetID(const std::string &Name, uint160 &parent)
|
|
{
|
|
std::string cleanName = CleanName(Name, parent);
|
|
if (cleanName.empty())
|
|
{
|
|
return uint160();
|
|
}
|
|
|
|
std::string subName = boost::algorithm::to_lower_copy(cleanName);
|
|
const char *idName = subName.c_str();
|
|
//printf("hashing: %s, %s\n", idName, parent.GetHex().c_str());
|
|
|
|
uint256 idHash;
|
|
if (parent.IsNull())
|
|
{
|
|
idHash = Hash(idName, idName + strlen(idName));
|
|
}
|
|
else
|
|
{
|
|
idHash = Hash(idName, idName + strlen(idName));
|
|
idHash = Hash(parent.begin(), parent.end(), idHash.begin(), idHash.end());
|
|
|
|
}
|
|
return Hash160(idHash.begin(), idHash.end());
|
|
}
|
|
|
|
CIdentityID CIdentity::GetID(const std::string &Name) const
|
|
{
|
|
uint160 parent;
|
|
std::string cleanName = CleanName(Name, parent);
|
|
|
|
std::string subName = boost::algorithm::to_lower_copy(cleanName);
|
|
const char *idName = subName.c_str();
|
|
//printf("hashing: %s, %s\n", idName, parent.GetHex().c_str());
|
|
|
|
uint256 idHash;
|
|
if (parent.IsNull())
|
|
{
|
|
idHash = Hash(idName, idName + strlen(idName));
|
|
}
|
|
else
|
|
{
|
|
idHash = Hash(idName, idName + strlen(idName));
|
|
idHash = Hash(parent.begin(), parent.end(), idHash.begin(), idHash.end());
|
|
|
|
}
|
|
return Hash160(idHash.begin(), idHash.end());
|
|
}
|
|
|
|
CIdentityID CIdentity::GetID() const
|
|
{
|
|
return GetID(name);
|
|
}
|
|
|
|
uint160 CCrossChainRPCData::GetID(std::string name)
|
|
{
|
|
uint160 parent;
|
|
return CIdentity::GetID(name,parent);
|
|
}
|
|
|
|
UniValue ValueFromAmount(const CAmount& amount)
|
|
{
|
|
bool sign = amount < 0;
|
|
int64_t n_abs = (sign ? -amount : amount);
|
|
int64_t quotient = n_abs / COIN;
|
|
int64_t remainder = n_abs % COIN;
|
|
return UniValue(UniValue::VNUM,
|
|
strprintf("%s%d.%08d", sign ? "-" : "", quotient, remainder));
|
|
}
|
|
|
|
static const CRPCConvertParam vRPCConvertParams[] =
|
|
{
|
|
{ "stop", 0 },
|
|
{ "setmocktime", 0 },
|
|
{ "getaddednodeinfo", 0 },
|
|
{ "setgenerate", 0 },
|
|
{ "setgenerate", 1 },
|
|
{ "generate", 0 },
|
|
{ "getnetworkhashps", 0 },
|
|
{ "getnetworkhashps", 1 },
|
|
{ "getnetworksolps", 0 },
|
|
{ "getnetworksolps", 1 },
|
|
{ "sendtoaddress", 1 },
|
|
{ "sendtoaddress", 4 },
|
|
{ "settxfee", 0 },
|
|
{ "getreceivedbyaddress", 1 },
|
|
{ "getreceivedbyaccount", 1 },
|
|
{ "listreceivedbyaddress", 0 },
|
|
{ "listreceivedbyaddress", 1 },
|
|
{ "listreceivedbyaddress", 2 },
|
|
{ "listreceivedbyaccount", 0 },
|
|
{ "listreceivedbyaccount", 1 },
|
|
{ "listreceivedbyaccount", 2 },
|
|
{ "getbalance", 1 },
|
|
{ "getbalance", 2 },
|
|
{ "getcurrencybalance", 1},
|
|
{ "getcurrencybalance", 2},
|
|
{ "getblockhash", 0 },
|
|
{ "move", 2 },
|
|
{ "move", 3 },
|
|
{ "sendfrom", 2 },
|
|
{ "sendfrom", 3 },
|
|
{ "listtransactions", 1 },
|
|
{ "listtransactions", 2 },
|
|
{ "listtransactions", 3 },
|
|
{ "listaccounts", 0 },
|
|
{ "listaccounts", 1 },
|
|
{ "walletpassphrase", 1 },
|
|
{ "setminingdistribution", 0 },
|
|
{ "getblocktemplate", 0 },
|
|
{ "listsinceblock", 1 },
|
|
{ "listsinceblock", 2 },
|
|
{ "sendmany", 1 },
|
|
{ "sendmany", 2 },
|
|
{ "sendmany", 4 },
|
|
{ "addmultisigaddress", 0 },
|
|
{ "addmultisigaddress", 1 },
|
|
{ "createmultisig", 0 },
|
|
{ "createmultisig", 1 },
|
|
{ "listunspent", 0 },
|
|
{ "listunspent", 1 },
|
|
{ "listunspent", 2 },
|
|
{ "getblock", 1 },
|
|
{ "getblockheader", 1 },
|
|
{ "gettransaction", 1 },
|
|
{ "getrawtransaction", 1 },
|
|
{ "createrawtransaction", 0 },
|
|
{ "createrawtransaction", 1 },
|
|
{ "createrawtransaction", 2 },
|
|
{ "createrawtransaction", 3 },
|
|
{ "signrawtransaction", 1 },
|
|
{ "signrawtransaction", 2 },
|
|
{ "sendrawtransaction", 1 },
|
|
{ "fundrawtransaction", 1 },
|
|
{ "gettxout", 1 },
|
|
{ "gettxout", 2 },
|
|
{ "gettxoutproof", 0 },
|
|
{ "lockunspent", 0 },
|
|
{ "lockunspent", 1 },
|
|
{ "importprivkey", 2 },
|
|
{ "importaddress", 2 },
|
|
{ "verifychain", 0 },
|
|
{ "verifychain", 1 },
|
|
{ "keypoolrefill", 0 },
|
|
{ "getrawmempool", 0 },
|
|
{ "estimatefee", 0 },
|
|
{ "estimatepriority", 0 },
|
|
{ "prioritisetransaction", 1 },
|
|
{ "prioritisetransaction", 2 },
|
|
{ "setban", 2 },
|
|
{ "setban", 3 },
|
|
{ "getspentinfo", 0},
|
|
{ "getaddresstxids", 0},
|
|
{ "getaddressbalance", 0},
|
|
{ "getaddressdeltas", 0},
|
|
{ "getaddressutxos", 0},
|
|
{ "getaddressmempool", 0},
|
|
{ "getblockhashes", 0},
|
|
{ "getblockhashes", 1},
|
|
{ "getblockhashes", 2},
|
|
{ "getblockdeltas", 0},
|
|
{ "zcrawjoinsplit", 1 },
|
|
{ "zcrawjoinsplit", 2 },
|
|
{ "zcrawjoinsplit", 3 },
|
|
{ "zcrawjoinsplit", 4 },
|
|
{ "zcbenchmark", 1 },
|
|
{ "zcbenchmark", 2 },
|
|
{ "getblocksubsidy", 0},
|
|
{ "z_listaddresses", 0},
|
|
{ "z_listreceivedbyaddress", 1},
|
|
{ "z_listunspent", 0 },
|
|
{ "z_listunspent", 1 },
|
|
{ "z_listunspent", 2 },
|
|
{ "z_listunspent", 3 },
|
|
{ "z_getbalance", 1},
|
|
{ "z_gettotalbalance", 0},
|
|
{ "z_gettotalbalance", 1},
|
|
{ "z_gettotalbalance", 2},
|
|
{ "z_mergetoaddress", 0},
|
|
{ "z_mergetoaddress", 2},
|
|
{ "z_mergetoaddress", 3},
|
|
{ "z_mergetoaddress", 4},
|
|
{ "z_sendmany", 1},
|
|
{ "z_sendmany", 2},
|
|
{ "z_sendmany", 3},
|
|
{ "z_shieldcoinbase", 2},
|
|
{ "z_shieldcoinbase", 3},
|
|
{ "z_getoperationstatus", 0},
|
|
{ "z_getoperationresult", 0},
|
|
//{ "z_importkey", 1 },
|
|
{ "paxprice", 4 },
|
|
{ "paxprices", 3 },
|
|
{ "paxpending", 0 },
|
|
{ "notaries", 2 },
|
|
{ "minerids", 1 },
|
|
{ "kvsearch", 1 },
|
|
{ "kvupdate", 4 },
|
|
{ "z_importkey", 2 },
|
|
{ "z_importviewingkey", 2 },
|
|
{ "z_getpaymentdisclosure", 1},
|
|
{ "z_getpaymentdisclosure", 2},
|
|
// crosschain
|
|
{ "assetchainproof", 1},
|
|
{ "crosschainproof", 1},
|
|
{ "getbestproofroot", 0},
|
|
{ "submitacceptednotarization", 0},
|
|
{ "submitimports", 0},
|
|
{ "height_MoM", 1},
|
|
{ "calc_MoM", 2},
|
|
// pbaas
|
|
{ "definecurrency", 0},
|
|
{ "definecurrency", 1},
|
|
{ "definecurrency", 2},
|
|
{ "definecurrency", 3},
|
|
{ "definecurrency", 4},
|
|
{ "definecurrency", 5},
|
|
{ "definecurrency", 6},
|
|
{ "definecurrency", 7},
|
|
{ "definecurrency", 8},
|
|
{ "definecurrency", 9},
|
|
{ "definecurrency", 10},
|
|
{ "definecurrency", 11},
|
|
{ "definecurrency", 12},
|
|
{ "definecurrency", 13},
|
|
{ "listcurrencies", 0},
|
|
{ "listcurrencies", 1},
|
|
{ "sendcurrency", 1},
|
|
{ "registeridentity", 0},
|
|
{ "updateidentity", 0},
|
|
{ "setidentitytimelock", 1},
|
|
{ "recoveridentity", 0},
|
|
{ "getidentitieswithaddress", 0},
|
|
{ "getidentitieswithrevocation", 0},
|
|
{ "getidentitieswithrecovery", 0},
|
|
{ "makeoffer", 1},
|
|
{ "takeoffer", 1},
|
|
{ "closeoffers", 0},
|
|
{ "getvdxfid", 1},
|
|
// Zcash addition
|
|
{ "z_setmigration", 0},
|
|
};
|
|
|
|
class CRPCConvertTable
|
|
{
|
|
private:
|
|
std::set<std::pair<std::string, int> > members;
|
|
|
|
public:
|
|
CRPCConvertTable();
|
|
|
|
bool convert(const std::string& method, int idx) {
|
|
return (members.count(std::make_pair(method, idx)) > 0);
|
|
}
|
|
};
|
|
|
|
CRPCConvertTable::CRPCConvertTable()
|
|
{
|
|
const unsigned int n_elem =
|
|
(sizeof(vRPCConvertParams) / sizeof(vRPCConvertParams[0]));
|
|
|
|
for (unsigned int i = 0; i < n_elem; i++) {
|
|
members.insert(std::make_pair(vRPCConvertParams[i].methodName,
|
|
vRPCConvertParams[i].paramIdx));
|
|
}
|
|
}
|
|
|
|
static CRPCConvertTable rpcCvtTable;
|
|
|
|
/** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null)
|
|
* as well as objects and arrays.
|
|
*/
|
|
UniValue ParseNonRFCJSONValue(const std::string& strVal)
|
|
{
|
|
UniValue jVal;
|
|
if (!jVal.read(std::string("[")+strVal+std::string("]")) ||
|
|
!jVal.isArray() || jVal.size()!=1)
|
|
throw runtime_error(string("Error JSON:")+strVal);
|
|
return jVal[0];
|
|
}
|
|
|
|
/** Convert strings to command-specific RPC representation */
|
|
UniValue RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams)
|
|
{
|
|
UniValue params(UniValue::VARR);
|
|
|
|
for (unsigned int idx = 0; idx < strParams.size(); idx++) {
|
|
const std::string& strVal = strParams[idx];
|
|
if (!rpcCvtTable.convert(strMethod, idx)) {
|
|
// insert string value directly
|
|
params.push_back(strVal);
|
|
} else {
|
|
// parse string as JSON, insert bool/number/object/etc. value
|
|
params.push_back(ParseNonRFCJSONValue(strVal));
|
|
}
|
|
}
|
|
|
|
return params;
|
|
}
|
|
|