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; } }
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; }