Пример #1
0
	/** Main Connection Thread. Handles all the networking to allow
	Mining threads the most performance. **/
	void ServerConnection::ServerThread()
	{

		/** Don't begin until all mining threads are Created. **/
		while (THREADS.size() != nThreads)
			Sleep(1000);


		/** Initialize the Server Connection. **/
		CLIENT = new LLP::Miner(IP, PORT);


		/** Initialize a Timer for the Hash Meter. **/
		TIMER.Start();
		unsigned int nTimerWait = 2;

		unsigned int nBestHeight = 0;
		loop
		{
			try
			{
				/** Run this thread at 1 Cycle per Second. **/
				Sleep(50);


				/** Attempt with best efforts to keep the Connection Alive. **/
				if (!CLIENT->Connected() || CLIENT->Errors())
				{
					ResetThreads();

					if (!CLIENT->Connect())
						continue;
					else
						CLIENT->SetChannel(2);
				}


				/** Check the Block Height. **/
				unsigned int nHeight = CLIENT->GetHeight(5);
				if (nHeight == 0)
				{
					printf("[MASTER] Failed to Update Height\n");
					CLIENT->Disconnect();
					continue;
				}

				/** If there is a new block, Flag the Threads to Stop Mining. **/
				if (nHeight != nBestHeight)
				{
					nBestHeight = nHeight;
					printf("[MASTER] Coinshield Network: New Block %u\n", nHeight);

					ResetThreads();
				}

				/** Rudimentary Meter **/
				if (TIMER.Elapsed() > nTimerWait)
				{
					double  Elapsed = (double)TIMER.ElapsedMilliseconds();
					unsigned long long nHashes = Hashes();
					//double khash = ((double)nHashes)/Elapsed;
					unsigned long long khash = nHashes / TIMER.ElapsedMilliseconds();
					unsigned int nDifficulty = THREADS[0]->GetBlock()->GetBits();
					nDifficulty = nDifficulty & 0xffffff;
					CBigNum target;
					target.SetCompact(nDifficulty);

					//double diff = (double)(0xFFFF * pow(2, 208)) / (double)nDifficulty;
					printf("[METERS] %llu kHash/s | Height = %u | Diff= %.08f\n", khash, nBestHeight, 1.0 / (double)nDifficulty);

					TIMER.Reset();
					if (nTimerWait == 2)
						nTimerWait = 20;
				}


				/** Check if there is work to do for each Miner Thread. **/
				for (unsigned int nIndex = 0; nIndex < THREADS.size(); nIndex++)
				{

					/** Attempt to get a new block from the Server if Thread needs One. **/

					if (THREADS[nIndex]->GetIsNewBlock())
					{
						/** Retrieve new block from Server. **/
						/** Delete the Block Pointer if it Exists. **/
						CBlock* pBlock = THREADS[nIndex]->GetBlock();
						if (pBlock != NULL)
						{
							delete(pBlock);
						}

						/** Retrieve new block from Server. **/
						pBlock = CLIENT->GetBlock(5);


						/** If the block is good, tell the Mining Thread its okay to Mine. **/
						if (pBlock)
						{
							THREADS[nIndex]->SetIsBlockFound(false);
							THREADS[nIndex]->SetIsNewBlock(false);
							THREADS[nIndex]->SetBlock(pBlock);
							THREADS[nIndex]->SetHashes(0); // reset hash count

						}

						/** If the Block didn't come in properly, Reconnect to the Server. **/
						else
						{
							CLIENT->Disconnect();

							break;
						}

					}

					/** Submit a block from Mining Thread if Flagged. **/
					else if (THREADS[nIndex]->GetIsBlockFound())
					{

						//							
						/** Attempt to Submit the Block to Network. **/
						unsigned char RESPONSE = CLIENT->SubmitBlock(THREADS[nIndex]->GetBlock()->GetMerkleRoot(), THREADS[nIndex]->GetBlock()->GetNonce(), 10);
						double  Elapsed = (double)TIMER.ElapsedMilliseconds();
						double  nHashes = THREADS[nIndex]->GetHashes();
						double khash = nHashes / Elapsed;
						Hashes();
						TIMER.Reset();
						if (RESPONSE == 200)
							printf("[MASTER] Block Found by %s on thread %d                   %.1f kHash/s (accepted) Yay !!!\n", device_name[nIndex], nIndex, khash);
						else if (RESPONSE == 201)
						{

							printf("[MASTER] Block Found by %s on thread %d                  %.1f kHash/s (rejected) Booo !!!\n", device_name[nIndex], nIndex, khash);
							THREADS[nIndex]->SetIsNewBlock(true);
							THREADS[nIndex]->SetIsBlockFound(false);
						}
						else
						{
							printf("[MASTER] Failure to Submit Block. Reconnecting...\n");
							CLIENT->Disconnect();
						}

						break;


					}
				}
			}

			catch (std::exception& e)
			{
				printf("%s\n", e.what());
			}
		}

	};
