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 initialization, notarization, and cross-chain token
8 * transactions and enabling liquid or non-liquid tokens across the
13 #include "pbaas/pbaas.h"
14 #include "pbaas/notarization.h"
15 #include "rpc/pbaasrpc.h"
16 #include "pbaas/crosschainrpc.h"
22 CConnectedChains ConnectedChains;
26 return (strcmp(ASSETCHAINS_SYMBOL, "VRSC") == 0 || strcmp(ASSETCHAINS_SYMBOL, "VRSCTEST") == 0);
29 // this adds an opret to a mutable transaction and returns the voutnum if it could be added
30 int32_t AddOpRetOutput(CMutableTransaction &mtx, const CScript &opRetScript)
32 if (opRetScript.IsOpReturn() && opRetScript.size() <= MAX_OP_RETURN_RELAY)
34 CTxOut vOut = CTxOut();
35 vOut.scriptPubKey = opRetScript;
37 mtx.vout.push_back(vOut);
38 return mtx.vout.size() - 1;
46 // returns a pointer to a base chain object, which can be cast to the
47 // object type indicated in its objType member
48 uint256 GetChainObjectHash(const CBaseChainObject &bo)
51 const CChainObject<CBlockHeader> *pNewHeader;
52 const CChainObject<CTransaction> *pNewTx;
53 const CChainObject<CMerkleBranch> *pNewProof;
54 const CChainObject<CHeaderRef> *pNewHeaderRef;
55 const CChainObject<CPriorBlocksCommitment> *pPriors;
56 const CBaseChainObject *retPtr;
64 return pNewHeader->GetHash();
66 case CHAINOBJ_TRANSACTION:
67 return pNewTx->GetHash();
70 return pNewProof->GetHash();
72 case CHAINOBJ_HEADER_REF:
73 return pNewHeaderRef->GetHash();
75 case CHAINOBJ_PRIORBLOCKS:
76 return pPriors->GetHash();
81 // used to export coins from one chain to another, if they are not native, they are represented on the other
83 bool ValidateChainExport(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn)
88 // used to validate import of coins from one chain to another. if they are not native and are supported,
89 // they are represented o the chain as tokens
90 bool ValidateChainImport(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn)
95 // used to validate a specific service reward based on the spending transaction
96 bool ValidateServiceReward(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn)
98 // for each type of service reward, we need to check and see if the spender is
99 // correctly formatted to be a valid spend of the service reward. for notarization
100 // we ensure that the notarization and its outputs are valid and that the spend
101 // applies to the correct billing period
105 // used as a proxy token output for a reserve currency on its fractional reserve chain
106 bool ValidateReserveOutput(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn)
111 // used to convert a fractional reserve currency into its reserve and back
112 bool ValidateReserveExchange(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn)
117 // used for distribution of premine
118 bool ValidatePremineOutput(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn)
124 * Verifies that the input objects match the hashes and returns the transaction.
126 * If the opRetTx has the op ret, this calculates based on the actual transaction and
127 * validates the hashes. If the opRetTx does not have the opRet itself, this validates
128 * by ensuring that all objects are present on this chain, composing the opRet, and
129 * ensuring that the transaction then hashes to the correct txid.
132 bool ValidateOpretProof(CScript &opRet, COpRetProof &orProof)
134 // enumerate through the objects and validate that they are objects of the expected type that hash
135 // to the value expected. return true if so
139 int8_t ObjTypeCode(const CBlockHeader &obj)
141 return CHAINOBJ_HEADER;
144 int8_t ObjTypeCode(const CMerkleBranch &obj)
146 return CHAINOBJ_PROOF;
149 int8_t ObjTypeCode(const CTransaction &obj)
151 return CHAINOBJ_TRANSACTION;
154 int8_t ObjTypeCode(const CHeaderRef &obj)
156 return CHAINOBJ_HEADER_REF;
159 int8_t ObjTypeCode(const CPriorBlocksCommitment &obj)
161 return CHAINOBJ_PRIORBLOCKS;
164 // this adds an opret to a mutable transaction that provides the necessary evidence of a signed, cheating stake transaction
165 CScript StoreOpRetArray(std::vector<CBaseChainObject *> &objPtrs)
168 CDataStream s = CDataStream(SER_NETWORK, PROTOCOL_VERSION);
171 for (auto pobj : objPtrs)
173 if (!DehydrateChainObject(s, pobj))
180 std::vector<unsigned char> vch(s.begin(), s.end());
182 vData << (int32_t)OPRETTYPE_OBJECTARR << vch;
183 vch = std::vector<unsigned char>(vData.begin(), vData.end());
184 return CScript() << OP_RETURN << vch;
187 std::vector<CBaseChainObject *> RetrieveOpRetArray(const CScript &opRetScript)
189 std::vector<unsigned char> vch;
190 std::vector<CBaseChainObject *> vRet;
191 if (opRetScript.IsOpReturn() && GetOpReturnData(opRetScript, vch) && vch.size() > 0)
193 CDataStream s = CDataStream(vch, SER_NETWORK, PROTOCOL_VERSION);
200 if (opRetType == OPRETTYPE_OBJECTARR)
202 CBaseChainObject *pobj;
203 while (!s.empty() && (pobj = RehydrateChainObject(s)))
205 vRet.push_back(pobj);
209 catch(const std::exception& e)
211 std::cerr << e.what() << '\n';
222 CNodeData::CNodeData(UniValue &obj)
224 networkAddress = uni_get_str(find_value(obj, "networkaddress"));
225 CBitcoinAddress ba(uni_get_str(find_value(obj, "paymentaddress")));
226 ba.GetKeyID(paymentAddress);
229 UniValue CNodeData::ToUniValue() const
231 UniValue obj(UniValue::VOBJ);
232 obj.push_back(Pair("networkaddress", networkAddress));
233 obj.push_back(Pair("paymentaddress", CBitcoinAddress(paymentAddress).ToString()));
237 CPBaaSChainDefinition::CPBaaSChainDefinition(const UniValue &obj)
239 nVersion = PBAAS_VERSION;
240 name = uni_get_str(find_value(obj, "name"));
241 CBitcoinAddress ba(uni_get_str(find_value(obj, "paymentaddress")));
242 ba.GetKeyID(address);
243 premine = uni_get_int64(find_value(obj, "premine"));
244 conversion = uni_get_int64(find_value(obj, "conversion"));
245 launchFee = uni_get_int64(find_value(obj, "launchfee"));
246 startBlock = uni_get_int(find_value(obj, "startblock"));
247 endBlock = uni_get_int(find_value(obj, "endblock"));
249 auto vEras = uni_getValues(find_value(obj, "eras"));
250 if (vEras.size() > ASSETCHAINS_MAX_ERAS)
252 vEras.resize(ASSETCHAINS_MAX_ERAS);
254 eras = !vEras.size() ? 1 : vEras.size();
256 for (auto era : vEras)
258 rewards.push_back(uni_get_int64(find_value(era, "reward")));
259 rewardsDecay.push_back(uni_get_int64(find_value(era, "decay")));
260 halving.push_back(uni_get_int64(find_value(era, "halving")));
261 eraEnd.push_back(uni_get_int64(find_value(era, "eraend")));
262 eraOptions.push_back(uni_get_int64(find_value(era, "eraoptions")));
265 billingPeriod = uni_get_int(find_value(obj, "billingperiod"));
266 notarizationReward = uni_get_int64(find_value(obj, "notarizationreward"));
268 auto nodeVec = uni_getValues(find_value(obj, "nodes"));
269 for (auto node : nodeVec)
271 nodes.push_back(CNodeData(node));
275 CPBaaSChainDefinition::CPBaaSChainDefinition(const CTransaction &tx, bool validate)
277 bool definitionFound = false;
278 nVersion = PBAAS_VERSION_INVALID;
279 for (auto out : tx.vout)
282 if (IsPayToCryptoCondition(out.scriptPubKey, p))
284 if (p.evalCode == EVAL_PBAASDEFINITION)
288 nVersion = PBAAS_VERSION_INVALID;
292 FromVector(p.vData[0], *this);
293 definitionFound = true;
305 CServiceReward::CServiceReward(const CTransaction &tx, bool validate)
307 nVersion = PBAAS_VERSION_INVALID;
308 for (auto out : tx.vout)
311 if (IsPayToCryptoCondition(out.scriptPubKey, p))
313 // always take the first for now
314 if (p.evalCode == EVAL_SERVICEREWARD)
316 FromVector(p.vData[0], *this);
329 uint160 CPBaaSChainDefinition::GetChainID(std::string name)
331 const char *chainName = name.c_str();
332 uint256 chainHash = Hash(chainName, chainName + strlen(chainName));
333 return Hash160(chainHash.begin(), chainHash.end());
336 uint160 CPBaaSChainDefinition::GetConditionID(int32_t condition)
338 return CCrossChainRPCData::GetConditionID(name, condition);
341 UniValue CPBaaSChainDefinition::ToUniValue() const
343 UniValue obj(UniValue::VOBJ);
344 obj.push_back(Pair("version", (int64_t)nVersion));
345 obj.push_back(Pair("name", name));
346 obj.push_back(Pair("paymentaddress", CBitcoinAddress(CTxDestination(address)).ToString()));
347 obj.push_back(Pair("premine", (int64_t)premine));
348 obj.push_back(Pair("conversion", (int64_t)conversion));
349 obj.push_back(Pair("launchfee", (int64_t)launchFee));
350 obj.push_back(Pair("conversionpercent", (double)conversion / 100000000));
351 obj.push_back(Pair("launchfeepercent", ((double)launchFee / 100000000) * 100));
352 obj.push_back(Pair("startblock", (int32_t)startBlock));
353 obj.push_back(Pair("endblock", (int32_t)endBlock));
355 UniValue eraArr(UniValue::VARR);
356 for (int i = 0; i < eras; i++)
358 UniValue era(UniValue::VOBJ);
359 era.push_back(Pair("reward", rewards.size() > i ? rewards[i] : (int64_t)0));
360 era.push_back(Pair("decay", rewardsDecay.size() > i ? rewardsDecay[i] : (int64_t)0));
361 era.push_back(Pair("halving", halving.size() > i ? (int32_t)halving[i] : (int32_t)0));
362 era.push_back(Pair("eraend", eraEnd.size() > i ? (int32_t)eraEnd[i] : (int32_t)0));
363 era.push_back(Pair("eraoptions", eraOptions.size() > i ? (int32_t)eraOptions[i] : (int32_t)0));
364 eraArr.push_back(era);
366 obj.push_back(Pair("eras", eraArr));
368 obj.push_back(Pair("billingperiod", billingPeriod));
369 obj.push_back(Pair("notarizationreward", notarizationReward));
371 UniValue nodeArr(UniValue::VARR);
372 for (auto node : nodes)
374 nodeArr.push_back(node.ToUniValue());
376 obj.push_back(Pair("nodes", nodeArr));
381 int CPBaaSChainDefinition::GetDefinedPort() const
385 for (auto node : nodes)
387 SplitHostPort(node.networkAddress, port, host);
396 #define _ASSETCHAINS_TIMELOCKOFF 0xffffffffffffffff
397 extern uint64_t ASSETCHAINS_TIMELOCKGTE, ASSETCHAINS_TIMEUNLOCKFROM, ASSETCHAINS_TIMEUNLOCKTO;
398 extern int64_t ASSETCHAINS_SUPPLY, ASSETCHAINS_REWARD[3], ASSETCHAINS_DECAY[3], ASSETCHAINS_HALVING[3], ASSETCHAINS_ENDSUBSIDY[3];
399 extern int32_t PBAAS_STARTBLOCK, PBAAS_ENDBLOCK, ASSETCHAINS_LWMAPOS;
400 extern uint32_t ASSETCHAINS_ALGO, ASSETCHAINS_VERUSHASH, ASSETCHAINS_LASTERA;
401 extern std::string VERUS_CHAINNAME;
403 // adds the chain definition for this chain and nodes as well
404 // this also sets up the notarization chain, if there is one
405 bool SetThisChain(UniValue &chainDefinition)
407 ConnectedChains.ThisChain() = CPBaaSChainDefinition(chainDefinition);
409 if (ConnectedChains.ThisChain().IsValid())
411 // set all command line parameters into mapArgs from chain definition
412 vector<string> nodeStrs;
413 for (auto node : ConnectedChains.ThisChain().nodes)
415 nodeStrs.push_back(node.networkAddress);
419 mapMultiArgs["-seednode"] = nodeStrs;
421 if (int port = ConnectedChains.ThisChain().GetDefinedPort())
423 mapArgs["-port"] = to_string(port);
426 ASSETCHAINS_SUPPLY = ConnectedChains.ThisChain().premine;
427 ASSETCHAINS_ALGO = ASSETCHAINS_VERUSHASH;
428 ASSETCHAINS_LWMAPOS = 50;
430 ASSETCHAINS_TIMELOCKGTE = _ASSETCHAINS_TIMELOCKOFF;
431 ASSETCHAINS_TIMEUNLOCKFROM = 0;
432 ASSETCHAINS_TIMEUNLOCKTO = 0;
434 auto numEras = ConnectedChains.ThisChain().eras;
435 ASSETCHAINS_LASTERA = numEras - 1;
436 mapArgs["-ac_eras"] = to_string(numEras);
438 mapArgs["-ac_end"] = "";
439 mapArgs["-ac_reward"] = "";
440 mapArgs["-ac_halving"] = "";
441 mapArgs["-ac_decay"] = "";
443 for (int j = 0; j < ASSETCHAINS_MAX_ERAS; j++)
445 if (j > ASSETCHAINS_LASTERA)
447 ASSETCHAINS_REWARD[j] = ASSETCHAINS_REWARD[j-1];
448 ASSETCHAINS_DECAY[j] = ASSETCHAINS_DECAY[j-1];
449 ASSETCHAINS_HALVING[j] = ASSETCHAINS_HALVING[j-1];
450 ASSETCHAINS_ENDSUBSIDY[j] = 0;
454 ASSETCHAINS_REWARD[j] = ConnectedChains.ThisChain().rewards[j];
455 ASSETCHAINS_DECAY[j] = ConnectedChains.ThisChain().rewardsDecay[j];
456 ASSETCHAINS_HALVING[j] = ConnectedChains.ThisChain().halving[j];
457 ASSETCHAINS_ENDSUBSIDY[j] = ConnectedChains.ThisChain().eraEnd[j];
460 mapArgs["-ac_reward"] = to_string(ASSETCHAINS_REWARD[j]);
461 mapArgs["-ac_decay"] = to_string(ASSETCHAINS_DECAY[j]);
462 mapArgs["-ac_halving"] = to_string(ASSETCHAINS_HALVING[j]);
463 mapArgs["-ac_end"] = to_string(ASSETCHAINS_ENDSUBSIDY[j]);
467 mapArgs["-ac_reward"] += "," + to_string(ASSETCHAINS_REWARD[j]);
468 mapArgs["-ac_decay"] += "," + to_string(ASSETCHAINS_DECAY[j]);
469 mapArgs["-ac_halving"] += "," + to_string(ASSETCHAINS_HALVING[j]);
470 mapArgs["-ac_end"] += "," + to_string(ASSETCHAINS_ENDSUBSIDY[j]);
475 PBAAS_STARTBLOCK = ConnectedChains.ThisChain().startBlock;
476 mapArgs["-startblock"] = to_string(PBAAS_STARTBLOCK);
477 PBAAS_ENDBLOCK = ConnectedChains.ThisChain().endBlock;
478 mapArgs["-endblock"] = to_string(PBAAS_ENDBLOCK);
488 // ensures that the chain definition is valid and that there are no other definitions of the same name
489 // that have been confirmed.
490 bool ValidateChainDefinition(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn)
492 // the chain definition output can be spent when the chain is at the end of its life and only then
497 // ensures that the chain definition is valid and that there are no other definitions of the same name
498 // that have been confirmed.
499 bool CheckChainDefinitionOutput(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn)
501 // checked before a chain definition output script is accepted as a valid transaction
503 // basics - we need a chain definition transaction to kick off a PBaaS chain. it must have:
504 // 1) valid chain definition output with parameters in proper ranges and no duplicate name
505 // 2) notarization output with conformant values
506 // 3) finalization output
507 // 3) notarization funding
510 // get the source transaction
513 if (!myGetTransaction(tx.vin[nIn].prevout.hash, thisTx, blkHash))
515 LogPrintf("failed to retrieve transaction %s\n", tx.vin[nIn].prevout.hash.GetHex().c_str());
519 CPBaaSChainDefinition chainDef(thisTx, true);
520 CPBaaSNotarization notarization(thisTx, true);
521 CNotarizationFinalization finalization(thisTx, true);
523 if (!chainDef.IsValid() || !notarization.IsValid() || finalization.IsValid())
525 LogPrintf("transaction specified, %s, must have valid chain definition, notarization, and finaization outputs\n", tx.vin[nIn].prevout.hash.GetHex().c_str());
529 CPBaaSChainDefinition prior;
530 // this ensures that there is no other definition of the same name already on the blockchain
531 if (!GetChainDefinition(chainDef.name, prior))
533 LogPrintf("PBaaS chain with the name %s already exists\n", chainDef.name.c_str());
540 bool CConnectedChains::RemoveMergedBlock(uint160 chainID)
543 LOCK(cs_mergemining);
544 auto chainIt = mergeMinedChains.find(chainID);
545 if (chainIt != mergeMinedChains.end())
547 arith_uint256 target;
548 target.SetCompact(chainIt->second.block.nBits);
549 for (auto removeRange = mergeMinedTargets.equal_range(target); removeRange.first != removeRange.second; removeRange.first++)
551 // make sure we don't just match by target
552 if (removeRange.first->second->GetChainID() == chainID)
554 mergeMinedTargets.erase(removeRange.first);
558 mergeMinedChains.erase(chainID);
559 dirty = retval = true;
561 // if we get to 0, give the thread a kick to stop waiting for mining
562 //if (!mergeMinedChains.size())
564 // sem_submitthread.post();
570 // remove merge mined chains added and not updated since a specific time
571 uint32_t CConnectedChains::PruneOldChains(uint32_t pruneBefore)
573 vector<uint160> toRemove;
575 LOCK(cs_mergemining);
576 for (auto blkData : mergeMinedChains)
578 if (blkData.second.block.nTime < pruneBefore)
580 toRemove.push_back(blkData.first);
584 for (auto id : toRemove)
586 RemoveMergedBlock(id);
590 // adds or updates merge mined blocks
591 // returns false if failed to add
592 bool CConnectedChains::AddMergedBlock(CPBaaSMergeMinedChainData &blkData)
594 // determine if we should replace one or add to the merge mine vector
596 LOCK(cs_mergemining);
598 arith_uint256 target;
599 uint160 cID = blkData.GetChainID();
600 auto it = mergeMinedChains.find(cID);
601 if (it != mergeMinedChains.end())
603 RemoveMergedBlock(cID); // remove it if already there
605 target.SetCompact(blkData.block.nBits);
606 mergeMinedTargets.insert(make_pair(target, &(mergeMinedChains.insert(make_pair(cID, blkData)).first->second)));
612 bool CConnectedChains::GetChainInfo(uint160 chainID, CRPCChainData &rpcChainData)
615 LOCK(cs_mergemining);
616 auto chainIt = mergeMinedChains.find(chainID);
617 if (chainIt != mergeMinedChains.end())
619 rpcChainData = (CRPCChainData)chainIt->second;
626 // this returns a pointer to the data without copy and assumes the lock is held
627 CPBaaSMergeMinedChainData *CConnectedChains::GetChainInfo(uint160 chainID)
630 auto chainIt = mergeMinedChains.find(chainID);
631 if (chainIt != mergeMinedChains.end())
633 return &chainIt->second;
639 bool CConnectedChains::QueueNewBlockHeader(CBlockHeader &bh)
641 printf("QueueNewBlockHeader %s\n", bh.GetHash().GetHex().c_str());
643 LOCK(cs_mergemining);
644 qualifiedHeaders[UintToArith256(bh.GetHash())] = bh;
646 sem_submitthread.post();
649 // get the latest block header and submit one block at a time, returning after there are no more
650 // matching blocks to be found
651 vector<pair<string, UniValue>> CConnectedChains::SubmitQualifiedBlocks()
653 std::set<uint160> inHeader;
654 bool submissionFound;
655 CPBaaSMergeMinedChainData chainData;
656 vector<pair<string, UniValue>> results;
659 arith_uint256 lastHash;
660 CPBaaSBlockHeader pbh;
664 submissionFound = false;
666 LOCK(cs_mergemining);
667 // attempt to submit with the lowest hash answers first to increase the likelihood of submitting
668 // common, merge mined headers for notarization, drop out on any submission
669 for (auto headerIt = qualifiedHeaders.begin(); !submissionFound && headerIt != qualifiedHeaders.end(); headerIt = qualifiedHeaders.begin())
671 // add the PBaaS chain ids from this header to a set for search
672 for (uint32_t i = 0; headerIt->second.GetPBaaSHeader(pbh, i); i++)
674 inHeader.insert(pbh.chainID);
677 // now look through all targets that are equal to or above the hash of this header
678 for (auto chainIt = mergeMinedTargets.lower_bound(headerIt->first); !submissionFound && chainIt != mergeMinedTargets.end(); chainIt++)
680 uint160 chainID = chainIt->second->GetChainID();
681 if (inHeader.count(chainID))
683 // first, check that the winning header matches the block that is there
684 CPBaaSPreHeader preHeader(chainIt->second->block);
685 preHeader.SetBlockData(headerIt->second);
687 // check if the block header matches the block's specific data, only then can we create a submission from this block
688 if (headerIt->second.CheckNonCanonicalData(chainID))
690 // save block as is, remove the block from merged headers, replace header, and submit
691 chainData = *chainIt->second;
693 *(CBlockHeader *)&chainData.block = headerIt->second;
695 // once it is going to be submitted, remove block from this chain until a new one is added again
696 RemoveMergedBlock(chainID);
698 submissionFound = true;
700 //else // not an error condition. code was here for debugging
702 // printf("Mismatch in non-canonical data for chain %s\n", chainIt->second->chainDefinition.name.c_str());
707 // if this header matched no block, discard and move to the next, otherwise, we'll drop through
708 if (!submissionFound)
710 qualifiedHeaders.erase(headerIt);
716 // submit one block and loop again. this approach allows multiple threads
717 // to collectively empty the submission queue, mitigating the impact of
718 // any one stalled daemon
719 UniValue submitParams(UniValue::VARR);
720 submitParams.push_back(EncodeHexBlk(chainData.block));
721 UniValue result, error;
724 result = RPCCall("submitblock", submitParams, chainData.rpcUserPass, chainData.rpcPort, chainData.rpcHost);
725 result = find_value(result, "result");
726 error = find_value(result, "error");
730 result = UniValue(e.what());
732 results.push_back(make_pair(chainData.chainDefinition.name, result));
733 if (result.isStr() || !error.isNull())
735 printf("Error submitting block to %s chain: %s\n", chainData.chainDefinition.name.c_str(), result.isStr() ? result.get_str().c_str() : error.get_str().c_str());
739 printf("Successfully submitted block to %s chain\n", chainData.chainDefinition.name.c_str());
742 } while (submissionFound);
746 // add all merge mined chain PBaaS headers into the blockheader and return the easiest nBits target in the header
747 uint32_t CConnectedChains::CombineBlocks(CBlockHeader &bh)
749 vector<uint160> inHeader;
750 vector<UniValue> toCombine;
751 arith_uint256 blkHash = UintToArith256(bh.GetHash());
752 arith_uint256 target(0);
754 CPBaaSBlockHeader pbh;
757 LOCK(cs_mergemining);
759 CPBaaSSolutionDescriptor descr = CVerusSolutionVector::solutionTools.GetDescriptor(bh.nSolution);
761 for (uint32_t i = 0; i < descr.numPBaaSHeaders; i++)
763 if (bh.GetPBaaSHeader(pbh, i))
765 inHeader.push_back(pbh.chainID);
769 // loop through the existing PBaaS chain ids in the header
770 // remove any that are not either this Chain ID or in our local collection and then add all that are present
771 for (uint32_t i = 0; i < inHeader.size(); i++)
773 auto it = mergeMinedChains.find(inHeader[i]);
774 if (inHeader[i] != ASSETCHAINS_CHAINID && (it == mergeMinedChains.end()))
776 bh.DeletePBaaSHeader(i);
780 for (auto chain : mergeMinedChains)
782 // get the native PBaaS header for each chain and put it into the
783 // header we are given
784 uint160 cid = chain.second.GetChainID();
785 if (chain.second.block.GetPBaaSHeader(pbh, cid) != -1)
787 if (!bh.AddUpdatePBaaSHeader(pbh))
789 LogPrintf("Failure to add PBaaS block header for %s chain\n", chain.second.chainDefinition.name.c_str());
795 t.SetCompact(chain.second.block.nBits);
805 return target.GetCompact();
808 bool CConnectedChains::IsVerusPBaaSAvailable()
810 return notaryChainVersion > "0.6";
813 extern string PBAAS_HOST, PBAAS_USERPASS;
814 extern int32_t PBAAS_PORT;
815 bool CConnectedChains::CheckVerusPBaaSAvailable(UniValue &chainInfoUni, UniValue &chainDefUni)
817 if (chainInfoUni.isObject() && chainDefUni.isObject())
819 UniValue uniVer = find_value(chainInfoUni, "VRSCversion");
822 LOCK(cs_mergemining);
823 notaryChainVersion = uni_get_str(uniVer);
824 notaryChainHeight = uni_get_int(find_value(chainInfoUni, "blocks"));
825 CPBaaSChainDefinition chainDef(chainDefUni);
826 notaryChain = CRPCChainData(chainDef, PBAAS_HOST, PBAAS_PORT, PBAAS_USERPASS);
829 return IsVerusPBaaSAvailable();
832 bool CConnectedChains::CheckVerusPBaaSAvailable()
836 notaryChainVersion = "";
840 // if this is a PBaaS chain, poll for presence of Verus / root chain and current Verus block and version number
841 // tolerate only 15 second timeout
842 UniValue chainInfo, chainDef;
845 UniValue params(UniValue::VARR);
846 chainInfo = find_value(RPCCallRoot("getinfo", params), "result");
847 if (!chainInfo.isNull())
849 params.push_back(VERUS_CHAINNAME);
850 chainDef = find_value(RPCCallRoot("getchaindefinition", params), "result");
852 if (!chainDef.isNull() && CheckVerusPBaaSAvailable(chainInfo, chainDef))
857 } catch (exception e)
861 notaryChainVersion = "";
865 void CConnectedChains::SubmissionThread()
869 arith_uint256 lastHash;
871 // wait for something to check on, then submit blocks that should be submitted
876 // blocks get discarded after no refresh for 5 minutes by default
877 ConnectedChains.PruneOldChains(GetAdjustedTime() - 300);
880 LOCK(cs_mergemining);
881 submit = qualifiedHeaders.size() != 0 && mergeMinedChains.size() != 0;
885 SubmitQualifiedBlocks();
889 sem_submitthread.wait();
896 // if this is a PBaaS chain, poll for presence of Verus / root chain and current Verus block and version number
897 CheckVerusPBaaSAvailable();
898 for (int i = 0; i < 10; i++)
900 boost::this_thread::interruption_point();
905 boost::this_thread::interruption_point();
908 catch (const boost::thread_interrupted&)
910 LogPrintf("Verus merge mining thread terminated\n");
914 void CConnectedChains::SubmissionThreadStub()
916 ConnectedChains.SubmissionThread();
919 bool IsChainDefinitionInput(const CScript &scriptSig)
922 return scriptSig.IsPayToCryptoCondition(&ecode) && ecode == EVAL_PBAASDEFINITION;
925 bool IsServiceRewardInput(const CScript &scriptSig)
927 // this is an output check, and is incorrect. need to change to input
929 return scriptSig.IsPayToCryptoCondition(&ecode) && ecode == EVAL_SERVICEREWARD;