int CInterpreter::GetCamera( void ) { CBlock block; char typeName[MAX_STRING_SIZE]; int type; block.Create( ID_CAMERA ); if (!Match( TK_OPEN_PARENTHESIS )) return Error("syntax error : '(' not found"); if ( GetType( (char *) typeName ) == false ) return false; type = FindSymbol( typeName, m_typeKeywords); switch ( type ) { case TYPE_PAN: //PAN ( ANGLES, DURATION ) block.Write( TK_FLOAT, (float) type ); if ( GetVector( &block ) == false ) return false; if ( GetVector( &block ) == false ) return false; if ( GetFloat( &block ) == false ) return false; break; case TYPE_ZOOM: //ZOOM ( FOV, DURATION ) block.Write( TK_FLOAT, (float) type ); if ( GetFloat( &block ) == false ) return false; if ( GetFloat( &block ) == false ) return false; break; case TYPE_MOVE: //MOVE ( ORIGIN, DURATION ) block.Write( TK_FLOAT, (float) type ); if ( GetVector( &block ) == false ) return false; if ( GetFloat( &block ) == false ) return false; break; case TYPE_FADE: //FADE ( SOURCE(R,G,B,A), DEST(R,G,B,A), DURATION ) block.Write( TK_FLOAT, (float) type ); //Source color if ( GetVector( &block ) == false ) return false; if ( GetFloat( &block ) == false ) return false; //Dest color if ( GetVector( &block ) == false ) return false; if ( GetFloat( &block ) == false ) return false; //Duration if ( GetFloat( &block ) == false ) return false; break; case TYPE_PATH: //PATH ( FILENAME ) block.Write( TK_FLOAT, (float) type ); //Filename if ( GetString( &block ) == false ) return false; break; case TYPE_ENABLE: case TYPE_DISABLE: block.Write( TK_FLOAT, (float) type ); break; case TYPE_SHAKE: //SHAKE ( INTENSITY, DURATION ) block.Write( TK_FLOAT, (float) type ); //Intensity if ( GetFloat( &block ) == false ) return false; //Duration if ( GetFloat( &block ) == false ) return false; break; case TYPE_ROLL: //ROLL ( ANGLE, TIME ) block.Write( TK_FLOAT, (float) type ); //Angle if ( GetFloat( &block ) == false ) return false; //Time if ( GetFloat( &block ) == false ) return false; break; case TYPE_TRACK: //TRACK ( TARGETNAME, SPEED, INITLERP ) block.Write( TK_FLOAT, (float) type ); //Target name if ( GetString( &block ) == false ) return false; //Speed if ( GetFloat( &block ) == false ) return false; //Init lerp if ( GetFloat( &block ) == false ) return false; break; case TYPE_FOLLOW: //FOLLOW ( CAMERAGROUP, SPEED, INITLERP ) block.Write( TK_FLOAT, (float) type ); //Camera group if ( GetString( &block ) == false ) return false; //Speed if ( GetFloat( &block ) == false ) return false; //Init lerp if ( GetFloat( &block ) == false ) return false; break; case TYPE_DISTANCE: //DISTANCE ( DISTANCE, INITLERP ) block.Write( TK_FLOAT, (float) type ); //Distance if ( GetFloat( &block ) == false ) return false; //Init lerp if ( GetFloat( &block ) == false ) return false; break; } if (!Match( TK_CLOSED_PARENTHESIS )) return Error("camera : too many parameters"); m_blockStream->WriteBlock( &block ); return true; }
bool CTxDB::LoadBlockIndex() { if (mapBlockIndex.size() > 0) { // Already loaded once in this session. It can happen during migration // from BDB. return true; } // The block index is an in-memory structure that maps hashes to on-disk // locations where the contents of the block can be found. Here, we scan it // out of the DB and into mapBlockIndex. leveldb::Iterator *iterator = pdb->NewIterator(leveldb::ReadOptions()); // Seek to start key. CDataStream ssStartKey(SER_DISK, CLIENT_VERSION); ssStartKey << make_pair(string("blockindex"), uint256(0)); iterator->Seek(ssStartKey.str()); // Now read each entry. while (iterator->Valid()) { // Unpack keys and values. CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.write(iterator->key().data(), iterator->key().size()); CDataStream ssValue(SER_DISK, CLIENT_VERSION); ssValue.write(iterator->value().data(), iterator->value().size()); string strType; ssKey >> strType; // Did we reach the end of the data to read? if (fRequestShutdown || strType != "blockindex") break; CDiskBlockIndex diskindex; ssValue >> diskindex; uint256 blockHash = diskindex.GetBlockHash(); // Construct block index object CBlockIndex* pindexNew = InsertBlockIndex(blockHash); pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev); pindexNew->pnext = InsertBlockIndex(diskindex.hashNext); pindexNew->nFile = diskindex.nFile; pindexNew->nBlockPos = diskindex.nBlockPos; pindexNew->nHeight = diskindex.nHeight; pindexNew->nMint = diskindex.nMint; pindexNew->nMoneySupply = diskindex.nMoneySupply; pindexNew->nFlags = diskindex.nFlags; pindexNew->nStakeModifier = diskindex.nStakeModifier; pindexNew->prevoutStake = diskindex.prevoutStake; pindexNew->nStakeTime = diskindex.nStakeTime; pindexNew->hashProof = diskindex.hashProof; pindexNew->nVersion = diskindex.nVersion; pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot; pindexNew->nTime = diskindex.nTime; pindexNew->nBits = diskindex.nBits; pindexNew->nNonce = diskindex.nNonce; // Watch for genesis block if (pindexGenesisBlock == NULL && blockHash == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet)) pindexGenesisBlock = pindexNew; if (!pindexNew->CheckIndex()) { delete iterator; return error("LoadBlockIndex() : CheckIndex failed at %d", pindexNew->nHeight); } // ARbit: build setStakeSeen if (pindexNew->IsProofOfStake()) setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime)); iterator->Next(); } delete iterator; if (fRequestShutdown) return true; // Calculate nChainTrust vector<pair<int, CBlockIndex*> > vSortedByHeight; vSortedByHeight.reserve(mapBlockIndex.size()); BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex) { CBlockIndex* pindex = item.second; vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex)); } sort(vSortedByHeight.begin(), vSortedByHeight.end()); BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight) { CBlockIndex* pindex = item.second; pindex->nChainTrust = (pindex->pprev ? pindex->pprev->nChainTrust : 0) + pindex->GetBlockTrust(); // ARbit: calculate stake modifier checksum pindex->nStakeModifierChecksum = GetStakeModifierChecksum(pindex); if (!CheckStakeModifierCheckpoints(pindex->nHeight, pindex->nStakeModifierChecksum)) return error("CTxDB::LoadBlockIndex() : Failed stake modifier checkpoint height=%d, modifier=0x%016"PRIx64, pindex->nHeight, pindex->nStakeModifier); } // Load hashBestChain pointer to end of best chain if (!ReadHashBestChain(hashBestChain)) { if (pindexGenesisBlock == NULL) return true; return error("CTxDB::LoadBlockIndex() : hashBestChain not loaded"); } if (!mapBlockIndex.count(hashBestChain)) return error("CTxDB::LoadBlockIndex() : hashBestChain not found in the block index"); pindexBest = mapBlockIndex[hashBestChain]; nBestHeight = pindexBest->nHeight; nBestChainTrust = pindexBest->nChainTrust; printf("LoadBlockIndex(): hashBestChain=%s height=%d trust=%s date=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, CBigNum(nBestChainTrust).ToString().c_str(), DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str()); // ARbit: load hashSyncCheckpoint if (!ReadSyncCheckpoint(Checkpoints::hashSyncCheckpoint)) return error("CTxDB::LoadBlockIndex() : hashSyncCheckpoint not loaded"); printf("LoadBlockIndex(): synchronized checkpoint %s\n", Checkpoints::hashSyncCheckpoint.ToString().c_str()); // Load bnBestInvalidTrust, OK if it doesn't exist CBigNum bnBestInvalidTrust; ReadBestInvalidTrust(bnBestInvalidTrust); nBestInvalidTrust = bnBestInvalidTrust.getuint256(); // Verify blocks in the best chain int nCheckLevel = GetArg("-checklevel", 1); int nCheckDepth = GetArg( "-checkblocks", 2500); if (nCheckDepth == 0) nCheckDepth = 1000000000; // suffices until the year 19000 if (nCheckDepth > nBestHeight) nCheckDepth = nBestHeight; printf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel); CBlockIndex* pindexFork = NULL; map<pair<unsigned int, unsigned int>, CBlockIndex*> mapBlockPos; for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev) { if (fRequestShutdown || pindex->nHeight < nBestHeight-nCheckDepth) break; CBlock block; if (!block.ReadFromDisk(pindex)) return error("LoadBlockIndex() : block.ReadFromDisk failed"); // check level 1: verify block validity // check level 7: verify block signature too if (nCheckLevel>0 && !block.CheckBlock(true, true, (nCheckLevel>6))) { printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); pindexFork = pindex->pprev; } // check level 2: verify transaction index validity if (nCheckLevel>1) { pair<unsigned int, unsigned int> pos = make_pair(pindex->nFile, pindex->nBlockPos); mapBlockPos[pos] = pindex; BOOST_FOREACH(const CTransaction &tx, block.vtx) { uint256 hashTx = tx.GetHash(); CTxIndex txindex; if (ReadTxIndex(hashTx, txindex)) { // check level 3: checker transaction hashes if (nCheckLevel>2 || pindex->nFile != txindex.pos.nFile || pindex->nBlockPos != txindex.pos.nBlockPos) { // either an error or a duplicate transaction CTransaction txFound; if (!txFound.ReadFromDisk(txindex.pos)) { printf("LoadBlockIndex() : *** cannot read mislocated transaction %s\n", hashTx.ToString().c_str()); pindexFork = pindex->pprev; } else if (txFound.GetHash() != hashTx) // not a duplicate tx { printf("LoadBlockIndex(): *** invalid tx position for %s\n", hashTx.ToString().c_str()); pindexFork = pindex->pprev; } } // check level 4: check whether spent txouts were spent within the main chain unsigned int nOutput = 0; if (nCheckLevel>3) { BOOST_FOREACH(const CDiskTxPos &txpos, txindex.vSpent) { if (!txpos.IsNull()) { pair<unsigned int, unsigned int> posFind = make_pair(txpos.nFile, txpos.nBlockPos); if (!mapBlockPos.count(posFind)) { printf("LoadBlockIndex(): *** found bad spend at %d, hashBlock=%s, hashTx=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str(), hashTx.ToString().c_str()); pindexFork = pindex->pprev; } // check level 6: check whether spent txouts were spent by a valid transaction that consume them if (nCheckLevel>5) { CTransaction txSpend; if (!txSpend.ReadFromDisk(txpos)) { printf("LoadBlockIndex(): *** cannot read spending transaction of %s:%i from disk\n", hashTx.ToString().c_str(), nOutput); pindexFork = pindex->pprev; } else if (!txSpend.CheckTransaction()) { printf("LoadBlockIndex(): *** spending transaction of %s:%i is invalid\n", hashTx.ToString().c_str(), nOutput); pindexFork = pindex->pprev; } else { bool fFound = false; BOOST_FOREACH(const CTxIn &txin, txSpend.vin) if (txin.prevout.hash == hashTx && txin.prevout.n == nOutput) fFound = true; if (!fFound) { printf("LoadBlockIndex(): *** spending transaction of %s:%i does not spend it\n", hashTx.ToString().c_str(), nOutput); pindexFork = pindex->pprev; } } } } nOutput++; } } }
int CInterpreter::GetSet( void ) { CBlock block; block.Create( ID_SET ); if (!Match( TK_OPEN_PARENTHESIS )) return Error("syntax error : '(' not found"); if ( GetString( &block ) == false ) return false; //Check for get placement if ( MatchGet() ) { if ( GetGet( &block ) == false ) return false; } else { switch( GetNextType() ) { case TK_INT: if ( GetInteger( &block ) == false ) return false; break; case TK_FLOAT: if ( GetFloat( &block ) == false ) return false; break; case TK_STRING: if ( GetString( &block ) == false ) return false; break; case TK_VECTOR_START: if ( GetVector( &block ) == false ) return false; break; default: if ( MatchTag() ) { GetTag( &block ); break; } if ( MatchRandom() ) { GetRandom( &block ); break; } return Error("unknown parameter type"); break; } } if (!Match( TK_CLOSED_PARENTHESIS )) return Error("set : too many parameters"); m_blockStream->WriteBlock( &block ); return true; }
UniValue generate(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 1) throw runtime_error( "generate numblocks\n" "\nMine blocks immediately (before the RPC call returns)\n" "\nNote: this function can only be used on the regtest network\n" "\nArguments:\n" "1. numblocks (numeric, required) How many blocks are generated immediately.\n" "\nResult\n" "[ blockhashes ] (array) hashes of blocks generated\n" "\nExamples:\n" "\nGenerate 11 blocks\n" + HelpExampleCli("generate", "11") ); if (!Params().MineBlocksOnDemand()) throw JSONRPCError(RPC_METHOD_NOT_FOUND, "This method can only be used on regtest"); int nHeightStart = 0; int nHeightEnd = 0; int nHeight = 0; int nGenerate = params[0].get_int(); boost::shared_ptr<CReserveScript> coinbaseScript; GetMainSignals().ScriptForMining(coinbaseScript); // If the keypool is exhausted, no script is returned at all. Catch this. if (!coinbaseScript) throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); //throw an error if no script was provided if (coinbaseScript->reserveScript.empty()) throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available (mining requires a wallet)"); { // Don't keep cs_main locked LOCK(cs_main); nHeightStart = chainActive.Height(); nHeight = nHeightStart; nHeightEnd = nHeightStart+nGenerate; } unsigned int nExtraNonce = 0; UniValue blockHashes(UniValue::VARR); while (nHeight < nHeightEnd) { auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(Params(), coinbaseScript->reserveScript)); if (!pblocktemplate.get()) throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); CBlock *pblock = &pblocktemplate->block; { LOCK(cs_main); IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce); } while (!CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) { // Yes, there is a chance every nonce could fail to satisfy the -regtest // target -- 1 in 2^(2^32). That ain't gonna happen. ++pblock->nNonce; } CValidationState state; if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL)) throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); ++nHeight; blockHashes.push_back(pblock->GetHash().GetHex()); //mark script as important because it was used at least for one coinbase output coinbaseScript->KeepScript(); } return blockHashes; }
UniValue getblocktemplate(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 1) throw runtime_error( "getblocktemplate ( \"jsonrequestobject\" )\n" "\nIf the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'.\n" "It returns data needed to construct a block to work on.\n" "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n" "\nArguments:\n" "1. \"jsonrequestobject\" (string, optional) A json object in the following spec\n" " {\n" " \"mode\":\"template\" (string, optional) This must be set to \"template\" or omitted\n" " \"capabilities\":[ (array, optional) A list of strings\n" " \"support\" (string) client side supported feature, 'longpoll', 'coinbasetxn', 'coinbasevalue', 'proposal', 'serverlist', 'workid'\n" " ,...\n" " ]\n" " }\n" "\n" "\nResult:\n" "{\n" " \"version\" : n, (numeric) The block version\n" " \"previousblockhash\" : \"xxxx\", (string) The hash of current highest block\n" " \"transactions\" : [ (array) contents of non-coinbase transactions that should be included in the next block\n" " {\n" " \"data\" : \"xxxx\", (string) transaction data encoded in hexadecimal (byte-for-byte)\n" " \"hash\" : \"xxxx\", (string) hash/id encoded in little-endian hexadecimal\n" " \"depends\" : [ (array) array of numbers \n" " n (numeric) transactions before this one (by 1-based index in 'transactions' list) that must be present in the final block if this one is\n" " ,...\n" " ],\n" " \"fee\": n, (numeric) difference in value between transaction inputs and outputs (in duffs); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one\n" " \"sigops\" : n, (numeric) total number of SigOps, as counted for purposes of block limits; if key is not present, sigop count is unknown and clients MUST NOT assume there aren't any\n" " \"required\" : true|false (boolean) if provided and true, this transaction must be in the final block\n" " }\n" " ,...\n" " ],\n" " \"coinbaseaux\" : { (json object) data that should be included in the coinbase's scriptSig content\n" " \"flags\" : \"flags\" (string) \n" " },\n" " \"coinbasevalue\" : n, (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in duffs)\n" " \"coinbasetxn\" : { ... }, (json object) information for coinbase transaction\n" " \"target\" : \"xxxx\", (string) The hash target\n" " \"mintime\" : xxx, (numeric) The minimum timestamp appropriate for next block time in seconds since epoch (Jan 1 1970 GMT)\n" " \"mutable\" : [ (array of string) list of ways the block template may be changed \n" " \"value\" (string) A way the block template may be changed, e.g. 'time', 'transactions', 'prevblock'\n" " ,...\n" " ],\n" " \"noncerange\" : \"00000000ffffffff\", (string) A range of valid nonces\n" " \"sigoplimit\" : n, (numeric) limit of sigops in blocks\n" " \"sizelimit\" : n, (numeric) limit of block size\n" " \"curtime\" : ttt, (numeric) current timestamp in seconds since epoch (Jan 1 1970 GMT)\n" " \"bits\" : \"xxx\", (string) compressed target of next block\n" " \"height\" : n (numeric) The height of the next block\n" " \"masternode\" : { (json object) required masternode payee that must be included in the next block\n" " \"payee\" : \"xxxx\", (string) payee address\n" " \"script\" : \"xxxx\", (string) payee scriptPubKey\n" " \"amount\": n (numeric) required amount to pay\n" " },\n" " \"masternode_payments_started\" : true|false, (boolean) true, if masternode payments started\n" " \"masternode_payments_enforced\" : true|false, (boolean) true, if masternode payments are enforced\n" " \"superblock\" : [ (array) required superblock payees that must be included in the next block\n" " {\n" " \"payee\" : \"xxxx\", (string) payee address\n" " \"script\" : \"xxxx\", (string) payee scriptPubKey\n" " \"amount\": n (numeric) required amount to pay\n" " }\n" " ,...\n" " ],\n" " \"superblocks_started\" : true|false, (boolean) true, if superblock payments started\n" " \"superblocks_enabled\" : true|false (boolean) true, if superblock payments are enabled\n" "}\n" "\nExamples:\n" + HelpExampleCli("getblocktemplate", "") + HelpExampleRpc("getblocktemplate", "") ); LOCK(cs_main); std::string strMode = "template"; UniValue lpval = NullUniValue; if (params.size() > 0) { const UniValue& oparam = params[0].get_obj(); const UniValue& modeval = find_value(oparam, "mode"); if (modeval.isStr()) strMode = modeval.get_str(); else if (modeval.isNull()) { /* Do nothing */ } else throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); lpval = find_value(oparam, "longpollid"); if (strMode == "proposal") { const UniValue& dataval = find_value(oparam, "data"); if (!dataval.isStr()) throw JSONRPCError(RPC_TYPE_ERROR, "Missing data String key for proposal"); CBlock block; if (!DecodeHexBlk(block, dataval.get_str())) throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed"); uint256 hash = block.GetHash(); BlockMap::iterator mi = mapBlockIndex.find(hash); if (mi != mapBlockIndex.end()) { CBlockIndex *pindex = mi->second; if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) return "duplicate"; if (pindex->nStatus & BLOCK_FAILED_MASK) return "duplicate-invalid"; return "duplicate-inconclusive"; } CBlockIndex* const pindexPrev = chainActive.Tip(); // TestBlockValidity only supports blocks built on the current Tip if (block.hashPrevBlock != pindexPrev->GetBlockHash()) return "inconclusive-not-best-prevblk"; CValidationState state; TestBlockValidity(state, Params(), block, pindexPrev, false, true); return BIP22ValidationResult(state); } } if (strMode != "template") throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); if (vNodes.empty()) throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "H2O Core is not connected!"); if (IsInitialBlockDownload()) throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "H2O Core is downloading blocks..."); if (!masternodeSync.IsSynced()) throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "H2O Core is syncing with network..."); static unsigned int nTransactionsUpdatedLast; if (!lpval.isNull()) { // Wait to respond until either the best block changes, OR a minute has passed and there are more transactions uint256 hashWatchedChain; boost::system_time checktxtime; unsigned int nTransactionsUpdatedLastLP; if (lpval.isStr()) { // Format: <hashBestChain><nTransactionsUpdatedLast> std::string lpstr = lpval.get_str(); hashWatchedChain.SetHex(lpstr.substr(0, 64)); nTransactionsUpdatedLastLP = atoi64(lpstr.substr(64)); } else { // NOTE: Spec does not specify behaviour for non-string longpollid, but this makes testing easier hashWatchedChain = chainActive.Tip()->GetBlockHash(); nTransactionsUpdatedLastLP = nTransactionsUpdatedLast; } // Release the wallet and main lock while waiting LEAVE_CRITICAL_SECTION(cs_main); { checktxtime = boost::get_system_time() + boost::posix_time::minutes(1); boost::unique_lock<boost::mutex> lock(csBestBlock); while (chainActive.Tip()->GetBlockHash() == hashWatchedChain && IsRPCRunning()) { if (!cvBlockChange.timed_wait(lock, checktxtime)) { // Timeout: Check transactions for update if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLastLP) break; checktxtime += boost::posix_time::seconds(10); } } } ENTER_CRITICAL_SECTION(cs_main); if (!IsRPCRunning()) throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down"); // TODO: Maybe recheck connections/IBD and (if something wrong) send an expires-immediately template to stop miners? } // Update block static CBlockIndex* pindexPrev; static int64_t nStart; static CBlockTemplate* pblocktemplate; if (pindexPrev != chainActive.Tip() || (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5)) { // Clear pindexPrev so future calls make a new block, despite any failures from here on pindexPrev = NULL; // Store the chainActive.Tip() used before CreateNewBlock, to avoid races nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); CBlockIndex* pindexPrevNew = chainActive.Tip(); nStart = GetTime(); // Create new block if(pblocktemplate) { delete pblocktemplate; pblocktemplate = NULL; } CScript scriptDummy = CScript() << OP_TRUE; pblocktemplate = CreateNewBlock(Params(), scriptDummy); if (!pblocktemplate) throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); // Need to update only after we know CreateNewBlock succeeded pindexPrev = pindexPrevNew; } CBlock* pblock = &pblocktemplate->block; // pointer for convenience // Update nTime UpdateTime(pblock, Params().GetConsensus(), pindexPrev); pblock->nNonce = 0; UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal"); UniValue transactions(UniValue::VARR); map<uint256, int64_t> setTxIndex; int i = 0; BOOST_FOREACH (const CTransaction& tx, pblock->vtx) { uint256 txHash = tx.GetHash(); setTxIndex[txHash] = i++; if (tx.IsCoinBase()) continue; UniValue entry(UniValue::VOBJ); entry.push_back(Pair("data", EncodeHexTx(tx))); entry.push_back(Pair("hash", txHash.GetHex())); UniValue deps(UniValue::VARR); BOOST_FOREACH (const CTxIn &in, tx.vin) { if (setTxIndex.count(in.prevout.hash)) deps.push_back(setTxIndex[in.prevout.hash]); } entry.push_back(Pair("depends", deps)); int index_in_template = i - 1; entry.push_back(Pair("fee", pblocktemplate->vTxFees[index_in_template])); entry.push_back(Pair("sigops", pblocktemplate->vTxSigOps[index_in_template])); transactions.push_back(entry); } UniValue aux(UniValue::VOBJ); aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end()))); arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits); static UniValue aMutable(UniValue::VARR); if (aMutable.empty()) { aMutable.push_back("time"); aMutable.push_back("transactions"); aMutable.push_back("prevblock"); } UniValue result(UniValue::VOBJ); result.push_back(Pair("capabilities", aCaps)); result.push_back(Pair("version", pblock->nVersion)); result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex())); result.push_back(Pair("transactions", transactions)); result.push_back(Pair("coinbaseaux", aux)); result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].GetValueOut())); result.push_back(Pair("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast))); result.push_back(Pair("target", hashTarget.GetHex())); result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1)); result.push_back(Pair("mutable", aMutable)); result.push_back(Pair("noncerange", "00000000ffffffff")); result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS)); result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE)); result.push_back(Pair("curtime", pblock->GetBlockTime())); result.push_back(Pair("bits", strprintf("%08x", pblock->nBits))); result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1))); UniValue masternodeObj(UniValue::VOBJ); if(pblock->txoutMasternode != CTxOut()) { CTxDestination address1; ExtractDestination(pblock->txoutMasternode.scriptPubKey, address1); CBitcoinAddress address2(address1); masternodeObj.push_back(Pair("payee", address2.ToString().c_str())); masternodeObj.push_back(Pair("script", HexStr(pblock->txoutMasternode.scriptPubKey.begin(), pblock->txoutMasternode.scriptPubKey.end()))); masternodeObj.push_back(Pair("amount", pblock->txoutMasternode.nValue)); } result.push_back(Pair("masternode", masternodeObj)); result.push_back(Pair("masternode_payments_started", pindexPrev->nHeight + 1 > Params().GetConsensus().nMasternodePaymentsStartBlock)); result.push_back(Pair("masternode_payments_enforced", sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT))); UniValue superblockObjArray(UniValue::VARR); if(pblock->voutSuperblock.size()) { BOOST_FOREACH (const CTxOut& txout, pblock->voutSuperblock) { UniValue entry(UniValue::VOBJ); CTxDestination address1; ExtractDestination(txout.scriptPubKey, address1); CBitcoinAddress address2(address1); entry.push_back(Pair("payee", address2.ToString().c_str())); entry.push_back(Pair("script", HexStr(txout.scriptPubKey.begin(), txout.scriptPubKey.end()))); entry.push_back(Pair("amount", txout.nValue)); superblockObjArray.push_back(entry); } }
// max_nonce is not used by this function int scanhash_hodl( int threadNumber, struct work* work, uint32_t max_nonce, uint64_t *hashes_done ) { unsigned char *mainMemoryPsuedoRandomData = hodl_scratchbuf; uint32_t *pdata = work->data; uint32_t *ptarget = work->target; //retreive target std::stringstream s; for (int i = 7; i>=0; i--) s << strprintf("%08x", ptarget[i]); //retreive preveios hash std::stringstream p; for (int i = 0; i < 8; i++) p << strprintf("%08x", swab32(pdata[8 - i])); //retreive merkleroot std::stringstream m; for (int i = 0; i < 8; i++) m << strprintf("%08x", swab32(pdata[16 - i])); CBlock pblock; pblock.SetNull(); pblock.nVersion=swab32(pdata[0]); pblock.nNonce=swab32(pdata[19]); pblock.nTime=swab32(pdata[17]); pblock.nBits=swab32(pdata[18]); pblock.hashPrevBlock=uint256S(p.str()); pblock.hashMerkleRoot=uint256S(m.str()); uint256 hashTarget=uint256S(s.str()); int collisions=0; uint256 hash; //Begin AES Search //Allocate temporary memory uint32_t cacheMemorySize = (1<<L2CACHE_TARGET); //2^12 = 4096 bytes uint32_t comparisonSize=(1<<(PSUEDORANDOM_DATA_SIZE-L2CACHE_TARGET)); //2^(30-12) = 256K unsigned char *cacheMemoryOperatingData; unsigned char *cacheMemoryOperatingData2; cacheMemoryOperatingData=new unsigned char[cacheMemorySize+16]; cacheMemoryOperatingData2=new unsigned char[cacheMemorySize]; //Create references to data as 32 bit arrays uint32_t* cacheMemoryOperatingData32 = (uint32_t*)cacheMemoryOperatingData; uint32_t* cacheMemoryOperatingData322 = (uint32_t*)cacheMemoryOperatingData2; //Search for pattern in psuedorandom data unsigned char key[32] = {0}; unsigned char iv[AES_BLOCK_SIZE]; int outlen1, outlen2; //Iterate over the data // int searchNumber=comparisonSize/totalThreads; int searchNumber = comparisonSize / opt_n_threads; int startLoc=threadNumber*searchNumber; EVP_CIPHER_CTX ctx; for(int32_t k = startLoc;k<startLoc+searchNumber && !work_restart[threadNumber].restart;k++){ //copy data to first l2 cache memcpy((char*)&cacheMemoryOperatingData[0], (char*)&mainMemoryPsuedoRandomData[k*cacheMemorySize], cacheMemorySize); for(int j=0;j<AES_ITERATIONS;j++){ //use last 4 bytes of first cache as next location uint32_t nextLocation = cacheMemoryOperatingData32[(cacheMemorySize/4)-1]%comparisonSize; //Copy data from indicated location to second l2 cache - memcpy((char*)&cacheMemoryOperatingData2[0], (char*)&mainMemoryPsuedoRandomData[nextLocation*cacheMemorySize], cacheMemorySize); //XOR location data into second cache for(uint32_t i = 0; i < cacheMemorySize/4; i++) cacheMemoryOperatingData322[i] = cacheMemoryOperatingData32[i] ^ cacheMemoryOperatingData322[i]; memcpy(key,(unsigned char*)&cacheMemoryOperatingData2[cacheMemorySize-32],32); memcpy(iv,(unsigned char*)&cacheMemoryOperatingData2[cacheMemorySize-AES_BLOCK_SIZE],AES_BLOCK_SIZE); EVP_EncryptInit(&ctx, EVP_aes_256_cbc(), key, iv); EVP_EncryptUpdate(&ctx, cacheMemoryOperatingData, &outlen1, cacheMemoryOperatingData2, cacheMemorySize); EVP_EncryptFinal(&ctx, cacheMemoryOperatingData + outlen1, &outlen2); EVP_CIPHER_CTX_cleanup(&ctx); } //use last X bits as solution uint32_t solution=cacheMemoryOperatingData32[(cacheMemorySize/4)-1]%comparisonSize; if(solution<1000){ uint32_t proofOfCalculation=cacheMemoryOperatingData32[(cacheMemorySize/4)-2]; pblock.nStartLocation = k; pblock.nFinalCalculation = proofOfCalculation; hash = Hash(BEGIN(pblock.nVersion), END(pblock.nFinalCalculation)); collisions++; if (UintToArith256(hash) <= UintToArith256(hashTarget) && !work_restart[threadNumber].restart){ pdata[21] = swab32(pblock.nFinalCalculation); pdata[20] = swab32(pblock.nStartLocation); *hashes_done = collisions; //free memory delete [] cacheMemoryOperatingData; delete [] cacheMemoryOperatingData2; return 1; } } } //free memory delete [] cacheMemoryOperatingData; delete [] cacheMemoryOperatingData2; *hashes_done = collisions; return 0; }
bool CTxDB::LoadBlockIndex() { if (!LoadBlockIndexGuts()) return false; if (fRequestShutdown) return true; // Calculate bnChainTrust vector<pair<int, CBlockIndex*> > vSortedByHeight; vSortedByHeight.reserve(mapBlockIndex.size()); BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex) { CBlockIndex* pindex = item.second; vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex)); } sort(vSortedByHeight.begin(), vSortedByHeight.end()); BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight) { CBlockIndex* pindex = item.second; pindex->bnChainTrust = (pindex->pprev ? pindex->pprev->bnChainTrust : 0) + pindex->GetBlockTrust(); // ppcoin: calculate stake modifier checksum pindex->nStakeModifierChecksum = GetStakeModifierChecksum(pindex); if (!CheckStakeModifierCheckpoints(pindex->nHeight, pindex->nStakeModifierChecksum)) return error("CTxDB::LoadBlockIndex() : Failed stake modifier checkpoint height=%d, modifier=0x%016"PRI64x, pindex->nHeight, pindex->nStakeModifier); } // Load hashBestChain pointer to end of best chain if (!ReadHashBestChain(hashBestChain)) { if (pindexGenesisBlock == NULL) return true; return error("CTxDB::LoadBlockIndex() : hashBestChain not loaded"); } if (!mapBlockIndex.count(hashBestChain)) return error("CTxDB::LoadBlockIndex() : hashBestChain not found in the block index"); pindexBest = mapBlockIndex[hashBestChain]; nBestHeight = pindexBest->nHeight; bnBestChainTrust = pindexBest->bnChainTrust; printf("LoadBlockIndex(): hashBestChain=%s height=%d trust=%s date=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainTrust.ToString().c_str(), DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str()); // ppcoin: load hashSyncCheckpoint if (!ReadSyncCheckpoint(Checkpoints::hashSyncCheckpoint)) return error("CTxDB::LoadBlockIndex() : hashSyncCheckpoint not loaded"); printf("LoadBlockIndex(): synchronized checkpoint %s\n", Checkpoints::hashSyncCheckpoint.ToString().c_str()); // Load bnBestInvalidTrust, OK if it doesn't exist ReadBestInvalidTrust(bnBestInvalidTrust); // Verify blocks in the best chain int nCheckLevel = GetArg("-checklevel", 1); int nCheckDepth = GetArg( "-checkblocks", 2500); if (nCheckDepth == 0) nCheckDepth = 1000000000; // suffices until the year 19000 if (nCheckDepth > nBestHeight) nCheckDepth = nBestHeight; printf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel); CBlockIndex* pindexFork = NULL; map<pair<unsigned int, unsigned int>, CBlockIndex*> mapBlockPos; for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev) { if (fRequestShutdown || pindex->nHeight < nBestHeight-nCheckDepth) break; CBlock block; if (!block.ReadFromDisk(pindex)) return error("LoadBlockIndex() : block.ReadFromDisk failed"); // check level 1: verify block validity if (nCheckLevel>0 && !block.CheckBlock()) { printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); pindexFork = pindex->pprev; } // check level 2: verify transaction index validity if (nCheckLevel>1) { pair<unsigned int, unsigned int> pos = make_pair(pindex->nFile, pindex->nBlockPos); mapBlockPos[pos] = pindex; BOOST_FOREACH(const CTransaction &tx, block.vtx) { uint256 hashTx = tx.GetHash(); CTxIndex txindex; if (ReadTxIndex(hashTx, txindex)) { // check level 3: checker transaction hashes if (nCheckLevel>2 || pindex->nFile != txindex.pos.nFile || pindex->nBlockPos != txindex.pos.nBlockPos) { // either an error or a duplicate transaction CTransaction txFound; if (!txFound.ReadFromDisk(txindex.pos)) { printf("LoadBlockIndex() : *** cannot read mislocated transaction %s\n", hashTx.ToString().c_str()); pindexFork = pindex->pprev; } else if (txFound.GetHash() != hashTx) // not a duplicate tx { printf("LoadBlockIndex(): *** invalid tx position for %s\n", hashTx.ToString().c_str()); pindexFork = pindex->pprev; } } // check level 4: check whether spent txouts were spent within the main chain unsigned int nOutput = 0; if (nCheckLevel>3) { BOOST_FOREACH(const CDiskTxPos &txpos, txindex.vSpent) { if (!txpos.IsNull()) { pair<unsigned int, unsigned int> posFind = make_pair(txpos.nFile, txpos.nBlockPos); if (!mapBlockPos.count(posFind)) { printf("LoadBlockIndex(): *** found bad spend at %d, hashBlock=%s, hashTx=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str(), hashTx.ToString().c_str()); pindexFork = pindex->pprev; } // check level 6: check whether spent txouts were spent by a valid transaction that consume them if (nCheckLevel>5) { CTransaction txSpend; if (!txSpend.ReadFromDisk(txpos)) { printf("LoadBlockIndex(): *** cannot read spending transaction of %s:%i from disk\n", hashTx.ToString().c_str(), nOutput); pindexFork = pindex->pprev; } else if (!txSpend.CheckTransaction()) { printf("LoadBlockIndex(): *** spending transaction of %s:%i is invalid\n", hashTx.ToString().c_str(), nOutput); pindexFork = pindex->pprev; } else { bool fFound = false; BOOST_FOREACH(const CTxIn &txin, txSpend.vin) if (txin.prevout.hash == hashTx && txin.prevout.n == nOutput) fFound = true; if (!fFound) { printf("LoadBlockIndex(): *** spending transaction of %s:%i does not spend it\n", hashTx.ToString().c_str(), nOutput); pindexFork = pindex->pprev; } } } } nOutput++; } } }
UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, const uint32_t nMode = 0) { UniValue result(UniValue::VOBJ); result.push_back(Pair("hash", block.GetHash().GetHex())); int confirmations = -1; // Only report confirmations if the block is on the main chain if (chainActive.Contains(blockindex)) confirmations = chainActive.Height() - blockindex->nHeight + 1; result.push_back(Pair("confirmations", confirmations)); result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION))); result.push_back(Pair("height", blockindex->nHeight)); result.push_back(Pair("version", block.nVersion)); result.push_back(Pair("payload", blockindex->GetPayloadString())); result.push_back(Pair("payloadhash", blockindex->hashPayload.ToString())); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); result.push_back(Pair("time", block.GetBlockTime())); result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast())); result.push_back(Pair("creator", strprintf("0x%08x", blockindex->nCreatorId))); result.push_back(Pair("creatorSignature", block.creatorSignature.ToString())); result.push_back(Pair("nSignatures", (uint64_t)GetNumChainSigs(blockindex))); result.push_back(Pair("nAdminSignatures", (uint64_t)block.vAdminIds.size())); result.push_back(Pair("chainSignature", block.chainMultiSig.ToString())); result.push_back(Pair("adminMultiSig", block.adminMultiSig.IsNull() ? "" : block.adminMultiSig.ToString())); ///////// MISSING CHAIN SIGNERS UniValue missingSigners(UniValue::VARR); BOOST_FOREACH(const uint32_t& signerId, block.vMissingSignerIds) { missingSigners.push_back(strprintf("0x%08x", signerId)); } result.push_back(Pair("missingCreatorIds", missingSigners)); ///////// ADMIN SIGNERS UniValue adminSigners(UniValue::VARR); BOOST_FOREACH(const uint32_t& signerId, block.vAdminIds) { adminSigners.push_back(strprintf("0x%08x", signerId)); } result.push_back(Pair("adminSignerIds", adminSigners)); ///////// TRANSACTIONS UniValue txs(UniValue::VARR); BOOST_FOREACH(const CTransaction& tx, block.vtx) { if (nMode >= 5) { UniValue objTx(UniValue::VOBJ); TxToJSON(tx, uint256(), objTx); txs.push_back(objTx); } else txs.push_back(tx.GetHash().GetHex()); } result.push_back(Pair("tx", txs)); if (blockindex->pprev) result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); CBlockIndex *pnext = chainActive.Next(blockindex); if (pnext) result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex())); if (nMode < 2) return result; ///////// CVN INFO UniValue cvns(UniValue::VARR); BOOST_FOREACH(const CCvnInfo& cvn, block.vCvns) { UniValue objCvn(UniValue::VOBJ); objCvn.push_back(Pair("nodeId", strprintf("0x%08x", cvn.nNodeId))); objCvn.push_back(Pair("heightAdded", (int) cvn.nHeightAdded)); if (nMode >= 3) objCvn.push_back(Pair("pubKey", cvn.pubKey.ToString())); cvns.push_back(objCvn); } result.push_back(Pair("cvnInfo", cvns)); ///////// DYNAMIC CHAIN PARAMETERS UniValue dParams(UniValue::VOBJ); if (block.HasChainParameters()) { DynamicChainparametersToJSON(block.dynamicChainParams, dParams); } result.push_back(Pair("chainParameters", dParams)); ///////// ADMIN INFO UniValue admins(UniValue::VARR); BOOST_FOREACH(const CChainAdmin& admin, block.vChainAdmins) { UniValue objAdmin(UniValue::VOBJ); objAdmin.push_back(Pair("adminId", strprintf("0x%08x", admin.nAdminId))); objAdmin.push_back(Pair("heightAdded", (int) admin.nHeightAdded)); if (nMode >= 3) objAdmin.push_back(Pair("pubKey", admin.pubKey.ToString())); admins.push_back(objAdmin); } result.push_back(Pair("chainAdmins", admins)); ///////// COINS SUPPLY UniValue coinSupply(UniValue::VOBJ); if (block.HasCoinSupplyPayload()) { CoinSupplyToJSON(block.coinSupply, coinSupply); } result.push_back(Pair("coinSupply", coinSupply)); return result; }
std::string BlockToString(CBlockIndex* pBlock) { if (!pBlock) return ""; CBlock block; ReadBlockFromDisk(block, pBlock); CAmount Fees = 0; CAmount OutVolume = 0; CAmount Reward = 0; std::string TxLabels[] = {_("Hash"), _("From"), _("Amount"), _("To"), _("Amount")}; std::string TxContent = table + makeHTMLTableRow(TxLabels, sizeof(TxLabels) / sizeof(std::string)); for (unsigned int i = 0; i < block.vtx.size(); i++) { const CTransaction& tx = block.vtx[i]; TxContent += TxToRow(tx); CAmount In = getTxIn(tx); CAmount Out = tx.GetValueOut(); if (tx.IsCoinBase()) Reward += Out; else if (In < 0) Fees = -Params().MaxMoneyOut(); else { Fees += In - Out; OutVolume += Out; } } TxContent += "</table>"; CAmount Generated; if (pBlock->nHeight == 0) Generated = OutVolume; else Generated = GetBlockValue(pBlock->nHeight - 1); std::string BlockContentCells[] = { _("Height"), itostr(pBlock->nHeight), _("Size"), itostr(GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)), _("Number of Transactions"), itostr(block.vtx.size()), _("Value Out"), ValueToString(OutVolume), _("Fees"), ValueToString(Fees), _("Generated"), ValueToString(Generated), _("Timestamp"), TimeToString(block.nTime), _("Difficulty"), strprintf("%.4f", GetDifficulty(pBlock)), _("Bits"), utostr(block.nBits), _("Nonce"), utostr(block.nNonce), _("Version"), itostr(block.nVersion), _("Hash"), "<pre>" + block.GetHash().GetHex() + "</pre>", _("Merkle Root"), "<pre>" + block.hashMerkleRoot.GetHex() + "</pre>", // _("Hash Whole Block"), "<pre>" + block.hashWholeBlock.GetHex() + "</pre>" // _("Miner Signature"), "<pre>" + block.MinerSignature.ToString() + "</pre>" }; std::string BlockContent = makeHTMLTable(BlockContentCells, sizeof(BlockContentCells) / (2 * sizeof(std::string)), 2); std::string Content; Content += "<h2><a class=\"nav\" href="; Content += itostr(pBlock->nHeight - 1); Content += ">◄ </a>"; Content += _("Block"); Content += " "; Content += itostr(pBlock->nHeight); Content += "<a class=\"nav\" href="; Content += itostr(pBlock->nHeight + 1); Content += "> ►</a></h2>"; Content += BlockContent; Content += "</br>"; /* if (block.nHeight > getThirdHardforkBlock()) { std::vector<std::string> votes[2]; for (int i = 0; i < 2; i++) { for (unsigned int j = 0; j < block.vvotes[i].size(); j++) { votes[i].push_back(block.vvotes[i][j].hash.ToString() + ':' + itostr(block.vvotes[i][j].n)); } } Content += "<h3>" + _("Votes +") + "</h3>"; Content += makeHTMLTable(&votes[1][0], votes[1].size(), 1); Content += "</br>"; Content += "<h3>" + _("Votes -") + "</h3>"; Content += makeHTMLTable(&votes[0][0], votes[0].size(), 1); Content += "</br>"; } */ Content += "<h2>" + _("Transactions") + "</h2>"; Content += TxContent; return Content; }
virtual void BlockChecked(const CBlock& block, const CValidationState& stateIn) { if (block.GetHash() != hash) return; found = true; state = stateIn; };
Value scaninput(const Array& params, bool fHelp) { if (fHelp || params.size() > 4 || params.size() < 2) throw runtime_error( "scaninput <txid> <nout> [difficulty] [days]\n" "Scan specified input for suitable kernel solutions.\n" " [difficulty] - upper limit for difficulty, current difficulty by default;\n" " [days] - time window, 365 days by default.\n" ); uint256 hash; hash.SetHex(params[0].get_str()); uint32_t nOut = params[1].get_int(), nBits = GetNextTargetRequired(pindexBest, true), nDays = 365; if (params.size() > 2) { CBigNum bnTarget(nPoWBase); bnTarget *= 1000; bnTarget /= (int) (params[2].get_real() * 1000); nBits = bnTarget.GetCompact(); } if (params.size() > 3) { nDays = params[3].get_int(); } CTransaction tx; uint256 hashBlock = 0; if (GetTransaction(hash, tx, hashBlock)) { if (nOut > tx.vout.size()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Incorrect output number"); if (hashBlock == 0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to find transaction in the blockchain"); CTxDB txdb("r"); CBlock block; CTxIndex txindex; // Load transaction index item if (!txdb.ReadTxIndex(tx.GetHash(), txindex)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to read block index item"); // Read block header if (!block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "CBlock::ReadFromDisk() failed"); uint64_t nStakeModifier = 0; if (!GetKernelStakeModifier(block.GetHash(), nStakeModifier)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No kernel stake modifier generated yet"); std::pair<uint32_t, uint32_t> interval; interval.first = GetTime(); // Only count coins meeting min age requirement if (nStakeMinAge + block.nTime > interval.first) interval.first += (nStakeMinAge + block.nTime - interval.first); interval.second = interval.first + nDays * 86400; SHA256_CTX ctx; GetKernelMidstate(nStakeModifier, block.nTime, txindex.pos.nTxPos - txindex.pos.nBlockPos, tx.nTime, nOut, ctx); std::pair<uint256, uint32_t> solution; if (ScanMidstateForward(ctx, nBits, tx.nTime, tx.vout[nOut].nValue, interval, solution)) { Object r; r.push_back(Pair("hash", solution.first.GetHex())); r.push_back(Pair("time", DateTimeStrFormat(solution.second))); return r; } } else throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); return Value::null; }
UniValue getblocktemplate(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() > 1) throw std::runtime_error( "getblocktemplate ( TemplateRequest )\n" "\nIf the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'.\n" "It returns data needed to construct a block to work on.\n" "For full specification, see BIPs 22, 23, 9, and 145:\n" " https://github.com/bitcoin/bips/blob/master/bip-0022.mediawiki\n" " https://github.com/bitcoin/bips/blob/master/bip-0023.mediawiki\n" " https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki#getblocktemplate_changes\n" " https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki\n" "\nArguments:\n" "1. template_request (json object, optional) A json object in the following spec\n" " {\n" " \"mode\":\"template\" (string, optional) This must be set to \"template\", \"proposal\" (see BIP 23), or omitted\n" " \"capabilities\":[ (array, optional) A list of strings\n" " \"support\" (string) client side supported feature, 'longpoll', 'coinbasetxn', 'coinbasevalue', 'proposal', 'serverlist', 'workid'\n" " ,...\n" " ],\n" " \"rules\":[ (array, optional) A list of strings\n" " \"support\" (string) client side supported softfork deployment\n" " ,...\n" " ]\n" " }\n" "\n" "\nResult:\n" "{\n" " \"version\" : n, (numeric) The preferred block version\n" " \"rules\" : [ \"rulename\", ... ], (array of strings) specific block rules that are to be enforced\n" " \"vbavailable\" : { (json object) set of pending, supported versionbit (BIP 9) softfork deployments\n" " \"rulename\" : bitnumber (numeric) identifies the bit number as indicating acceptance and readiness for the named softfork rule\n" " ,...\n" " },\n" " \"vbrequired\" : n, (numeric) bit mask of versionbits the server requires set in submissions\n" " \"previousblockhash\" : \"xxxx\", (string) The hash of current highest block\n" " \"transactions\" : [ (array) contents of non-coinbase transactions that should be included in the next block\n" " {\n" " \"data\" : \"xxxx\", (string) transaction data encoded in hexadecimal (byte-for-byte)\n" " \"txid\" : \"xxxx\", (string) transaction id encoded in little-endian hexadecimal\n" " \"hash\" : \"xxxx\", (string) hash encoded in little-endian hexadecimal (including witness data)\n" " \"depends\" : [ (array) array of numbers \n" " n (numeric) transactions before this one (by 1-based index in 'transactions' list) that must be present in the final block if this one is\n" " ,...\n" " ],\n" " \"fee\": n, (numeric) difference in value between transaction inputs and outputs (in Satoshis); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one\n" " \"sigops\" : n, (numeric) total SigOps cost, as counted for purposes of block limits; if key is not present, sigop cost is unknown and clients MUST NOT assume it is zero\n" " \"weight\" : n, (numeric) total transaction weight, as counted for purposes of block limits\n" " \"required\" : true|false (boolean) if provided and true, this transaction must be in the final block\n" " }\n" " ,...\n" " ],\n" " \"coinbaseaux\" : { (json object) data that should be included in the coinbase's scriptSig content\n" " \"flags\" : \"xx\" (string) key name is to be ignored, and value included in scriptSig\n" " },\n" " \"coinbasevalue\" : n, (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in Satoshis)\n" " \"coinbasetxn\" : { ... }, (json object) information for coinbase transaction\n" " \"target\" : \"xxxx\", (string) The hash target\n" " \"mintime\" : xxx, (numeric) The minimum timestamp appropriate for next block time in seconds since epoch (Jan 1 1970 GMT)\n" " \"mutable\" : [ (array of string) list of ways the block template may be changed \n" " \"value\" (string) A way the block template may be changed, e.g. 'time', 'transactions', 'prevblock'\n" " ,...\n" " ],\n" " \"noncerange\" : \"00000000ffffffff\",(string) A range of valid nonces\n" " \"sigoplimit\" : n, (numeric) limit of sigops in blocks\n" " \"sizelimit\" : n, (numeric) limit of block size\n" " \"weightlimit\" : n, (numeric) limit of block weight\n" " \"curtime\" : ttt, (numeric) current timestamp in seconds since epoch (Jan 1 1970 GMT)\n" " \"bits\" : \"xxxxxxxx\", (string) compressed target of next block\n" " \"height\" : n (numeric) The height of the next block\n" "}\n" "\nExamples:\n" + HelpExampleCli("getblocktemplate", "") + HelpExampleRpc("getblocktemplate", "") ); LOCK(cs_main); std::string strMode = "template"; UniValue lpval = NullUniValue; std::set<std::string> setClientRules; int64_t nMaxVersionPreVB = -1; if (!request.params[0].isNull()) { const UniValue& oparam = request.params[0].get_obj(); const UniValue& modeval = find_value(oparam, "mode"); if (modeval.isStr()) strMode = modeval.get_str(); else if (modeval.isNull()) { /* Do nothing */ } else throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); lpval = find_value(oparam, "longpollid"); if (strMode == "proposal") { const UniValue& dataval = find_value(oparam, "data"); if (!dataval.isStr()) throw JSONRPCError(RPC_TYPE_ERROR, "Missing data String key for proposal"); CBlock block; if (!DecodeHexBlk(block, dataval.get_str())) throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed"); uint256 hash = block.GetHash(); BlockMap::iterator mi = mapBlockIndex.find(hash); if (mi != mapBlockIndex.end()) { CBlockIndex *pindex = mi->second; if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) return "duplicate"; if (pindex->nStatus & BLOCK_FAILED_MASK) return "duplicate-invalid"; return "duplicate-inconclusive"; } CBlockIndex* const pindexPrev = chainActive.Tip(); // TestBlockValidity only supports blocks built on the current Tip if (block.hashPrevBlock != pindexPrev->GetBlockHash()) return "inconclusive-not-best-prevblk"; CValidationState state; TestBlockValidity(state, Params(), block, pindexPrev, false, true); return BIP22ValidationResult(state); } const UniValue& aClientRules = find_value(oparam, "rules"); if (aClientRules.isArray()) { for (unsigned int i = 0; i < aClientRules.size(); ++i) { const UniValue& v = aClientRules[i]; setClientRules.insert(v.get_str()); } } else { // NOTE: It is important that this NOT be read if versionbits is supported const UniValue& uvMaxVersion = find_value(oparam, "maxversion"); if (uvMaxVersion.isNum()) { nMaxVersionPreVB = uvMaxVersion.get_int64(); } } } if (strMode != "template") throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); if(!g_connman) throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); if (g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0) throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Litecoin is not connected!"); if (IsInitialBlockDownload()) throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Litecoin is downloading blocks..."); static unsigned int nTransactionsUpdatedLast; if (!lpval.isNull()) { // Wait to respond until either the best block changes, OR a minute has passed and there are more transactions uint256 hashWatchedChain; boost::system_time checktxtime; unsigned int nTransactionsUpdatedLastLP; if (lpval.isStr()) { // Format: <hashBestChain><nTransactionsUpdatedLast> std::string lpstr = lpval.get_str(); hashWatchedChain.SetHex(lpstr.substr(0, 64)); nTransactionsUpdatedLastLP = atoi64(lpstr.substr(64)); } else { // NOTE: Spec does not specify behaviour for non-string longpollid, but this makes testing easier hashWatchedChain = chainActive.Tip()->GetBlockHash(); nTransactionsUpdatedLastLP = nTransactionsUpdatedLast; } // Release the wallet and main lock while waiting LEAVE_CRITICAL_SECTION(cs_main); { checktxtime = boost::get_system_time() + boost::posix_time::minutes(1); boost::unique_lock<boost::mutex> lock(csBestBlock); while (chainActive.Tip()->GetBlockHash() == hashWatchedChain && IsRPCRunning()) { if (!cvBlockChange.timed_wait(lock, checktxtime)) { // Timeout: Check transactions for update if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLastLP) break; checktxtime += boost::posix_time::seconds(10); } } } ENTER_CRITICAL_SECTION(cs_main); if (!IsRPCRunning()) throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down"); // TODO: Maybe recheck connections/IBD and (if something wrong) send an expires-immediately template to stop miners? } const struct VBDeploymentInfo& segwit_info = VersionBitsDeploymentInfo[Consensus::DEPLOYMENT_SEGWIT]; // If the caller is indicating segwit support, then allow CreateNewBlock() // to select witness transactions, after segwit activates (otherwise // don't). bool fSupportsSegwit = setClientRules.find(segwit_info.name) != setClientRules.end(); // Update block static CBlockIndex* pindexPrev; static int64_t nStart; static std::unique_ptr<CBlockTemplate> pblocktemplate; // Cache whether the last invocation was with segwit support, to avoid returning // a segwit-block to a non-segwit caller. static bool fLastTemplateSupportsSegwit = true; if (pindexPrev != chainActive.Tip() || (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5) || fLastTemplateSupportsSegwit != fSupportsSegwit) { // Clear pindexPrev so future calls make a new block, despite any failures from here on pindexPrev = nullptr; // Store the pindexBest used before CreateNewBlock, to avoid races nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); CBlockIndex* pindexPrevNew = chainActive.Tip(); nStart = GetTime(); fLastTemplateSupportsSegwit = fSupportsSegwit; // Create new block CScript scriptDummy = CScript() << OP_TRUE; pblocktemplate = BlockAssembler(Params()).CreateNewBlock(scriptDummy, fSupportsSegwit); if (!pblocktemplate) throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); // Need to update only after we know CreateNewBlock succeeded pindexPrev = pindexPrevNew; } CBlock* pblock = &pblocktemplate->block; // pointer for convenience const Consensus::Params& consensusParams = Params().GetConsensus(); // Update nTime UpdateTime(pblock, consensusParams, pindexPrev); pblock->nNonce = 0; // NOTE: If at some point we support pre-segwit miners post-segwit-activation, this needs to take segwit support into consideration const bool fPreSegWit = (THRESHOLD_ACTIVE != VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_SEGWIT, versionbitscache)); UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal"); UniValue transactions(UniValue::VARR); std::map<uint256, int64_t> setTxIndex; int i = 0; for (const auto& it : pblock->vtx) { const CTransaction& tx = *it; uint256 txHash = tx.GetHash(); setTxIndex[txHash] = i++; if (tx.IsCoinBase()) continue; UniValue entry(UniValue::VOBJ); entry.push_back(Pair("data", EncodeHexTx(tx))); entry.push_back(Pair("txid", txHash.GetHex())); entry.push_back(Pair("hash", tx.GetWitnessHash().GetHex())); UniValue deps(UniValue::VARR); for (const CTxIn &in : tx.vin) { if (setTxIndex.count(in.prevout.hash)) deps.push_back(setTxIndex[in.prevout.hash]); } entry.push_back(Pair("depends", deps)); int index_in_template = i - 1; entry.push_back(Pair("fee", pblocktemplate->vTxFees[index_in_template])); int64_t nTxSigOps = pblocktemplate->vTxSigOpsCost[index_in_template]; if (fPreSegWit) { assert(nTxSigOps % WITNESS_SCALE_FACTOR == 0); nTxSigOps /= WITNESS_SCALE_FACTOR; } entry.push_back(Pair("sigops", nTxSigOps)); entry.push_back(Pair("weight", GetTransactionWeight(tx))); transactions.push_back(entry); } UniValue aux(UniValue::VOBJ); aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end()))); arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits); UniValue aMutable(UniValue::VARR); aMutable.push_back("time"); aMutable.push_back("transactions"); aMutable.push_back("prevblock"); UniValue result(UniValue::VOBJ); result.push_back(Pair("capabilities", aCaps)); UniValue aRules(UniValue::VARR); UniValue vbavailable(UniValue::VOBJ); for (int j = 0; j < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++j) { Consensus::DeploymentPos pos = Consensus::DeploymentPos(j); ThresholdState state = VersionBitsState(pindexPrev, consensusParams, pos, versionbitscache); switch (state) { case THRESHOLD_DEFINED: case THRESHOLD_FAILED: // Not exposed to GBT at all break; case THRESHOLD_LOCKED_IN: // Ensure bit is set in block version pblock->nVersion |= VersionBitsMask(consensusParams, pos); // FALL THROUGH to get vbavailable set... case THRESHOLD_STARTED: { const struct VBDeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos]; vbavailable.push_back(Pair(gbt_vb_name(pos), consensusParams.vDeployments[pos].bit)); if (setClientRules.find(vbinfo.name) == setClientRules.end()) { if (!vbinfo.gbt_force) { // If the client doesn't support this, don't indicate it in the [default] version pblock->nVersion &= ~VersionBitsMask(consensusParams, pos); } } break; } case THRESHOLD_ACTIVE: { // Add to rules only const struct VBDeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos]; aRules.push_back(gbt_vb_name(pos)); if (setClientRules.find(vbinfo.name) == setClientRules.end()) { // Not supported by the client; make sure it's safe to proceed if (!vbinfo.gbt_force) { // If we do anything other than throw an exception here, be sure version/force isn't sent to old clients throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Support for '%s' rule requires explicit client support", vbinfo.name)); } } break; } } } result.push_back(Pair("version", pblock->nVersion)); result.push_back(Pair("rules", aRules)); result.push_back(Pair("vbavailable", vbavailable)); result.push_back(Pair("vbrequired", int(0))); if (nMaxVersionPreVB >= 2) { // If VB is supported by the client, nMaxVersionPreVB is -1, so we won't get here // Because BIP 34 changed how the generation transaction is serialized, we can only use version/force back to v2 blocks // This is safe to do [otherwise-]unconditionally only because we are throwing an exception above if a non-force deployment gets activated // Note that this can probably also be removed entirely after the first BIP9 non-force deployment (ie, probably segwit) gets activated aMutable.push_back("version/force"); } result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex())); result.push_back(Pair("transactions", transactions)); result.push_back(Pair("coinbaseaux", aux)); result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0]->vout[0].nValue)); result.push_back(Pair("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast))); result.push_back(Pair("target", hashTarget.GetHex())); result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1)); result.push_back(Pair("mutable", aMutable)); result.push_back(Pair("noncerange", "00000000ffffffff")); int64_t nSigOpLimit = MAX_BLOCK_SIGOPS_COST; int64_t nSizeLimit = MAX_BLOCK_SERIALIZED_SIZE; if (fPreSegWit) { assert(nSigOpLimit % WITNESS_SCALE_FACTOR == 0); nSigOpLimit /= WITNESS_SCALE_FACTOR; assert(nSizeLimit % WITNESS_SCALE_FACTOR == 0); nSizeLimit /= WITNESS_SCALE_FACTOR; } result.push_back(Pair("sigoplimit", nSigOpLimit)); result.push_back(Pair("sizelimit", nSizeLimit)); if (!fPreSegWit) { result.push_back(Pair("weightlimit", (int64_t)MAX_BLOCK_WEIGHT)); } result.push_back(Pair("curtime", pblock->GetBlockTime())); result.push_back(Pair("bits", strprintf("%08x", pblock->nBits))); result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1))); if (!pblocktemplate->vchCoinbaseCommitment.empty() && fSupportsSegwit) { result.push_back(Pair("default_witness_commitment", HexStr(pblocktemplate->vchCoinbaseCommitment.begin(), pblocktemplate->vchCoinbaseCommitment.end()))); } return result; }
bool CRenderManager::update() { glColor3f(1.0f,1.0f,1.0f); // get camera CCamera *camera = CV_GAME_MANAGER->getControlManager()->getCamera(); // transform view camera->transformView(); // Draw the map and items that fall into view frustum. // 1. extract approximate logical location of camera in the level map. vector2i center = CConversions::realToLogical(camera->getPosition()); GLint centerX = center[0]; GLint centerY = center[1]; bool isFPS = CV_GAME_MANAGER->getControlManager()->isFPS(); if (isFPS) { // fog only in FPS mode glEnable(GL_FOG); } /* In FPS mode we can't use height to determine visible offset. We have to use some extent read from config (CV_CAMERA_FPS_EXTENT). */ GLint diff = (GLint)(isFPS?cameraFPSExtent:camera->getPosition()[1]*10.0f); // 2. create a bounding square making its center logical position calculate above. GLint minX = (centerX-diff>=0?centerX-diff:0); GLint minY = (centerY-diff>=0?centerY-diff:0); GLint maxX = (centerX+diff<(GLint)CV_LEVEL_MAP_SIZE?centerX+diff:CV_LEVEL_MAP_SIZE-1); GLint maxY = (centerY+diff<(GLint)CV_LEVEL_MAP_SIZE?centerY+diff:CV_LEVEL_MAP_SIZE-1); // 3. go through all block that fall into this bounding square and check if they fall // int out view frustum. If not then just exclude them. CBlock *block; GLint blockVisible = 0, allVerticesCount = 0, creaturesVisible = 0, maxVertInput = 0, maxTexInput = 0; tmpVboVertexBufferSize = 0; tmpVboTexCoordBufferSize = 0; vector3f vertA, vertB, vertC; GLfloat **verts, *texCoords; CLevelManager *lManager = CV_GAME_MANAGER->getLevelManager(); CAnimatedTerrainManager *atManager = CV_GAME_MANAGER->getAnimatedTerrainManager(); CFrustum *frustum = CV_GAME_MANAGER->getControlManager()->getViewFrustum(); bool lavaWater = false; GLfloat delta = CV_GAME_MANAGER->getDeltaTime(); renderedBlocks.clear(); for (GLint y=minY; y<=maxY; y++) { for (GLint x=minX; x<=maxX; x++) { block = lManager->getBlock(x,y); if (block) { //block->getBoundingBox()->draw(); // just for testing if (frustum->containsBBOX(block->getBoundingBox())) { blockVisible++; block->updateTexture(delta); lavaWater = (block->isLava() || block->isWater()); if (lavaWater) { atManager->updateBlock(block); } renderedBlocks.push_back(block); // draw block objects if (block->getBlockObjects()->size()>0) { for (std::vector<CBlockObject*>::iterator rmIter = block->getBlockObjects()->begin(); rmIter != block->getBlockObjects()->end(); rmIter++) { CBlockObject *bObj = *rmIter; bObj->moveTo(); glRotatef(bObj->getRotateY(),0.0f,1.0f,0.0f); bObj->drawModel(delta); glRotatef(-bObj->getRotateY(),0.0f,1.0f,0.0f); bObj->moveBack(); } } bool isRoom = block->isRoom(); if (isRoom) { std::vector<GLuint> *dls = block->getDisplayLists(); if (dls->size()!=0) { glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,textureAtlasColor); glBegin(GL_QUADS); { for (std::vector<GLuint>::iterator dlIter = dls->begin(); dlIter != dls->end(); dlIter++) { glCallList(*dlIter); } } glEnd(); glDisable(GL_TEXTURE_2D); } } for (GLint f=CBlock::BFS_FRONT; f<=CBlock::BFS_CEILING; f++) { if ((!isFPS && f==CBlock::BFS_CEILING) || (isFPS && f==CBlock::BFS_TOP) || (isRoom && f!=CBlock::BFS_CEILING)) { continue; } if (block->isFaceVisible((CBlock::BLOCK_FACE_SELECTOR)f)) { verts = block->getVertices(); texCoords = block->getTextureCoordinates((CBlock::BLOCK_FACE_SELECTOR)f); if (lavaWater && f<=CBlock::BFS_RIGHT) { /* Lava and water have only lowers row of wall sections drawn. If they are drawn at all. */ maxVertInput = CV_FBLR_W_L_FACE_VERT_FLOATS; maxTexInput = CV_FBLR_W_L_FACE_TEX_FLOATS; } else { maxVertInput = f>=CBlock::BFS_TOP?CV_TBWLC_FACE_VERT_FLOATS:CV_FBLR_FACE_VERT_FLOATS; maxTexInput = f>=CBlock::BFS_TOP?CV_TBWLC_FACE_TEX_FLOATS:CV_FBLR_FACE_TEX_FLOATS; } if (tmpVboVertexBufferSize+maxVertInput>CV_MAX_VERTEX_BUFFER*3) { vbo->setElementsCount(CVBO::IDT_vertex,tmpVboVertexBufferSize/3); vbo->setElementsCount(CVBO::IDT_texture0,tmpVboTexCoordBufferSize/2); vbo->setElementsCount(CVBO::IDT_texture1,tmpVboTexCoordBufferSize/2); vbo->draw(); allVerticesCount+=tmpVboVertexBufferSize; tmpVboVertexBufferSize=0; tmpVboTexCoordBufferSize=0; } memcpy(tmpVboVertexBuffer+tmpVboVertexBufferSize, verts[f], sizeof(GLfloat)*maxVertInput); tmpVboVertexBufferSize+=maxVertInput; memcpy(tmpVboTexCoordBuffer+tmpVboTexCoordBufferSize, texCoords, sizeof(GLfloat)*maxTexInput); tmpVboTexCoordBufferSize+=maxTexInput; } } } } } } if (tmpVboVertexBufferSize>0) { vbo->setElementsCount(CVBO::IDT_vertex,tmpVboVertexBufferSize/3); vbo->setElementsCount(CVBO::IDT_texture0,tmpVboTexCoordBufferSize/2); vbo->setElementsCount(CVBO::IDT_texture1,tmpVboTexCoordBufferSize/2); vbo->draw(); allVerticesCount+=tmpVboVertexBufferSize; } // draw creatures CCreatureManager *cManager = CV_GAME_MANAGER->getCreatureManager(); GLint cCount = cManager->getCreatureVector()->size(); if (cCount>0) { CCreature *creature = NULL; for (std::vector<CCreature*>::iterator cIter = cManager->getCreatureVector()->begin(); cIter != cManager->getCreatureVector()->end(); cIter++) { creature = (*cIter); if (creature) { sBoundingBox *cBBOX = creature->getModel()->getBoundingBox(); cBBOX->translate(creature->getPosition()); if (frustum->containsBBOX(cBBOX)) { creature->draw(delta); creaturesVisible++; } cBBOX->translate(-creature->getPosition()); } } } // draw transparent block objects for (std::vector<CBlock*>::iterator vbIter = renderedBlocks.begin(); vbIter != renderedBlocks.end(); vbIter++) { block = *vbIter; if (block->getBlockObjects()->size()>0) { for (std::vector<CBlockObject*>::iterator rmIter = block->getBlockObjects()->begin(); rmIter != block->getBlockObjects()->end(); rmIter++) { CBlockObject *bObj = *rmIter; bObj->moveTo(); glRotatef(bObj->getRotateY(),0.0f,1.0f,0.0f); bObj->drawEffect(); glRotatef(-bObj->getRotateY(),0.0f,1.0f,0.0f); bObj->moveBack(); } } } glDisable(GL_FOG); if (!isFPS) { handlePickedObjects(); } CV_GAME_MANAGER->getTextPrinter()->print((GLfloat)0,(GLfloat)(CV_SETTINGS_WINDOW_HEIGHT-15*3),"Visible blocks: %d",blockVisible); CV_GAME_MANAGER->getTextPrinter()->print((GLfloat)0,(GLfloat)(CV_SETTINGS_WINDOW_HEIGHT-15*2),"Visible creatures: %d",creaturesVisible); CV_GAME_MANAGER->getTextPrinter()->print((GLfloat)0,(GLfloat)(CV_SETTINGS_WINDOW_HEIGHT-15),"Triangles drawn: %d",(allVerticesCount/4)*2); // render the lights representations. usefull for debugging CV_GAME_MANAGER->getLightingManager()->drawLightSources(frustum); return true; }
GLvoid CRenderManager::handlePickedObjects() { // if we are ower the menu we do not have to proccess things under the cursor if (CV_GAME_MANAGER->getGUIManager()->getPlayGUI()->is_mouse_over_gui()) { return; } // if we are not selling or buying we don't have to process blocks (just objects TODO) ACTION_EVENT *ae = CV_GAME_MANAGER->getGUIManager()->getLastActionEvent(); // get the block we have our cousor on CBlock *pickedBlock = CV_GAME_MANAGER->getPickingManager()->getLastPickedBlock(); if (pickedBlock) { GLint type = pickedBlock->getType(); /*if (!pickedBlock->isSellable()) { return; }*/ sBoundingBox *bbox = pickedBlock->getBoundingBox(); vector3f a(bbox->A); vector3f b(bbox->B); vector3f c(bbox->C); vector3f d(bbox->D); vector3f e(bbox->E); vector3f f(bbox->F); vector3f g(bbox->G); vector3f h(bbox->H); a[1]=b[1]=c[1]=d[1]=CV_BLOCK_HEIGHT+CV_BLOCK_HEIGHT/4.0f+CV_BLOCK_HEIGHT/32.0f; e[1]=f[1]=g[1]=h[1]=CV_BLOCK_HEIGHT/4.0f+CV_BLOCK_HEIGHT/32.0f; glLineWidth(4.0f); if (pickedBlock->isLow()) { if (!(ae->message_group==AEMG_BUILD_ROOMS || ae->message_group==AEMG_BUILD_DOORS || ae->message_group==AEMG_BUILD_TRAPS)) { return; } // draw the selection box if (pickedBlock->isSellable(CV_CURRENT_PLAYER_ID) && ae->message == AEM_SELL) { glColor3f(0.0f,1.0f,0.0f); } else if (pickedBlock->isBuildable(CV_CURRENT_PLAYER_ID) && ae->message != AEM_SELL) { glColor3f(0.0f,1.0f,0.0f); } else { glColor3f(1.0f,0.0f,0.0f); } glBegin(GL_LINES); { /*glVertex3fv(&a[0]); glVertex3fv(&b[0]); glVertex3fv(&b[0]); glVertex3fv(&c[0]); glVertex3fv(&c[0]); glVertex3fv(&d[0]); glVertex3fv(&d[0]); glVertex3fv(&a[0]);*/ glVertex3fv(&e[0]); glVertex3fv(&f[0]); glVertex3fv(&f[0]); glVertex3fv(&g[0]); glVertex3fv(&g[0]); glVertex3fv(&h[0]); glVertex3fv(&h[0]); glVertex3fv(&e[0]); /*glVertex3fv(&a[0]); glVertex3fv(&e[0]); glVertex3fv(&b[0]); glVertex3fv(&f[0]); glVertex3fv(&c[0]); glVertex3fv(&g[0]); glVertex3fv(&d[0]); glVertex3fv(&h[0]);*/ } glEnd(); } else { if (!(ae->message_group==AEMG_BUILD_ROOMS || ae->message_group==AEMG_BUILD_DOORS || ae->message_group==AEMG_BUILD_TRAPS)) glColor3f(type==CV_BLOCK_TYPE_ROCK_ID?1.0f:0.0f,type==CV_BLOCK_TYPE_ROCK_ID?0.0f:1.0f,0.0f); else glColor3f(1.0f,0.0f,0.0f); glBegin(GL_LINES); { glVertex3fv(&a[0]); glVertex3fv(&b[0]); glVertex3fv(&b[0]); glVertex3fv(&c[0]); glVertex3fv(&c[0]); glVertex3fv(&d[0]); glVertex3fv(&d[0]); glVertex3fv(&a[0]); glVertex3fv(&e[0]); glVertex3fv(&f[0]); glVertex3fv(&f[0]); glVertex3fv(&g[0]); glVertex3fv(&g[0]); glVertex3fv(&h[0]); glVertex3fv(&h[0]); glVertex3fv(&e[0]); glVertex3fv(&a[0]); glVertex3fv(&e[0]); glVertex3fv(&b[0]); glVertex3fv(&f[0]); glVertex3fv(&c[0]); glVertex3fv(&g[0]); glVertex3fv(&d[0]); glVertex3fv(&h[0]); } glEnd(); } glLineWidth(1.0f); } }
// note new return type, this now returns the bad block number, else 0 for success. // // I also return -ve block numbers for errors between blocks. Eg if you read 3 good blocks, then find an unexpected // float in the script between blocks 3 & 4 then I return -3 to indicate the error is after that, but not block 4 // int CInterpreter::Interpret( CTokenizer *Tokenizer, CBlockStream *BlockStream, char *filename ) { CBlock block; CToken *token; int type, blockLevel = 0, parenthesisLevel = 0; m_sCurrentFile = filename; // used during error reporting because you can't ask tokenizer for pushed streams m_tokenizer = Tokenizer; m_blockStream = BlockStream; m_iCurrentLine = m_tokenizer->GetCurLine(); token = m_tokenizer->GetToEndOfLine(TK_STRING); m_sCurrentLine = token->GetStringValue(); m_tokenizer->PutBackToken(token, false, NULL, true); m_iBadCBlockNumber = 0; while (m_tokenizer->GetRemainingSize() > 0) { token = m_tokenizer->GetToken( TKF_USES_EOL, 0 ); type = token->GetType(); switch ( type ) { case TK_UNDEFINED: token->Delete(); m_iBadCBlockNumber = -m_iBadCBlockNumber; Error("%d : undefined token", type); return m_iBadCBlockNumber; break; case TK_EOF: break; case TK_EOL: // read the next line, then put it back token->Delete(); m_iCurrentLine = m_tokenizer->GetCurLine(); token = m_tokenizer->GetToEndOfLine(TK_STRING); m_sCurrentLine = token->GetStringValue(); m_tokenizer->PutBackToken(token, false, NULL, true); break; case TK_CHAR: case TK_STRING: token->Delete(); m_iBadCBlockNumber = -m_iBadCBlockNumber; Error("syntax error : unexpected string"); return m_iBadCBlockNumber; break; case TK_INT: token->Delete(); m_iBadCBlockNumber = -m_iBadCBlockNumber; Error("syntax error : unexpected integer"); return m_iBadCBlockNumber; break; case TK_FLOAT: token->Delete(); m_iBadCBlockNumber = -m_iBadCBlockNumber; Error("syntax error : unexpected float"); return m_iBadCBlockNumber; break; case TK_IDENTIFIER: m_iBadCBlockNumber++; if (!GetID( (char *) token->GetStringValue() )) { token->Delete(); return m_iBadCBlockNumber; } token->Delete(); break; case TK_BLOCK_START: token->Delete(); if (parenthesisLevel) { m_iBadCBlockNumber = -m_iBadCBlockNumber; Error("syntax error : brace inside parenthesis"); return m_iBadCBlockNumber; } blockLevel++; break; case TK_BLOCK_END: token->Delete(); if (parenthesisLevel) { m_iBadCBlockNumber = -m_iBadCBlockNumber; Error("syntax error : brace inside parenthesis"); return m_iBadCBlockNumber; } block.Create( ID_BLOCK_END ); m_blockStream->WriteBlock( &block ); block.Free(); blockLevel--; break; case TK_OPEN_PARENTHESIS: token->Delete(); blockLevel++; parenthesisLevel++; break; case TK_CLOSED_PARENTHESIS: token->Delete(); blockLevel--; parenthesisLevel--; if (parenthesisLevel<0) { m_iBadCBlockNumber = -m_iBadCBlockNumber; Error("syntax error : closed parenthesis with no opening match"); return m_iBadCBlockNumber; } break; case TK_VECTOR_START: token->Delete(); m_iBadCBlockNumber = -m_iBadCBlockNumber; Error("syntax error : unexpected vector"); return m_iBadCBlockNumber; break; case TK_VECTOR_END: token->Delete(); m_iBadCBlockNumber = -m_iBadCBlockNumber; Error("syntax error : unexpected vector"); return m_iBadCBlockNumber; break; } } if ( blockLevel ) { m_iBadCBlockNumber = -m_iBadCBlockNumber; Error("error : open brace was not closed"); return m_iBadCBlockNumber; } if ( parenthesisLevel ) { m_iBadCBlockNumber = -m_iBadCBlockNumber; Error("error: open parenthesis"); return m_iBadCBlockNumber; } //Release all the variable information, because it's already been written out FreeVars(); m_iBadCBlockNumber = 0; return m_iBadCBlockNumber; //true; }
bool CreateCoinStake( CBlock &blocknew, CKey &key, vector<const CWalletTx*> &StakeInputs, uint64_t &CoinAge, CWallet &wallet, CBlockIndex* pindexPrev ) { int64_t CoinWeight; CBigNum StakeKernelHash; CTxDB txdb("r"); int64_t StakeWeightSum = 0; double StakeValueSum = 0; int64_t StakeWeightMin=MAX_MONEY; int64_t StakeWeightMax=0; uint64_t StakeCoinAgeSum=0; double StakeDiffSum = 0; double StakeDiffMax = 0; CTransaction &txnew = blocknew.vtx[1]; // second tx is coinstake //initialize the transaction txnew.nTime = blocknew.nTime & (~STAKE_TIMESTAMP_MASK); txnew.vin.clear(); txnew.vout.clear(); // Choose coins to use set <pair <const CWalletTx*,unsigned int> > CoinsToStake; int64_t BalanceToStake = wallet.GetBalance(); int64_t nValueIn = 0; //Request all the coins here, check reserve later if ( BalanceToStake<=0 || !wallet.SelectCoinsForStaking(BalanceToStake*2, txnew.nTime, CoinsToStake, nValueIn) ) { LOCK(MinerStatus.lock); MinerStatus.ReasonNotStaking+=_("No coins; "); if (fDebug) LogPrintf("CreateCoinStake: %s",MinerStatus.ReasonNotStaking); return false; } BalanceToStake -= nReserveBalance; if(fDebug2) LogPrintf("\nCreateCoinStake: Staking nTime/16= %d Bits= %u", txnew.nTime/16,blocknew.nBits); for(const auto& pcoin : CoinsToStake) { const CTransaction &CoinTx =*pcoin.first; //transaction that produced this coin unsigned int CoinTxN =pcoin.second; //index of this coin inside it CTxIndex txindex; { LOCK2(cs_main, wallet.cs_wallet); if (!txdb.ReadTxIndex(pcoin.first->GetHash(), txindex)) continue; //error? } CBlock CoinBlock; //Block which contains CoinTx { LOCK2(cs_main, wallet.cs_wallet); if (!CoinBlock.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false)) continue; } // only count coins meeting min age requirement if (CoinBlock.GetBlockTime() + nStakeMinAge > txnew.nTime) continue; if (CoinTx.vout[CoinTxN].nValue > BalanceToStake) continue; { int64_t nStakeValue= CoinTx.vout[CoinTxN].nValue; StakeValueSum += nStakeValue /(double)COIN; //crazy formula... // todo: clean this // todo reuse calculated value for interst CBigNum bn = CBigNum(nStakeValue) * (blocknew.nTime-CoinTx.nTime) / CENT; bn = bn * CENT / COIN / (24 * 60 * 60); StakeCoinAgeSum += bn.getuint64(); } if(blocknew.nVersion==7) { NetworkTimer(); CoinWeight = CalculateStakeWeightV3(CoinTx,CoinTxN,GlobalCPUMiningCPID); StakeKernelHash= CalculateStakeHashV3(CoinBlock,CoinTx,CoinTxN,txnew.nTime,GlobalCPUMiningCPID,mdPORNonce); } else { uint64_t StakeModifier = 0; if(!FindStakeModifierRev(StakeModifier,pindexPrev)) continue; CoinWeight = CalculateStakeWeightV8(CoinTx,CoinTxN,GlobalCPUMiningCPID); StakeKernelHash= CalculateStakeHashV8(CoinBlock,CoinTx,CoinTxN,txnew.nTime,StakeModifier,GlobalCPUMiningCPID); } CBigNum StakeTarget; StakeTarget.SetCompact(blocknew.nBits); StakeTarget*=CoinWeight; StakeWeightSum += CoinWeight; StakeWeightMin=std::min(StakeWeightMin,CoinWeight); StakeWeightMax=std::max(StakeWeightMax,CoinWeight); double StakeKernelDiff = GetBlockDifficulty(StakeKernelHash.GetCompact())*CoinWeight; StakeDiffSum += StakeKernelDiff; StakeDiffMax = std::max(StakeDiffMax,StakeKernelDiff); if (fDebug2) { int64_t RSA_WEIGHT = GetRSAWeightByBlock(GlobalCPUMiningCPID); LogPrintf( "CreateCoinStake: V%d Time %.f, Por_Nonce %.f, Bits %jd, Weight %jd\n" " RSA_WEIGHT %.f\n" " Stk %72s\n" " Trg %72s\n" " Diff %0.7f of %0.7f\n", blocknew.nVersion, (double)txnew.nTime, mdPORNonce, (intmax_t)blocknew.nBits,(intmax_t)CoinWeight, (double)RSA_WEIGHT, StakeKernelHash.GetHex().c_str(), StakeTarget.GetHex().c_str(), StakeKernelDiff, GetBlockDifficulty(blocknew.nBits) ); } if( StakeKernelHash <= StakeTarget ) { // Found a kernel LogPrintf("\nCreateCoinStake: Found Kernel;\n"); blocknew.nNonce= mdPORNonce; vector<valtype> vSolutions; txnouttype whichType; CScript scriptPubKeyOut; CScript scriptPubKeyKernel; scriptPubKeyKernel = CoinTx.vout[CoinTxN].scriptPubKey; if (!Solver(scriptPubKeyKernel, whichType, vSolutions)) { LogPrintf("CreateCoinStake: failed to parse kernel\n"); break; } if (whichType == TX_PUBKEYHASH) // pay to address type { // convert to pay to public key type if (!wallet.GetKey(uint160(vSolutions[0]), key)) { LogPrintf("CreateCoinStake: failed to get key for kernel type=%d\n", whichType); break; // unable to find corresponding public key } scriptPubKeyOut << key.GetPubKey() << OP_CHECKSIG; } else if (whichType == TX_PUBKEY) // pay to public key type { valtype& vchPubKey = vSolutions[0]; if (!wallet.GetKey(Hash160(vchPubKey), key) || key.GetPubKey() != vchPubKey) { LogPrintf("CreateCoinStake: failed to get key for kernel type=%d\n", whichType); break; // unable to find corresponding public key } scriptPubKeyOut = scriptPubKeyKernel; } else { LogPrintf("CreateCoinStake: no support for kernel type=%d\n", whichType); break; // only support pay to public key and pay to address } txnew.vin.push_back(CTxIn(CoinTx.GetHash(), CoinTxN)); StakeInputs.push_back(pcoin.first); if (!txnew.GetCoinAge(txdb, CoinAge)) return error("CreateCoinStake: failed to calculate coin age"); int64_t nCredit = CoinTx.vout[CoinTxN].nValue; txnew.vout.push_back(CTxOut(0, CScript())); // First Must be empty txnew.vout.push_back(CTxOut(nCredit, scriptPubKeyOut)); //txnew.vout.push_back(CTxOut(0, scriptPubKeyOut)); LogPrintf("CreateCoinStake: added kernel type=%d credit=%f\n", whichType,CoinToDouble(nCredit)); LOCK(MinerStatus.lock); MinerStatus.KernelsFound++; MinerStatus.KernelDiffMax = 0; MinerStatus.KernelDiffSum = StakeDiffSum; return true; } } LOCK(MinerStatus.lock); MinerStatus.WeightSum = StakeWeightSum; MinerStatus.ValueSum = StakeValueSum; MinerStatus.WeightMin=StakeWeightMin; MinerStatus.WeightMax=StakeWeightMax; MinerStatus.CoinAgeSum=StakeCoinAgeSum; MinerStatus.KernelDiffMax = std::max(MinerStatus.KernelDiffMax,StakeDiffMax); MinerStatus.KernelDiffSum = StakeDiffSum; MinerStatus.nLastCoinStakeSearchInterval= txnew.nTime; return false; }
Value getworkex(const Array& params, bool fHelp) { if (fHelp || params.size() > 2) throw runtime_error( "getworkex [data, coinbase]\n" "If [data, coinbase] is not specified, returns extended work data.\n" ); if (vNodes.empty()) throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Gytecoin is not connected!"); if (IsInitialBlockDownload()) throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Gytecoin is downloading blocks..."); typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t; static mapNewBlock_t mapNewBlock; // FIXME: thread safety static vector<CBlockTemplate*> vNewBlockTemplate; static CReserveKey reservekey(pwalletMain); if (params.size() == 0) { // Update block static unsigned int nTransactionsUpdatedLast; static CBlockIndex* pindexPrev; static int64 nStart; static CBlockTemplate* pblocktemplate; if (pindexPrev != pindexBest || (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60)) { if (pindexPrev != pindexBest) { // Deallocate old blocks since they're obsolete now mapNewBlock.clear(); BOOST_FOREACH(CBlockTemplate* pblocktemplate, vNewBlockTemplate) delete pblocktemplate; vNewBlockTemplate.clear(); } // Clear pindexPrev so future getworks make a new block, despite any failures from here on pindexPrev = NULL; // Store the pindexBest used before CreateNewBlock, to avoid races nTransactionsUpdatedLast = nTransactionsUpdated; CBlockIndex* pindexPrevNew = pindexBest; nStart = GetTime(); // Create new block pblocktemplate = CreateNewBlockWithKey(*pMiningKey); if (!pblocktemplate) throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); vNewBlockTemplate.push_back(pblocktemplate); // Need to update only after we know CreateNewBlock succeeded pindexPrev = pindexPrevNew; } CBlock* pblock = &pblocktemplate->block; // pointer for convenience // Update nTime pblock->UpdateTime(pindexPrev); pblock->nNonce = 0; // Update nExtraNonce static unsigned int nExtraNonce = 0; IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); // Save mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig); // Pre-build hash buffers char pmidstate[32]; char pdata[128]; char phash1[64]; FormatHashBuffers(pblock, pmidstate, pdata, phash1); uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); CTransaction coinbaseTx = pblock->vtx[0]; std::vector<uint256> merkle = pblock->GetMerkleBranch(0); Object result; result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata)))); result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget)))); CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); ssTx << coinbaseTx; result.push_back(Pair("coinbase", HexStr(ssTx.begin(), ssTx.end()))); Array merkle_arr; BOOST_FOREACH(uint256 merkleh, merkle) { printf("%s\n", merkleh.ToString().c_str()); merkle_arr.push_back(HexStr(BEGIN(merkleh), END(merkleh))); } result.push_back(Pair("merkle", merkle_arr)); return result; }
GLvoid CRoomManager::addRoomTile(CBlock *block) { CLevelManager *lManager = CV_GAME_MANAGER->getLevelManager(); vector2i pos = block->getLogicalPosition(); vector2i posses[] = {vector2i(-1,0),vector2i(1,0),vector2i(0,-1),vector2i(0,1)}; bool nbrs[4]; nbrs[0] = lManager->isSameTypeAndOwner(pos[0]-1,pos[1],block); nbrs[1] = lManager->isSameTypeAndOwner(pos[0]+1,pos[1],block); nbrs[2] = lManager->isSameTypeAndOwner(pos[0],pos[1]-1,block); nbrs[3] = lManager->isSameTypeAndOwner(pos[0],pos[1]+1,block); GLint cnt = 0; cnt+=nbrs[0]?1:0; cnt+=nbrs[1]?1:0; cnt+=nbrs[2]?1:0; cnt+=nbrs[3]?1:0; if (cnt==0) { // create a new room CRoom *newRoom = new CRoom(); newRoom->getRoomTilesVector()->push_back(block); newRoom->reownTiles(); allRooms[newRoom->getIndex()] = newRoom; roomColors[newRoom->getIndex()] = vector3f((GLfloat)(rand()%101)/100.0f,(GLfloat)(rand()%101)/100.0f,(GLfloat)(rand()%101)/100.0f); CV_GAME_MANAGER->getConsole()->writeLine("A new room!"); } else { GLint owner = -1; GLint roomIndex = -1; GLint type = -1; bool set = false; bool ok[] = {true, true, true}; CBlock *testBlock = NULL; for (int i=0; i<4; i++) { if (nbrs[i]) { testBlock = lManager->getBlock(pos+posses[i]); if (!set) { set = true; owner = testBlock->getOwner(); roomIndex = testBlock->getRoomIndex(); type = testBlock->getType(); } else { ok[0] &= (owner == testBlock->getOwner()); ok[1] &= (roomIndex == testBlock->getRoomIndex()); ok[2] &= (type == testBlock->getType()); } } } if (ok[0]&&ok[1]&&ok[2]) { // all of same type, owner and room. just add this tile to this existing room allRooms[testBlock->getRoomIndex()]->getRoomTilesVector()->push_back(block); allRooms[testBlock->getRoomIndex()]->reownTiles(); CV_GAME_MANAGER->getConsole()->writeLine("Tile added to the existing room."); } else { std::map<GLint, CBlock*> blockPerRoom; // we must make some merging for (int i=0; i<4; i++) { if (nbrs[i]) { testBlock = lManager->getBlock(pos+posses[i]); blockPerRoom[testBlock->getRoomIndex()] = testBlock; } } // on this stage there are at least 2 elements in blockPerRoom. // take the first room and add it it all other room tiles. // then delete other rooms std::map<GLint, CBlock*>::iterator irIter = blockPerRoom.begin(); CRoom *targetRoom = allRooms[irIter->first]; irIter++; for (irIter; irIter!=blockPerRoom.end(); irIter++) { CRoom *room = allRooms[irIter->first]; for (GLuint t=0; t<room->getRoomTilesVector()->size(); t++) { targetRoom->getRoomTilesVector()->push_back((*room->getRoomTilesVector())[t]); } // delete the unwanted room allRooms.erase(allRooms.find(irIter->first)); } targetRoom->getRoomTilesVector()->push_back(block); targetRoom->reownTiles(); CV_GAME_MANAGER->getConsole()->writeLine("Rooms merged."); } } }