Пример #2
0
void
ReaderTask(int fd, const char *id)
{
    time_t dtime = 0;
    time_t ltime = 0;
    time_t itime = 0;
    time_t ftime = 0;
    time_t atime = 0;
    int counter = 0;
    int forceallcheck = 0;
    int check_disconn_counter = 0;

    TFd = fd;

    /*
     * [re]open RTStatus
     */
    RTStatusOpen(RTStatus, ThisReaderFork * DOpts.ReaderThreads + 1, DOpts.ReaderThreads);

    /*
     * Since we setuid(), we won't core.  This is for debugging
     */
    if (CoreDebugOpt || (DOpts.ReaderCrashHandler != NULL &&
			strcasecmp(DOpts.ReaderCrashHandler, "none") != 0)) {
	signal(SIGSEGV, sigSegVReader);
	signal(SIGBUS, sigSegVReader);
	signal(SIGFPE, sigSegVReader);
	signal(SIGILL, sigSegVReader);
    }

    signal(SIGHUP, sigHup);
    signal(SIGUSR1, sigUsr1);

    /*
     * Setup thread for passed pipe
     */
    ResetThreads();
    AddThread("reader", fd, -1, THREAD_READER, -1, 0);

    FD_SET(fd, &RFds);

    /*
     * Open KPDB database for active file
     */

    if ((KDBActive = KPDBOpen(PatDbExpand(ReaderDActivePat), O_RDWR)) == NULL) {
	logit(LOG_CRIT, "Unable to open %s", PatDbExpand(ReaderDActivePat));
	sleep(60);
	exit(1);
    }

    LoadExpireCtl(1);

    /*
     * Only startup connections to backend spools for reader threads
     */
    if (!FeedOnlyServer)
	CheckServerConfig(time(NULL), 1);

    /*
     * Selection core
     */

    while (!TerminatePending || NReadServAct || NumReaders) {
	/*
	 *  select core
	 */
	struct timeval tv;
	fd_set rfds = RFds;
	fd_set wfds = WFds;
	fd_set read_only_to_find_eof_fds;
	int i, sel_r;

	if (TerminatePending) {
	    if (TerminateTime == 0)
		TerminateTime = time(NULL) + 2;
	    if (TerminateTime < time(NULL) || !NumReaders)
		CanTerminate = 1;
	}

	/*
	 *  Get next scheduled timeout, no more then 2 seconds
	 *  (x 10 counter counts = 20 seconds max for {d,i,f}time 
	 *  check)
	 *
	 * If we are terminating, then speed up the select to clear
	 * out the connections.
	 *
	 */

	if (TerminatePending)
	    NextTimeout(&tv, 50);
	else
	    NextTimeout(&tv, 2 * 1000);

	stprintf("%s readers=%02d spoolsrv=%d/%d postsrv=%d/%d",
	    id,
	    NumReaders,
	    NReadServAct, NReadServers, 
	    NWriteServAct, NWriteServers
	);

	/* Check for disconnected clients every 50 times through the loop */
	FD_ZERO(&read_only_to_find_eof_fds);
	if (++check_disconn_counter == 50) {
	    for (i = 0; i < MaxFds; ++i) {
		if (FD_ISSET(i, &wfds) && (!(FD_ISSET(i, &rfds)))) {
		    FD_SET(i, &rfds);
		    FD_SET(i, &read_only_to_find_eof_fds);
		}
	    }
	    check_disconn_counter = 0;
	}

#if USE_AIO
	AIOUnblockSignal();
#endif
	sel_r = select(MaxFds, &rfds, &wfds, NULL, &tv);
#if USE_AIO
	AIOBlockSignal();
#endif

	gettimeofday(&CurTime, NULL);

	if(sel_r < 0 && errno != EINTR)
	    logit(LOG_CRIT,
		  "select error: %s (rfds=0x%x, wfds=0x%x)",
		  strerror(errno),
		  rfds,
		  wfds);

	/*
	 * select is critical, don't make unnecessary system calls.  Only
	 * test the time every 10 selects (20 seconds worst case), and
	 * only check for a new server configuration file every 60 seconds 
	 * after the initial load.  This may rearrange THREAD_SPOOL and
	 * THREAD_POST threads.
	 *
	 * We do not startup spool/post servers for feed-only forks
	 *
	 * However, flush overview cache even for feed-only forks.
	 */

	if (FeedOnlyServer <= 0) {
	    if (++counter == 10) {
		time_t t = CurTime.tv_sec;
		if (ltime) {
		    dtime += t - ltime;
		    itime += t - ltime;
		    ftime += t - ltime;
		    atime += t - ltime;
		}

		/*
		 * Check for server config change once a minute
		 */
		if (dtime < -5 || dtime >= 5) {
		    if (!TerminatePending)
			CheckServerConfig(t, ServersTerminated);
		    dtime = 0;
		}

		/*
		 * Flush overview every 30 seconds to allow dexpireover to work
		 */
		if (ftime < -5 || ftime >= 30) {
		    FlushOverCache();
		    LoadExpireCtl(0);
		    ftime = 0;
		}

		/*
		 * Poll all active descriptors once every 5 minutes.  This
		 * will work around a linux embrionic close bug that
		 * doesn't wakeup select(), and is used to idle-timeout
		 * connections. XXX
		 */
		if (itime < -5 || itime >= 300) {
		    rfds = RFds;
		    itime = 0;
		}

		/*
		 * Force a check all of FD's every 30 seconds to handle
		 * idle and session timeouts
		 */
		if (atime < -5 || atime >= 30) {
		    forceallcheck = 1;
		    atime = 0;
		}
		ltime = t;
		counter = 0;
	    }
	} else {
	    /*
	     * For a feed-only server, we only flush the overview FD
	     * cache every 5 minutes, and with a greater granularity.
	     * It should cycle much faster than that normally, and this
	     * is to prevent idle feed-only forks from keeping locks.
	     *
	     */

	    if (++counter == 10) {
		time_t t = CurTime.tv_sec;
		if (ltime) {
		    ftime += t - ltime;
		}

		if (ftime < -5 || ftime >= 300) {
		    FlushOverCache();
		    ftime = 0;
		}
		ltime = t;
		counter = 0;
	    }
	}

	for (i = 0; i < MaxFds; ++i) {
	    if (FD_ISSET(i, &rfds) && FD_ISSET(i, &read_only_to_find_eof_fds)) {
		char junk_byte;
		int ret_val;
		/*
		 * This FD is not marked for reading, but select() claims
		 * it has something to say. We don't actually want to read
		 * from it, but we do want to close it if the associated
		 * connection is dead.
		 */
		FD_CLR(i, &rfds);

		/* Use recv() with MSG_PEEK to see if it's closed.
		 * We shouldn't block because we're O_NONBLOCK.
		 */
		ret_val = recv(i, &junk_byte, 1, MSG_PEEK);

		/* If ret_val is zero, this means the socket is closed.
		 * Blast it. Otherwise, ignore it.
		 */
		if(ret_val == 0) {
		    ForkDesc *desc;
		    if((desc = FindThread(i, -1)) != NULL) {
			Connection *conn = desc->d_Data;

			if(conn) {
			    NNTerminate(conn);
			    DeleteConnection(conn);
			}
			DelThread(desc);
		    }
		}
	    }
	}

	for (i = 0; i < MaxFds; ++i) {
	    if (forceallcheck || TerminatePending ||
		FD_ISSET(i, &rfds) || FD_ISSET(i, &wfds)) {
		ForkDesc *desc;

		if ((desc = FindThread(i, -1)) != NULL) {
		    Connection *conn = desc->d_Data;

		    if (conn) {
			/*
			 * handle output I/O (optimization)
			 */

			MBFlush(conn, &conn->co_TMBuf);
			conn->co_FCounter = 0;
		    } 

		    /*
		     * Function dispatch
		     */

		    switch(desc->d_Type) {
		    case THREAD_READER:
			if (FD_ISSET(i, &rfds) || FD_ISSET(i, &wfds))
			    HandleReaderMsg(desc);
			break;
		    case THREAD_NNTP:		/* client	  */
			conn->co_Func(conn);
			if (conn->co_Auth.dr_ResultFlags & DR_REQUIRE_DNS) {
			    /* Go back to parent for DNS check */
			    conn->co_Auth.dr_Code = 0;
			    conn->co_TMBuf.mh_WEof = 1;
			}
			break;
		    case THREAD_SPOOL:		/* spool server	  */
		    case THREAD_POST:		/* posting server */
			conn->co_Func(conn);
			LogServerInfo(conn, TFd);
			break;
		    default:
			/* panic */
			break;
		    }

		    /*
		     * do not call MBFlush after the function because the
		     * function may be waiting for write data to drain and
		     * we don't want to cause write data to drain here and
		     * then not get a select wakeup later.
		     *
		     * check for connection termination
		     */

		    if (conn) {
			int idleTimeout = 0;
			if (conn->co_Auth.dr_ReaderDef) {
			    if (conn->co_Auth.dr_ReaderDef->rd_IdleTimeout &&
				    conn->co_LastActiveTime +
				    conn->co_Auth.dr_ReaderDef->rd_IdleTimeout <=
				    CurTime.tv_sec) {
				logit(LOG_INFO, "timeout idle %s",
				    conn->co_Auth.dr_Host);
				MBLogPrintf(conn,
				    &conn->co_TMBuf,
				    "400 %s: Idle timeout.\r\n",
				    conn->co_Auth.dr_VServerDef->vs_HostName
				);
				idleTimeout = 1;
				NNTerminate(conn);
			    }
			    if (conn->co_Auth.dr_ReaderDef->rd_SessionTimeout &&
				    conn->co_SessionStartTime +
				    conn->co_Auth.dr_ReaderDef->rd_SessionTimeout <=
				    CurTime.tv_sec) {
				logit(LOG_INFO, "timeout session %s",
				    conn->co_Auth.dr_Host);
				MBLogPrintf(conn,
				    &conn->co_TMBuf,
				    "400 %s: Session timeout.\r\n",
				    conn->co_Auth.dr_VServerDef->vs_HostName
				);
				idleTimeout = 1;
				NNTerminate(conn);
			    }
			}
			if ((!conn->co_Auth.dr_Code &&
				desc->d_Type == THREAD_NNTP) ||
			    idleTimeout ||
			    (conn->co_RMBuf.mh_REof && 
			    conn->co_TMBuf.mh_WEof &&
			    conn->co_TMBuf.mh_MBuf == NULL) ||
			    (TerminatePending &&
					!(conn->co_Flags & COF_MAYNOTCLOSE))
			) {
			    DeleteConnection(conn);
			    DelThread(desc);
			}
		    }
		}
	    }
	}
	forceallcheck = 0;
	(void)ScanTimers(1, 0);
	if (CanTerminate)
	    break;
    }
    RTStatusClose();
    KPDBClose(KDBActive);
    exit(0);
}
Пример #3
0
	/** Main Connection Thread. Handles all the networking to allow
		Mining threads the most performance. **/
	void ServerConnection::ServerThread()
	{
		
		/** Don't begin until all mining threads are Created. **/
		while(THREADS.size() != nThreads)
			Sleep(1);
				
				
		/** Initialize the Server Connection. **/
		CLIENT = new LLP::Miner(IP, PORT);
			
				
		/** Initialize a Timer for the Hash Meter. **/
		METER_TIMER.Start();
		HEIGHT_TIMER.Start();

		loop
		{
			try
			{
				/** Run this thread at 100 Cycles per Second. **/
				Sleep(10);
					
					
				/** Attempt with best efforts to keep the Connection Alive. **/
				if(!CLIENT->Connected() || CLIENT->Errors() || CLIENT->Timeout(nTimeout))
				{
					ResetThreads();
					
					if(!CLIENT->Connect())
						continue;
					else
					{
						CLIENT->SetChannel(1);
						CLIENT->GetHeight();
					}
				}
				
				
				/** Check the Block Height every Second. **/
				if(HEIGHT_TIMER.ElapsedMilliseconds() > 1000)
				{
					HEIGHT_TIMER.Reset();
					CLIENT->GetHeight();
				}
				
				
				/** Show the Meter every 15 Seconds. **/
				if(METER_TIMER.Elapsed() > 15)
				{
					unsigned int SecondsElapsed = (unsigned int)time(0) - nStartTimer;
					unsigned int nElapsed = METER_TIMER.Elapsed();
					double PPS = (double) nPrimes / nElapsed;
					double CPS = (double) nChains / nElapsed;
					double CSD = (double) (nBlocks * 60.0) / (SecondsElapsed / 60.0);
					
					nPrimes = 0;
					nChains = 0;
					
					printf("[METERS] %f PPS | %f CPS | %u Blocks | %f NXS per Hour | Height = %u | Difficulty %f | %02d:%02d:%02d\n", PPS, CPS, nBlocks, CSD, nBestHeight, nDifficulty / 10000000.0, (SecondsElapsed/3600)%60, (SecondsElapsed/60)%60, (SecondsElapsed)%60);
					METER_TIMER.Reset();	
					
					ResetThreads();
				}
				
				
				/** Check if there is work to do for each Miner Thread. **/
				for(int nIndex = 0; nIndex < THREADS.size(); nIndex++)
				{
					/** Attempt to get a new block from the Server if Thread needs One. **/
					if(THREADS[nIndex]->fNewBlock)
					{
						CLIENT->GetBlock();
						THREADS[nIndex]->fBlockWaiting = true;
						THREADS[nIndex]->fNewBlock = false;
					}
				}
					
				CLIENT->ReadPacket();
				if(!CLIENT->PacketComplete())
					continue;
						
				/** Handle the New Packet, and Interpret its Data. **/
				LLP::Packet PACKET = CLIENT->NewPacket();
				CLIENT->ResetPacket();
							
							
				/** Output if a Share is Accepted. **/
				if(PACKET.HEADER == CLIENT->GOOD)
				{
					nBlocks++;
					printf("[MASTER] Nexus : Block ACCEPTED\n");
					
					ResetThreads();
				}
					
					
				/** Output if a Share is Rejected. **/
				else if(PACKET.HEADER == CLIENT->FAIL) 
				{
					printf("[MASTER] Nexus : Block REJECTED\n");
					
					ResetThreads();
				}
					
				/** Reset the Threads if a New Block came in. **/
				else if(PACKET.HEADER == CLIENT->BLOCK_HEIGHT)
				{
					unsigned int nHeight = bytes2uint(PACKET.DATA);
					if(nHeight > nBestHeight)
					{
						nBestHeight = nHeight;
						printf("[MASTER] Nexus : New Block %u.\n", nBestHeight);
							
						ResetThreads();
					}
				}
					
					
				/** Set the Block for the Thread if there is a New Block Packet. **/
				else if(PACKET.HEADER == CLIENT->BLOCK_DATA)
				{
					/** Search for a Thread waiting for a New Block to Supply its need. **/
					for(int nIndex = 0; nIndex < THREADS.size(); nIndex++)
					{
						if(THREADS[nIndex]->fBlockWaiting)
						{
							THREADS[nIndex]->MUTEX.lock();
							THREADS[nIndex]->cBlock.nVersion      = bytes2uint(std::vector<unsigned char>(PACKET.DATA.begin(), PACKET.DATA.begin() + 4));
							
							THREADS[nIndex]->cBlock.hashPrevBlock.SetBytes (std::vector<unsigned char>(PACKET.DATA.begin() + 4, PACKET.DATA.begin() + 132));
							THREADS[nIndex]->cBlock.hashMerkleRoot.SetBytes(std::vector<unsigned char>(PACKET.DATA.begin() + 132, PACKET.DATA.end() - 20));
							
							THREADS[nIndex]->cBlock.nChannel      = bytes2uint(std::vector<unsigned char>(PACKET.DATA.end() - 20, PACKET.DATA.end() - 16));
							THREADS[nIndex]->cBlock.nHeight       = bytes2uint(std::vector<unsigned char>(PACKET.DATA.end() - 16, PACKET.DATA.end() - 12));
							THREADS[nIndex]->cBlock.nBits         = bytes2uint(std::vector<unsigned char>(PACKET.DATA.end() - 12,  PACKET.DATA.end() - 8));
							THREADS[nIndex]->cBlock.nNonce        = bytes2uint64(std::vector<unsigned char>(PACKET.DATA.end() - 8,  PACKET.DATA.end()));
							THREADS[nIndex]->MUTEX.unlock();
							
							if(THREADS[nIndex]->cBlock.nHeight < nBestHeight)
							{
								printf("[MASTER] Received Obsolete Block %u... Requesting New Block.\n", THREADS[nIndex]->cBlock.nHeight);
								CLIENT->GetBlock();
									
								break;
							}
							
							/** Set the Difficulty from most recent Block Received. **/
							nDifficulty = THREADS[nIndex]->cBlock.nBits;
								
							printf("[MASTER] Block %s Height = %u Received on Thread %u\n", THREADS[nIndex]->cBlock.hashMerkleRoot.ToString().substr(0, 20).c_str(), THREADS[nIndex]->cBlock.nHeight, nIndex);
							THREADS[nIndex]->fBlockWaiting = false;
								
							break;
						}
					}
				}
					
			}
			catch(std::exception& e)
			{
				printf("%s\n", e.what()); CLIENT = new LLP::Miner(IP, PORT); 
			}
		}
	}
