void RemoteMinerClient::HandleMessage(const RemoteMinerMessage &message)
{
	json_spirit::Value tval=json_spirit::find_value(message.GetValue().get_obj(),"type");
	if(tval.type()==json_spirit::int_type)
	{
		std::cout << "Got message " << tval.get_int() << " from server." << std::endl;
		if(tval.get_int()==RemoteMinerMessage::MESSAGE_TYPE_SERVERHELLO)
		{
			m_gotserverhello=true;
			tval=json_spirit::find_value(message.GetValue().get_obj(),"metahashrate");
			if(tval.type()==json_spirit::int_type)
			{
				m_minerthreads.SetMetaHashSize(tval.get_int());
				m_metahashsize=tval.get_int();
			}
			tval=json_spirit::find_value(message.GetValue().get_obj(),"serverversion");
			if(tval.type()==json_spirit::str_type)
			{
				std::cout << "Server version " << tval.get_str() << std::endl;
			}
			tval=json_spirit::find_value(message.GetValue().get_obj(),"distributiontype");
			if(tval.type()==json_spirit::str_type)
			{
				std::cout << "Distribution type : " << tval.get_str() << std::endl;
			}
		}
		else if(tval.get_int()==RemoteMinerMessage::MESSAGE_TYPE_SERVERSENDWORK)
		{
			int64 nextblockid=0;
			std::vector<unsigned char> nextblock;
			std::vector<unsigned char> nextmidstate;
			uint256 nexttarget;
			tval=json_spirit::find_value(message.GetValue().get_obj(),"blockid");
			if(tval.type()==json_spirit::int_type)
			{
				nextblockid=tval.get_int();
			}
			tval=json_spirit::find_value(message.GetValue().get_obj(),"block");
			if(tval.type()==json_spirit::str_type)
			{
				DecodeBase64(tval.get_str(),nextblock);
			}
			tval=json_spirit::find_value(message.GetValue().get_obj(),"target");
			if(tval.type()==json_spirit::str_type)
			{
				nexttarget.SetHex(tval.get_str());
			}
			tval=json_spirit::find_value(message.GetValue().get_obj(),"midstate");
			if(tval.type()==json_spirit::str_type)
			{
				DecodeBase64(tval.get_str(),nextmidstate);
			}

			tval=json_spirit::find_value(message.GetValue().get_obj(),"fullblock");
			if(tval.type()==json_spirit::obj_type)
			{
				SaveBlock(tval.get_obj(),"block.txt");
				if(m_address160!=0)
				{
					double amount=0;
					if(FindGenerationAddressInBlock(m_address160,tval.get_obj(),amount))
					{
						std::cout << "Address " << Hash160ToAddress(m_address160) <<  " will receive " << amount << " BTC if this block is solved" << std::endl;
					}
					else
					{
						std::cout << "Address " << Hash160ToAddress(m_address160) << " not found in block being solved" << std::endl;
					}
				}
			}

			m_minerthreads.SetNextBlock(nextblockid,nexttarget,nextblock,nextmidstate);

		}
		else if(tval.get_int()==RemoteMinerMessage::MESSAGE_TYPE_SERVERSTATUS)
		{
			int64 clients=0;
			int64 khashmeta=0;
			int64 khashbest=0;
			int64 clientkhashmeta=0;
			time_t startuptime=0;
			struct tm startuptimetm;
			std::string startuptimestr("");
			int64 blocksgenerated=0;

			tval=json_spirit::find_value(message.GetValue().get_obj(),"clients");
			if(tval.type()==json_spirit::int_type)
			{
				clients=tval.get_int();
			}
			tval=json_spirit::find_value(message.GetValue().get_obj(),"khashmeta");
			if(tval.type()==json_spirit::int_type)
			{
				khashmeta=tval.get_int();
			}
			tval=json_spirit::find_value(message.GetValue().get_obj(),"khashbest");
			if(tval.type()==json_spirit::int_type)
			{
				khashbest=tval.get_int();
			}
			tval=json_spirit::find_value(message.GetValue().get_obj(),"yourkhashmeta");
			if(tval.type()==json_spirit::int_type)
			{
				clientkhashmeta=tval.get_int();
			}
			tval=json_spirit::find_value(message.GetValue().get_obj(),"sessionstartuptime");
			if(tval.type()==json_spirit::int_type)
			{
				startuptime=tval.get_int();
				startuptimetm=*gmtime(&startuptime);
				std::vector<char> buff(128,0);
				int rval=strftime(&buff[0],buff.size()-1,"%Y-%m-%d %H:%M:%S",&startuptimetm);
				buff.resize(rval);
				startuptimestr=std::string(buff.begin(),buff.end());
			}
			tval=json_spirit::find_value(message.GetValue().get_obj(),"sessionblocksgenerated");
			if(tval.type()==json_spirit::int_type)
			{
				blocksgenerated=tval.get_int();
			}
			
			std::cout << std::endl;
			std::cout << GetTimeStr(time(0)) << std::endl;
			std::cout << "Server Status : " << clients << " clients, " << khashmeta << " khash/s" << std::endl;
			std::cout << blocksgenerated << " blocks generated since " << startuptimestr << " UTC" << std::endl;
			std::cout << "Server reports my khash/s as " << clientkhashmeta << std::endl;
		}
	}
	else
	{
		std::cout << "Server sent invalid message.  Disconnecting." << std::endl;
	}
}
Exemple #2
0
bool ProcessBlockMsg(BTCMessage &msg)
{
	if (!msg.VerifyChecksum() || msg.vPayload.size()<=80)	// something wrong with checksum or length, can't process it
		return false;

	// calculate hash of this block
	uint256 curBlockHash = Hash(msg.vPayload.begin(), msg.vPayload.begin()+80);

	mysqlpp::Connection *my_conn = mydb.GrabConnection();	// get a database connection
	if (mydb.IsBlockHashKnown(my_conn, &curBlockHash)) {
		mydb.ReleaseConnection(my_conn);
		return true;			// nothing to do, as we got already this block somehow (from previous download or unsollicited message)
	}
	// now do the real stuff: block is not known yet
	ChainBlocks newBlock(0);	// create new block to add, we don't know ID yet
	newBlock.hash.assign((char *)curBlockHash.begin(), 32);
	newBlock.prevhash.assign((char *)&msg.vPayload[4], 32);	// first 4 bytes are version number, not checked for now
	newBlock.height=-2;			// height not yet known

	// --> see if prevBlockHash exists in existing blocks in ChainBlocks
	int iPrevHeight = mydb.GetBlockHeightFromHash(my_conn, newBlock.prevhash);
	if (iPrevHeight>=-1) {					// this new block has a previous hash of a temporary block with known height
		newBlock.height=iPrevHeight+1;		// so height of this block is known
		int iBestHeight=mydb.GetBestHeightKnown(my_conn);
		if (newBlock.height<=iBestHeight) {	// height of new block is less or equal then best known temporary --> discard all temp blocks with this height and above
			for (iPrevHeight=iBestHeight; iPrevHeight>=newBlock.height; iPrevHeight--)
				mydb.DeleteBlockDataOfHeight(my_conn, iPrevHeight);
		}
	}
	else {									// this new block has unknown height
		if (BTCnode.GetNodeStatus()>4) {				// we have an up-to-date block chain, so this is unusual, probably a block fork happened
			int iSafeHeight = mydb.GetSafeHeight(my_conn);
			if (iSafeHeight>0) {
				uint256 hash_start;
				if (mydb.GetBlockHashFromHeight(my_conn, iSafeHeight, hash_start)) {
					if (BTCnode.SendMsg_GetBlocks(hash_start, uint256(0))) {
						BTCnode.Peer_AskedBlockHeight = iSafeHeight + 500;  // we asked up to 500 new blocks
					}
				}
			}
		}
	}
	newBlock.status = (newBlock.height>=0)? 1 : 0;

	// --> add it to ChainBlocks
	if (mydb.AddBlockToChain(my_conn, newBlock)) {	// block added successfully
		// --> add tx's to ChainTxIns and ChainTxOuts
		std::vector<unsigned char>::iterator itTxBegin;
		std::vector<unsigned char>::iterator it=msg.vPayload.begin()+80;	// we start at 80 offset with TX data
		int iNrTransactions = (int)msg.GetVarInt(it);						// retrieve the varint indicating number of transactions
		int iEachTx;
		mysqlpp::Transaction myTrans(*my_conn);
		for (iEachTx=0; iEachTx < iNrTransactions; iEachTx++) {		// loop through each transaction
			itTxBegin = it;											// remember where current transaction starts for hash calculation later on
			ChainTxs newTx(newBlock.ID, iEachTx);					// insert incomplete Tx as we need referencial integrity on depending TxIns and TxOuts
			if (mydb.InsertChainTx(my_conn, newTx)) {
				it +=4;		// skip version number
				int iNrTxIO = (int)msg.GetVarInt(it);				// number of input transactions
				int iEachTxIO;
				for (iEachTxIO=0; iEachTxIO < iNrTxIO; iEachTxIO++) {
					// loop through each "in" transaction
					// we retain only the "OutPoint" Structure, we expect signature to be valid (otherwise it wouldn't be in a block)
					ChainTxIns newTxIn(newBlock.ID, iEachTx, iEachTxIO);		// create record data variable
					newTxIn.opHash.assign((char *)&it[0],32);	// OutPoint hash
					memcpy(&newTxIn.opN, &it[32], 4);			// OutPoint index number
					it+=36;		// skip OutPoint
					int iVI = (int)msg.GetVarInt(it);			// length of script
					it+=iVI;	// skip script
					it+=4;		// skip sequence
					mydb.InsertChainTxIn(my_conn, newTxIn);
				}
				iNrTxIO = (int)msg.GetVarInt(it);				// number of output transactions
				for (iEachTxIO=0; iEachTxIO < iNrTxIO; iEachTxIO++) {
					// loop through each "out" transaction
					// we examine the script and extract: value, type and hash(es)
					ChainTxOuts newTxOut(newBlock.ID, iEachTx, iEachTxIO);		// create record data variable
					memcpy(&newTxOut.value, &it[0], 8);			// value of output
					it+=8;		// skip the value
					newTxOut.txType=0;
					int iVI = (int)msg.GetVarInt(it);			// length of script
					// examine script to find out the type of transactions
					if (it[0]<OP_PUSHDATA1) {	// script starts with immediate data
						if (it[0]==65 && it[66]==OP_CHECKSIG) {		// transaction is "Transaction to IP address/ Generation"
							vector<unsigned char> vPubKey(it+1, it+66);	// extract Public Key from Msg
							uint160 uKeyHash = Hash160(vPubKey);
							newTxOut.smartID.assign((const char *)&uKeyHash, 20);		// copy it into record
							newTxOut.smartIDAdr = Hash160ToAddress(uKeyHash);			// store base58 address too
							newTxOut.storeID.it_is_null();								// storeID is not used
							newTxOut.txType=2;
						}
					}
					else {
						if (it[0]==OP_DUP && it[1]==OP_HASH160 && it[2]==20 && it[23]==OP_EQUALVERIFY) { // transaction start = std Tx to BitcoinAddress
							if (it[24]==OP_CHECKSIG) {	// it is standard transaction
								vector<unsigned char> vKeyHash(it+3, it+23);			// extract hash from Msg
								newTxOut.smartID.assign((const char *)&it[3], 20);		// extract hash from Msg
								newTxOut.smartIDAdr = Hash160ToAddress( uint160(vKeyHash) );
								newTxOut.storeID.it_is_null();
								newTxOut.txType=1;
							}
							else
								if (1==0) {	// our new type of transaction
									newTxOut.txType=3;
								}
						}
					}
					it+=iVI;	// skip script
					if (newTxOut.txType!=0)
						mydb.InsertChainTxOut(my_conn, newTxOut);
				} // END for each TxOut
				it+=4;		// skip lock time
			} // END if insert chain ok
			// iterator it points now to the end of the transaction, now we can calculate the hash of it
			curBlockHash = Hash(itTxBegin, it);						// calculate it
			newTx.txHash.assign((const char *)&curBlockHash, 32);	// transfer to record
			mydb.UpdateChainTx(my_conn, newTx);						// update the already inserted record
			mydb.TxUnconfirmedDies(my_conn, newTx.txHash);			// set life=0 for this unconfirmed tx
		} // END loop Tx
		myTrans.commit();
	} // END add block
	mydb.TxUnconfirmedAges(my_conn);
	mydb.ReleaseConnection(my_conn);
	return true;
}