1 /********************************************************************
2 * (C) 2019 Michael Toutonghi
4 * Distributed under the MIT software license, see the accompanying
5 * file COPYING or http://www.opensource.org/licenses/mit-license.php.
7 * This provides support for PBaaS cross chain communication.
9 * In merge mining and notarization, Verus acts as a hub that other PBaaS chains
10 * call via RPC in order to get information that allows earning and submitting
13 * All PBaaS chains communicate with their primary reserve chain, which is either Verus
14 * or the chain that is their reserve coin. The child PBaaS chain initiates all of
15 * the communication with the parent / reserve daemon.
17 * Generally, the PBaaS chain will call the Verus chain to either get information needed
18 * to create an earned or accepted notarization. If there is no Verus daemon available
19 * staking and mining of a PBaaS chain proceeds as usual, but without notarization
20 * reward opportunities.
24 #include "chainparamsbase.h"
25 #include "clientversion.h"
26 #include "rpc/client.h"
27 #include "rpc/protocol.h"
29 #include "utilstrencodings.h"
31 #include <boost/filesystem/operations.hpp>
32 #include <boost/format.hpp>
35 #include <event2/buffer.h>
36 #include <event2/keyvalq_struct.h>
37 #include "support/events.h"
43 #include "pbaas/crosschainrpc.h"
44 #include "pbaas/identity.h"
48 extern string PBAAS_HOST;
49 extern string PBAAS_USERPASS;
50 extern int32_t PBAAS_PORT;
51 extern std::string VERUS_CHAINNAME;
54 // Exception thrown on connection error. This error is used to determine
55 // when to wait if -rpcwait is given.
57 class CConnectionFailed : public std::runtime_error
61 explicit inline CConnectionFailed(const std::string& msg) :
62 std::runtime_error(msg)
67 /** Reply structure for request_done to fill in */
70 HTTPReply(): status(0), error(-1) {}
77 const char *http_errorstring(int code)
80 #if LIBEVENT_VERSION_NUMBER >= 0x02010300
81 case EVREQ_HTTP_TIMEOUT:
82 return "timeout reached";
85 case EVREQ_HTTP_INVALID_HEADER:
86 return "error while reading header, or invalid header";
87 case EVREQ_HTTP_BUFFER_ERROR:
88 return "error encountered while reading or writing";
89 case EVREQ_HTTP_REQUEST_CANCEL:
90 return "request was canceled";
91 case EVREQ_HTTP_DATA_TOO_LONG:
92 return "response body is larger than allowed";
99 static void http_request_done(struct evhttp_request *req, void *ctx)
101 HTTPReply *reply = static_cast<HTTPReply*>(ctx);
104 /* If req is NULL, it means an error occurred while connecting: the
105 * error code will have been passed to http_error_cb.
111 reply->status = evhttp_request_get_response_code(req);
113 struct evbuffer *buf = evhttp_request_get_input_buffer(req);
116 size_t size = evbuffer_get_length(buf);
117 const char *data = (const char*)evbuffer_pullup(buf, size);
119 reply->body = std::string(data, size);
120 evbuffer_drain(buf, size);
124 #if LIBEVENT_VERSION_NUMBER >= 0x02010300
125 static void http_error_cb(enum evhttp_request_error err, void *ctx)
127 HTTPReply *reply = static_cast<HTTPReply*>(ctx);
132 static CCrossChainRPCData LoadFromConfig(std::string name)
134 map<string, string> settings;
135 map<string, vector<string>> settingsmulti;
136 CCrossChainRPCData ret;
138 // if we are requested to automatically load the information from the Verus chain, do it if we can find the daemon
139 if (ReadConfigFile(name, settings, settingsmulti))
141 auto rpcuser = settings.find("-rpcuser");
142 auto rpcpwd = settings.find("-rpcpassword");
143 auto rpcport = settings.find("-rpcport");
144 auto rpchost = settings.find("-rpchost");
145 ret.credentials = rpcuser != settings.end() ? rpcuser->second + ":" : "";
146 ret.credentials += rpcpwd != settings.end() ? rpcpwd->second : "";
147 ret.port = rpcport != settings.end() ? atoi(rpcport->second) : (name == "VRSC" ? 27486 : 0);
148 ret.host = rpchost != settings.end() ? rpchost->second : "127.0.0.1";
153 // credentials for now are "user:password"
154 UniValue RPCCall(const string& strMethod, const UniValue& params, const string credentials, int port, const string host, int timeout)
156 // Used for inter-daemon communicatoin to enable merge mining and notarization without a client
160 raii_event_base base = obtain_event_base();
162 // Synchronously look up hostname
163 raii_evhttp_connection evcon = obtain_evhttp_connection_base(base.get(), host, port);
164 evhttp_connection_set_timeout(evcon.get(), timeout);
167 raii_evhttp_request req = obtain_evhttp_request(http_request_done, (void*)&response);
169 throw std::runtime_error("create http request failed");
170 #if LIBEVENT_VERSION_NUMBER >= 0x02010300
171 evhttp_request_set_error_cb(req.get(), http_error_cb);
174 struct evkeyvalq* output_headers = evhttp_request_get_output_headers(req.get());
175 assert(output_headers);
176 evhttp_add_header(output_headers, "Host", host.c_str());
177 evhttp_add_header(output_headers, "Connection", "close");
178 evhttp_add_header(output_headers, "Authorization", (std::string("Basic ") + EncodeBase64(credentials)).c_str());
180 // Attach request data
181 std::string strRequest = JSONRPCRequest(strMethod, params, 1);
182 struct evbuffer* output_buffer = evhttp_request_get_output_buffer(req.get());
183 assert(output_buffer);
184 evbuffer_add(output_buffer, strRequest.data(), strRequest.size());
186 int r = evhttp_make_request(evcon.get(), req.get(), EVHTTP_REQ_POST, "/");
187 req.release(); // ownership moved to evcon in above call
189 throw CConnectionFailed("send http request failed");
192 event_base_dispatch(base.get());
194 if (response.status == 0)
195 throw CConnectionFailed(strprintf("couldn't connect to server: %s (code %d)\n(make sure server is running and you are connecting to the correct RPC port)", http_errorstring(response.error), response.error));
196 else if (response.status == HTTP_UNAUTHORIZED)
197 throw std::runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
198 else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR)
199 throw std::runtime_error(strprintf("server returned HTTP error %d", response.status));
200 else if (response.body.empty())
201 throw std::runtime_error("no response from server");
204 UniValue valReply(UniValue::VSTR);
205 if (!valReply.read(response.body))
206 throw std::runtime_error("couldn't parse reply from server");
207 const UniValue& reply = valReply.get_obj();
209 throw std::runtime_error("expected reply to have result, error and id properties");
214 UniValue RPCCallRoot(const string& strMethod, const UniValue& params, int timeout)
216 string host, credentials;
218 map<string, string> settings;
219 map<string, vector<string>> settingsmulti;
221 if (PBAAS_HOST != "" && PBAAS_PORT != 0)
223 return RPCCall(strMethod, params, PBAAS_USERPASS, PBAAS_PORT, PBAAS_HOST);
225 else if (ReadConfigFile(PBAAS_TESTMODE ? "VRSCTEST" : "VRSC", settings, settingsmulti))
227 PBAAS_USERPASS = settingsmulti.find("-rpcuser")->second[0] + ":" + settingsmulti.find("-rpcpassword")->second[0];
228 PBAAS_PORT = atoi(settingsmulti.find("-rpcport")->second[0]);
229 PBAAS_HOST = settingsmulti.find("-rpchost")->second[0];
230 if (!PBAAS_HOST.size())
232 PBAAS_HOST = "127.0.0.1";
234 return RPCCall(strMethod, params, credentials, port, host, timeout);
236 return UniValue(UniValue::VNULL);
239 UniValue CCrossChainRPCData::ToUniValue() const
241 UniValue obj(UniValue::VOBJ);
242 obj.push_back(Pair("host", host));
243 obj.push_back(Pair("port", port));
244 obj.push_back(Pair("credentials", credentials));
248 CNodeData::CNodeData(const UniValue &obj)
250 networkAddress = uni_get_str(find_value(obj, "networkaddress"));
251 CTxDestination dest = DecodeDestination(uni_get_str(find_value(obj, "nodeidentity")));
252 if (dest.which() != COptCCParams::ADDRTYPE_ID)
254 nodeIdentity = uint160();
258 nodeIdentity = GetDestinationID(dest);
262 CNodeData::CNodeData(std::string netAddr, std::string paymentAddr) :
263 networkAddress(netAddr)
265 nodeIdentity = GetDestinationID(DecodeDestination(paymentAddr));
268 CIdentitySignature::CIdentitySignature(const UniValue &uni)
270 version = uni_get_int(find_value(uni, "version"));
271 blockHeight = uni_get_int64(find_value(uni, "blockheight"));
272 UniValue sigs = find_value(uni, "signatures");
273 if (sigs.isArray() && sigs.size())
275 for (int i = 0; i < sigs.size(); i++)
277 signatures.insert(ParseHex(uni_get_str(sigs[i])));
282 uint256 CIdentitySignature::IdentitySignatureHash(const std::vector<uint160> &vdxfCodes,
283 const std::vector<uint256> &statements,
284 const uint160 &systemID,
285 uint32_t blockHeight,
287 const std::string &prefixString,
288 const uint256 &msgHash) const
291 if (version == VERSION_VERUSID)
293 CHashWriterSHA256 ss(SER_GETHASH, PROTOCOL_VERSION);
301 retVal = ss.GetHash();
305 auto ss = CMMRNode<>::GetHashWriter();
307 if (vdxfCodes.size())
311 if (statements.size())
318 if (prefixString.size())
323 retVal = ss.GetHash();
328 CIdentitySignature::ESignatureVerification CIdentitySignature::CheckSignature(const CIdentity &signingID,
329 const std::vector<uint160> &vdxfCodes,
330 const std::vector<uint256> &statements,
331 const uint160 systemID,
332 const std::string &prefixString,
333 const uint256 &msgHash) const
336 std::set<uint160> keys;
337 std::set<uint160> idKeys;
338 for (auto &oneKey : signingID.primaryAddresses)
340 // we currently only support secp256k1 signatures
341 if (oneKey.which() != COptCCParams::ADDRTYPE_PK && oneKey.which() != COptCCParams::ADDRTYPE_PKH)
343 return SIGNATURE_INVALID;
345 idKeys.insert(GetDestinationID(oneKey));
347 uint256 signatureHash = IdentitySignatureHash(vdxfCodes, statements, systemID, blockHeight, signingID.GetID(), prefixString, msgHash);
348 for (auto &oneSig : signatures)
350 if (oneSig.size() != ECDSA_RECOVERABLE_SIZE)
352 return SIGNATURE_INVALID;
354 if (!checkKey.RecoverCompact(signatureHash, oneSig))
356 return SIGNATURE_INVALID;
358 uint160 checkKeyID = checkKey.GetID();
359 if (!idKeys.count(checkKeyID))
361 return SIGNATURE_INVALID;
363 keys.insert(checkKey.GetID());
365 if (keys.size() >= signingID.minSigs)
367 return SIGNATURE_COMPLETE;
369 else if (keys.size())
371 return SIGNATURE_PARTIAL;
375 return SIGNATURE_INVALID;
379 uint160 DecodeCurrencyName(std::string currencyStr)
382 currencyStr = TrimSpaces(currencyStr);
383 if (!currencyStr.size())
387 if (currencyStr.back() == '@')
392 currencyStr = CleanName(currencyStr, parent, true);
393 if (!parent.IsNull() && CCurrencyDefinition::GetID(currencyStr, parent) == ASSETCHAINS_CHAINID)
395 return ASSETCHAINS_CHAINID;
397 CTxDestination currencyDest = DecodeDestination(currencyStr);
398 if (currencyDest.which() == COptCCParams::ADDRTYPE_INVALID)
400 currencyDest = DecodeDestination(currencyStr + "@");
402 if (currencyDest.which() != COptCCParams::ADDRTYPE_INVALID)
404 return GetDestinationID(currencyDest);
409 CCurrencyDefinition::CCurrencyDefinition(const UniValue &obj) :
410 preLaunchDiscount(0),
411 initialFractionalSupply(0),
412 gatewayConverterIssuance(0),
413 minNotariesConfirm(0),
414 idRegistrationFees(IDENTITY_REGISTRATION_FEE),
415 idReferralLevels(DEFAULT_ID_REFERRAL_LEVELS),
416 idImportFees(IDENTITY_IMPORT_FEE),
417 currencyRegistrationFee(CURRENCY_REGISTRATION_FEE),
418 currencyImportFee(CURRENCY_IMPORT_FEE),
419 transactionImportFee(TRANSACTION_TRANSFER_FEE >> 1),
420 transactionExportFee(TRANSACTION_TRANSFER_FEE >> 1)
424 nVersion = uni_get_int64(find_value(obj, "version"), VERSION_CURRENT);
425 options = (uint32_t)uni_get_int64(find_value(obj, "options"));
426 name = std::string(uni_get_str(find_value(obj, "name")), 0, (KOMODO_ASSETCHAIN_MAXLEN - 1));
428 std::string parentStr = uni_get_str(find_value(obj, "parent"));
431 parent = DecodeCurrencyName(parentStr);
434 LogPrintf("%s: invalid parent for currency: %s\n", __func__, parentStr.c_str());
435 nVersion = PBAAS_VERSION_INVALID;
440 name = CleanName(name, parent);
442 std::string systemIDStr = uni_get_str(find_value(obj, "systemid"));
443 if (systemIDStr != "")
445 systemID = DecodeCurrencyName(systemIDStr);
446 // if we have a system, but it is invalid, the json for this definition cannot be valid
447 if (systemID.IsNull())
449 nVersion = PBAAS_VERSION_INVALID;
458 gatewayConverterName = uni_get_str(find_value(obj, "gatewayconvertername"));
459 if (!gatewayConverterName.empty())
461 if (!(IsPBaaSChain() || IsGateway()) || (IsPBaaSChain() && IsGateway()))
463 LogPrintf("%s: a gateway converter currency may only be defined as part of a gateway or PBaaS system definition\n", __func__);
464 nVersion = PBAAS_VERSION_INVALID;
467 else if (IsGateway())
471 uint160 parent = GetID();
472 std::string cleanGatewayName = CleanName(gatewayConverterName, parent, true);
473 uint160 converterID = GetID(cleanGatewayName, parent);
474 if (parent != GetID())
476 LogPrintf("%s: invalid name for gateway converter %s\n", __func__, cleanGatewayName.c_str());
477 nVersion = PBAAS_VERSION_INVALID;
480 gatewayConverterIssuance = AmountFromValueNoErr(find_value(obj, "gatewayconverterissuance"));
483 notarizationProtocol = (ENotarizationProtocol)uni_get_int(find_value(obj, "notarizationprotocol"), (int32_t)NOTARIZATION_NOTARY_CONFIRM);
484 if (notarizationProtocol != NOTARIZATION_NOTARY_CONFIRM && !(IsToken() && notarizationProtocol == NOTARIZATION_AUTO))
486 LogPrintf("%s: notarization protocol for PBaaS chains must be %d (NOTARIZATION_NOTARY_CONFIRM) at this time\n", __func__, (int)NOTARIZATION_NOTARY_CONFIRM);
487 nVersion = PBAAS_VERSION_INVALID;
490 proofProtocol = (EProofProtocol)uni_get_int(find_value(obj, "proofprotocol"), (int32_t)PROOF_PBAASMMR);
491 if (proofProtocol != PROOF_PBAASMMR && proofProtocol != PROOF_CHAINID && proofProtocol != PROOF_ETHNOTARIZATION)
493 LogPrintf("%s: proofprotocol must be %d, %d, or %d\n", __func__, (int)PROOF_PBAASMMR, (int)PROOF_CHAINID, (int)PROOF_ETHNOTARIZATION);
494 nVersion = PBAAS_VERSION_INVALID;
498 nativeCurrencyID = CTransferDestination(find_value(obj, "nativecurrencyid"));
500 std::string launchIDStr = uni_get_str(find_value(obj, "launchsystemid"));
501 if (launchIDStr != "")
503 launchSystemID = DecodeCurrencyName(launchIDStr);
504 // if we have a system, but it is invalid, the json for this definition cannot be valid
505 if (launchSystemID.IsNull())
507 nVersion = PBAAS_VERSION_INVALID;
513 launchSystemID = parent;
516 startBlock = uni_get_int(find_value(obj, "startblock"));
517 endBlock = uni_get_int(find_value(obj, "endblock"));
519 int32_t totalReserveWeight = IsFractional() ? SATOSHIDEN : 0;
520 UniValue currencyArr = find_value(obj, "currencies");
521 UniValue weightArr = find_value(obj, "weights");
522 UniValue conversionArr = find_value(obj, "conversions");
523 UniValue minPreconvertArr = find_value(obj, "minpreconversion");
524 UniValue maxPreconvertArr = find_value(obj, "maxpreconversion");
525 UniValue initialContributionArr = find_value(obj, "initialcontributions");
527 if (currencyArr.isArray() && currencyArr.size())
529 contributions = preconverted = std::vector<int64_t>(currencyArr.size());
533 preLaunchDiscount = AmountFromValueNoErr(find_value(obj, "prelaunchdiscount"));
534 initialFractionalSupply = AmountFromValueNoErr(find_value(obj, "initialsupply"));
536 if (!initialFractionalSupply)
538 LogPrintf("%s: cannot specify zero initial supply for fractional currency\n", __func__);
539 printf("%s: cannot specify zero initial supply for fractional currency\n", __func__);
540 nVersion = PBAAS_VERSION_INVALID;
543 UniValue preLaunchCarveoutsUni = find_value(obj, "prelaunchcarveouts");
544 int32_t preLaunchCarveOutTotal = 0;
545 if (nVersion != PBAAS_VERSION_INVALID && preLaunchCarveoutsUni.isArray())
547 for (int i = 0; i < preLaunchCarveoutsUni.size(); i++)
549 std::vector<std::string> preLaunchCarveOutKey = preLaunchCarveoutsUni[i].getKeys();
550 std::vector<UniValue> preLaunchCarveOutValue = preLaunchCarveoutsUni[i].getValues();
551 if (preLaunchCarveOutKey.size() != 1 || preLaunchCarveOutValue.size() != 1)
553 LogPrintf("%s: each prelaunchcarveouts entry must contain one destination identity and one amount\n", __func__);
554 printf("%s: each prelaunchcarveouts entry must contain one destination identity and one amount\n", __func__);
555 nVersion = PBAAS_VERSION_INVALID;
559 CTxDestination carveOutDest = DecodeDestination(preLaunchCarveOutKey[0]);
561 if (carveOutDest.which() != COptCCParams::ADDRTYPE_ID && !(carveOutDest.which() == COptCCParams::ADDRTYPE_INVALID && preLaunchCarveoutsUni.size() == 1))
563 LogPrintf("%s: prelaunchcarveouts destination must be an identity\n", __func__);
564 nVersion = PBAAS_VERSION_INVALID;
568 CAmount carveOutAmount = AmountFromValueNoErr(preLaunchCarveOutValue[0]);
569 if (carveOutAmount <= 0)
571 LogPrintf("%s: prelaunchcarveouts values must be greater than zero\n", __func__);
572 nVersion = PBAAS_VERSION_INVALID;
575 preLaunchCarveOutTotal += carveOutAmount;
576 if (preLaunchDiscount < 0 ||
577 preLaunchDiscount >= SATOSHIDEN ||
578 CCurrencyDefinition::CalculateRatioOfValue((totalReserveWeight - preLaunchCarveOutTotal), SATOSHIDEN - preLaunchDiscount) >= SATOSHIDEN)
580 LogPrintf("%s: prelaunchcarveouts values and discounts must total less than 1\n", __func__);
581 nVersion = PBAAS_VERSION_INVALID;
584 preLaunchCarveOuts.push_back(make_pair(CIdentityID(GetDestinationID(carveOutDest)), preLaunchCarveOutTotal));
588 // if weights are defined, use them as relative ratios of each member currency
589 if (weightArr.isArray() && weightArr.size())
591 if (weightArr.size() != currencyArr.size())
593 LogPrintf("%s: reserve currency weights must be specified for all currencies\n", __func__);
594 nVersion = PBAAS_VERSION_INVALID;
599 for (int i = 0; i < currencyArr.size(); i++)
601 int32_t weight = (int32_t)AmountFromValueNoErr(weightArr[i]);
604 nVersion = PBAAS_VERSION_INVALID;
609 weights.push_back(weight);
611 if (nVersion != PBAAS_VERSION_INVALID)
613 // calculate each weight as a relative part of the total
615 int64_t totalRelativeWeight = 0;
616 for (auto &onew : weights)
618 totalRelativeWeight += onew;
622 arith_uint256 bigReserveWeight(totalReserveWeight);
623 int32_t reserveLeft = totalReserveWeight;
624 for (weightIdx = 0; weightIdx < weights.size(); weightIdx++)
626 CAmount amount = (bigReserveWeight * arith_uint256(weights[weightIdx]) / arith_uint256(totalRelativeWeight)).GetLow64();
627 if (reserveLeft <= amount || (weightIdx + 1) == weights.size())
629 amount = reserveLeft;
631 reserveLeft -= amount;
632 weights[weightIdx] = amount;
637 else if (totalReserveWeight)
639 uint32_t oneWeight = totalReserveWeight / currencyArr.size();
640 uint32_t mod = totalReserveWeight % currencyArr.size();
641 for (int i = 0; i < currencyArr.size(); i++)
643 // distribute remainder of weight among first come currencies
644 int32_t weight = oneWeight;
650 weights.push_back(weight);
655 // if we have weights, we can be a fractional currency
658 // if we are fractional, explicit conversion values are not valid
659 // and are based on non-zero, initial contributions relative to supply
660 if ((conversionArr.isArray() && conversionArr.size() != currencyArr.size()) ||
661 !initialContributionArr.isArray() ||
662 initialContributionArr.size() != currencyArr.size() ||
663 weights.size() != currencyArr.size() ||
666 LogPrintf("%s: reserve currencies must have weights, initial contributions in at least one currency\n", __func__);
667 nVersion = PBAAS_VERSION_INVALID;
672 // if we are not a reserve currency, we either have a conversion vector, or we are not convertible at all
675 LogPrintf("%s: reserve currencies must define currency weight\n", __func__);
676 nVersion = PBAAS_VERSION_INVALID;
678 else if (conversionArr.isArray() && conversionArr.size() && conversionArr.size() != currencyArr.size())
680 LogPrintf("%s: non-reserve currencies must define all conversion rates for supported currencies if they define any\n", __func__);
681 nVersion = PBAAS_VERSION_INVALID;
683 else if (initialContributionArr.isArray() && initialContributionArr.size() != currencyArr.size())
685 LogPrintf("%s: initial contributions for currencies must all be specified if any are specified\n", __func__);
686 nVersion = PBAAS_VERSION_INVALID;
690 if (nVersion != PBAAS_VERSION_INVALID && IsFractional())
692 if (minPreconvertArr.isArray() && minPreconvertArr.size() && minPreconvertArr.size() != currencyArr.size())
694 LogPrintf("%s: currencies with minimum conversion required must define all minimums if they define any\n", __func__);
695 nVersion = PBAAS_VERSION_INVALID;
697 if (maxPreconvertArr.isArray() && maxPreconvertArr.size() && maxPreconvertArr.size() != currencyArr.size())
699 LogPrintf("%s: currencies that include maximum conversions on pre-launch must specify all maximums\n", __func__);
700 nVersion = PBAAS_VERSION_INVALID;
702 if (initialContributionArr.isArray() && initialContributionArr.size() && initialContributionArr.size() != currencyArr.size())
704 LogPrintf("%s: currencies that include initial contributions in one currency on pre-launch must specify all currency amounts\n", __func__);
705 nVersion = PBAAS_VERSION_INVALID;
709 bool isInitialContributions = initialContributionArr.isArray() && initialContributionArr.size();
710 bool isPreconvertMin = minPreconvertArr.isArray() && minPreconvertArr.size();
711 bool isPreconvertMax = maxPreconvertArr.isArray() && maxPreconvertArr.size();
712 bool explicitConversions = (!IsFractional() && conversionArr.isArray()) && conversionArr.size();
714 for (int i = 0; nVersion != PBAAS_VERSION_INVALID && i < currencyArr.size(); i++)
716 uint160 currencyID = DecodeCurrencyName(uni_get_str(currencyArr[i]));
717 // if we have a destination, but it is invalid, the json for this definition cannot be valid
718 if (currencyID.IsNull())
720 nVersion = PBAAS_VERSION_INVALID;
725 currencies.push_back(currencyID);
728 if (isInitialContributions && i < initialContributionArr.size())
730 int64_t contrib = AmountFromValueNoErr(initialContributionArr[i]);
731 contributions[i] = contrib;
732 preconverted[i] = contrib;
738 minPre = AmountFromValueNoErr(minPreconvertArr[i]);
741 LogPrintf("%s: minimum preconversions for any currency may not be less than 0\n", __func__);
742 nVersion = PBAAS_VERSION_INVALID;
745 minPreconvert.push_back(minPre);
749 int64_t maxPre = AmountFromValueNoErr(maxPreconvertArr[i]);
750 if (maxPre < 0 || maxPre < minPre)
752 LogPrintf("%s: maximum preconversions for any currency may not be less than 0 or minimum\n", __func__);
753 nVersion = PBAAS_VERSION_INVALID;
756 maxPreconvert.push_back(maxPre);
758 if (explicitConversions)
760 int64_t conversion = AmountFromValueNoErr(conversionArr[i]);
763 LogPrintf("%s: conversions for any currency must be greater than 0\n", __func__);
764 nVersion = PBAAS_VERSION_INVALID;
767 conversions.push_back(conversion);
771 conversions.push_back(0);
776 UniValue preallocationArr = find_value(obj, "preallocations");
777 if (preallocationArr.isArray())
779 for (int i = 0; i < preallocationArr.size(); i++)
781 std::vector<std::string> preallocationKey = preallocationArr[i].getKeys();
782 std::vector<UniValue> preallocationValue = preallocationArr[i].getValues();
783 if (preallocationKey.size() != 1 || preallocationValue.size() != 1)
785 LogPrintf("%s: each preallocation entry must contain one destination identity and one amount\n", __func__);
786 printf("%s: each preallocation entry must contain one destination identity and one amount\n", __func__);
787 nVersion = PBAAS_VERSION_INVALID;
791 CTxDestination preallocDest = DecodeDestination(preallocationKey[0]);
793 if (preallocDest.which() != COptCCParams::ADDRTYPE_ID && preallocDest.which() != COptCCParams::ADDRTYPE_INVALID)
795 LogPrintf("%s: preallocation destination must be an identity\n", __func__);
796 nVersion = PBAAS_VERSION_INVALID;
800 CAmount preAllocAmount = AmountFromValueNoErr(preallocationValue[0]);
801 if (preAllocAmount <= 0)
803 LogPrintf("%s: preallocation values must be greater than zero\n", __func__);
804 nVersion = PBAAS_VERSION_INVALID;
807 preAllocation.push_back(make_pair(CIdentityID(GetDestinationID(preallocDest)), preAllocAmount));
811 UniValue notaryArr = find_value(obj, "notaries");
812 minNotariesConfirm = 0;
813 if (notaryArr.isArray())
815 for (int i = 0; i < notaryArr.size(); i++)
817 CIdentityID notaryID;
818 CTxDestination notaryDest = DecodeDestination(uni_get_str(notaryArr[i]));
819 notaryID = GetDestinationID(notaryDest);
820 // if we have a destination, but it is invalid, the json for this definition cannot be valid
821 if (notaryID.IsNull())
823 nVersion = PBAAS_VERSION_INVALID;
827 notaries.push_back(notaryID);
830 minNotariesConfirm = uni_get_int(find_value(obj, "minnotariesconfirm"));
833 idRegistrationFees = uni_get_int64(find_value(obj, "idregistrationfees"), idRegistrationFees);
834 idReferralLevels = uni_get_int(find_value(obj, "idreferrallevels"), idReferralLevels);
835 idImportFees = uni_get_int64(find_value(obj, "idimportfees"), idImportFees);
837 auto vEras = uni_getValues(find_value(obj, "eras"));
838 if (vEras.size() > ASSETCHAINS_MAX_ERAS)
840 vEras.resize(ASSETCHAINS_MAX_ERAS);
845 currencyRegistrationFee = uni_get_int64(find_value(obj, "currencyregistrationfee"), currencyRegistrationFee);
846 currencyImportFee = uni_get_int64(find_value(obj, "currencyimportfee"), currencyImportFee);
847 transactionImportFee = uni_get_int64(find_value(obj, "transactionimportfee"), transactionImportFee);
848 transactionExportFee = uni_get_int64(find_value(obj, "transactionexportfee"), transactionExportFee);
850 if (!gatewayID.IsNull())
852 gatewayConverterIssuance = uni_get_int64(find_value(obj, "gatewayconverterissuance"));
855 for (auto era : vEras)
857 rewards.push_back(uni_get_int64(find_value(era, "reward")));
858 rewardsDecay.push_back(uni_get_int64(find_value(era, "decay")));
859 halving.push_back(uni_get_int64(find_value(era, "halving")));
860 eraEnd.push_back(uni_get_int64(find_value(era, "eraend")));
865 LogPrintf("%s: PBaaS chain does not have valid rewards eras");
866 nVersion = PBAAS_VERSION_INVALID;
872 LogPrintf("%s: exception reading currency definition JSON\n", __func__, e.what());
873 nVersion = PBAAS_VERSION_INVALID;
877 int64_t CCurrencyDefinition::CalculateRatioOfValue(int64_t value, int64_t ratio)
879 arith_uint256 bigAmount(value);
880 static const arith_uint256 bigSatoshi(SATOSHIDEN);
882 int64_t retVal = ((bigAmount * arith_uint256(ratio)) / bigSatoshi).GetLow64();
886 // this will only return an accurate result after total preconversion has been updated and before any emission
887 int64_t CCurrencyDefinition::GetTotalPreallocation() const
889 CAmount totalPreallocatedNative = 0;
890 for (auto &onePreallocation : preAllocation)
892 totalPreallocatedNative += onePreallocation.second;
894 return totalPreallocatedNative;
897 // this will only return an accurate result after total preconversion has been updated and before any emission
898 int32_t CCurrencyDefinition::GetTotalCarveOut() const
900 int32_t totalCarveOut = 0;
901 for (auto &oneCarveOut : preLaunchCarveOuts)
903 totalCarveOut += oneCarveOut.second;
904 if (oneCarveOut.second < 0 || oneCarveOut.second > SATOSHIDEN || totalCarveOut > SATOSHIDEN)
906 LogPrintf("%s: invalid carve out amount specified %d\n", __func__, oneCarveOut.second);
910 return totalCarveOut;