Пример #4
0
//Main Connection Thread. Handles all the networking to allow
//Mining threads the most performance.
void SKServerConnection::ServerThread()
{
	/** Don't begin until all mining threads are Created. **/
	while ((m_vecTHREADS.size() != m_nThreads) && !m_bIsShutDown)
		Sleep(1000);

	/** Initialize the Server Connection. **/
	m_pCLIENT = new LLP::Miner(m_szIP, m_szPORT);

	/** Initialize a Timer for the Hash Meter. **/
	m_tTIMER.Start();
	m_totalTIMER.Start();

	m_nBestHeight = 0;
	m_nNewBlocks = 0;
	loop
	{
		if (m_bIsShutDown)
		{
			break;
		}

		try
		{
			/** Run this thread at 1 Cycle per Second. **/
			Sleep(1000);

			if (!m_bIsEnabled)
			{
				continue;
			}

			/** Attempt with best efforts to keep the Connection Alive. **/
			if (!m_pCLIENT->Connected() || m_pCLIENT->Errors())
			{
				if (!m_pCLIENT->Connect())
					continue;

				/** Send to the server the Channel we will be Mining For. **/
				else
					m_pCLIENT->SetChannel(2);
			}

			/** Check the Block Height. **/
			unsigned int nHeight = m_pCLIENT->GetHeight(5);
			if (nHeight == 0)
			{
				printf("Failed to Update Height...\n");
				m_pCLIENT->Disconnect();
				continue;
			}

			/** If there is a new block, Flag the Threads to Stop Mining. **/
			if (nHeight != m_nBestHeight)
			{
				m_nBestHeight = nHeight;
				m_nNewBlocks++;

				printf("[MASTER] Coinshield Network | New Block %u\n", nHeight);

				ResetThreads();
			}


			/** Rudimentary Meter **/
			if (m_tTIMER.Elapsed() > 10)
			{
				//unsigned int nElapsed = m_tTIMER.ElapsedMilliseconds();
				//unsigned int nHashes = Hashes();
				double KHASH = Hashes();
				
				//double KHASH = (double)nHashes / nElapsed;
				printf("[METERS] %f KHash/s | Height = %u\n", KHASH, m_nBestHeight);

				m_tTIMER.Reset();
			}


			/** Check if there is work to do for each Miner Thread. **/
			for (int nIndex = 0; nIndex < m_vecTHREADS.size(); nIndex++)
			{
				if (m_bIsShutDown)
				{
					break;
				}

				if (!m_vecTHREADS[nIndex]->GetMinerData()->GetGPUData()->GetGPUSetting()->GetIsEnabled())
				{
					continue;
				}				

				/** Attempt to get a new block from the Server if Thread needs One. **/
				if (m_vecTHREADS[nIndex]->GetIsNewBlock())
				{
					/** Delete the Block Pointer if it Exists. **/
					Core::CBlock* pBlock = m_vecTHREADS[nIndex]->GetMinerData()->GetBlock();
					if (pBlock != NULL)
					{
						delete(pBlock);
						pBlock = NULL;
					}

					/** Retrieve new block from Server. **/
					m_pCLIENT->SetChannel(2);
					pBlock = m_pCLIENT->GetBlock(5);

					/** If the block is good, tell the Mining Thread its okay to Mine. **/
					if (pBlock && pBlock->GetChannel() == 2)
					{
						m_vecTHREADS[nIndex]->SetIsNewBlock(false);
						m_vecTHREADS[nIndex]->SetIsBlockFound(false);
						m_vecTHREADS[nIndex]->GetMinerData()->SetBlock(pBlock);
					}
					/** If the Block didn't come in properly, Reconnect to the Server. **/
					else
					{
						m_pCLIENT->Disconnect();
					}

				}
				/** Submit a block from Mining Thread if Flagged. **/
				else if (m_vecTHREADS[nIndex]->GetIsBlockFound())
				{
					/** Attempt to Submit the Block to Network. **/

					unsigned char RESPONSE = m_pCLIENT->SubmitBlock(m_vecTHREADS[nIndex]->GetMinerData()->GetBlock()->GetMerkleRoot(), m_vecTHREADS[nIndex]->GetMinerData()->GetBlock()->GetNonce(), 30);
					printf("[MASTER] Hash Found on Miner Thread %i\n", nIndex);

					unsigned long long truc = m_vecTHREADS[nIndex]->GetMinerData()->GetBlock()->GetNonce();
					printf("[MASTER] nonce %08x %08x\n", (uint32_t)(truc >> 32)), (uint32_t)(truc & 0xFFFFFFFFULL);

					/** Check the Response from the Server.**/
					if (RESPONSE == 200)
					{
						printf("[MASTER] Block Accepted By Coinshield Network.\n");

						m_vecTHREADS[nIndex]->SetBlocksFound(m_vecTHREADS[nIndex]->GetBlocksFound() + 1);
					}
					else if (RESPONSE == 201)
					{
						printf("[MASTER] Block Rejected by Coinshield Network.\n");

						m_vecTHREADS[nIndex]->SetRejected(m_vecTHREADS[nIndex]->GetRejected() + 1);
						m_vecTHREADS[nIndex]->SetIsNewBlock(true);
						m_vecTHREADS[nIndex]->SetIsBlockFound(false);
					}
					/** If the Response was Incomplete, Reconnect to Server and try to Submit Block Again. **/
					else
					{
						printf("[MASTER] Failure to Submit Block. Reconnecting...\n");
						m_pCLIENT->Disconnect();
					}

					break;                           
				}
			}
		}
		catch (std::exception& e)
		{ 
			std::cout << e.what() << std::endl;
		}
	}

	if (m_bIsShutDown)
	{
		for (size_t index = 0; index < m_vecTHREADS.size(); ++index)
		{
			m_vecTHREADS[index]->SetIsShuttingDown(true);

			while (!m_vecTHREADS[index]->GetDidShutDown()){}
		}

		m_bDidShutDown = true;
	}
}