Example #1
0
int main(int argc, char* argv[])
{
	if(argc == 1) {
		help_(argv[0]);
		return 0;
	}

	options	opts;

	// 設定ファイルの読み込み
	std::string conf_path;
	if(utils::probe_file(conf_file_)) {  // カレントにあるか?
		conf_path = conf_file_;
	} else {  // コマンド、カレントから読んでみる
		conf_path = get_current_path_(argv[0]) + '/' + conf_file_;
	}	
	if(conf_in_.load(conf_path)) {
		auto defa = conf_in_.get_default();
		opts.device = defa.device_;
#ifdef __CYGWIN__
		opts.platform = "Cygwin";
		opts.com_path = defa.port_win_;
		opts.com_speed = defa.speed_win_;
#endif
#ifdef __APPLE__
		opts.platform = "OS-X";
		opts.com_path = defa.port_osx_;
		opts.com_speed = defa.speed_osx_;
#endif
#ifdef __linux__
		opts.platform = "Linux";
		opts.com_path = defa.port_linux_;
		opts.com_speed = defa.speed_linux_;
#endif
		if(opts.com_path.empty()) {
			opts.com_path = defa.port_;
		}
		if(opts.com_speed.empty()) {
			opts.com_speed = defa.speed_;
		}
		opts.id_val = defa.id_;
	} else {
		std::cerr << "Configuration file can't load: '" << conf_path << '\'' << std::endl;
		return -1;
	}

   	// コマンドラインの解析
	bool opterr = false;
	for(int i = 1; i < argc; ++i) {
		const std::string p = argv[i];
		if(p[0] == '-') {
			if(p == "--verbose") opts.verbose = true;
			else if(p == "-s") opts.br = true;
			else if(p.find("--speed=") == 0) {
				opts.com_speed = &p[std::strlen("--speed=")];
			} else if(p == "-d") opts.dv = true;
			else if(p.find("--device=") == 0) {
				opts.device = &p[std::strlen("--device=")];
			} else if(p == "-P") opts.dp = true;
			else if(p.find("--port=") == 0) {
				opts.com_path = &p[std::strlen("--port=")];
///			} else if(p == "-a") {
///				opts.area = true;
///			} else if(p.find("--area=") == 0) {
///				if(!opts.set_area_(&p[7])) {
///					opterr = true;
///				}
//			} else if(p == "-r" || p == "--read") {
//				opts.read = true;
//			} else if(p == "-i") {
//				opts.id = true;
//			} else if(p.find("--id=") == 0) {
//				opts.id_val = &p[std::strlen("--id=")];
			} else if(p == "-w" || p == "--write") {
				opts.write = true;
			} else if(p == "-v" || p == "--verify") {
				opts.verify = true;
			} else if(p == "--progress") {
				opts.progress = true;
			} else if(p == "--device-list") {
				opts.device_list = true;
			} else if(p == "-e" || p == "--erase") {
				opts.erase = true;
///			} else if(p == "--erase-rom") opts.erase_rom = true;
///			} else if(p == "--erase-data") opts.erase_data = true;
///			} else if(p == "--erase-all" || p == "--erase-chip") {
//				opts.erase_rom = true;
//				opts.erase_data = true;
			} else if(p == "-h" || p == "--help") {
				opts.help = true;
			} else {
				opterr = true;
			}
		} else {
			if(!opts.set_str(p)) {
				opterr = true;
			}
		}
		if(opterr) {
			std::cerr << "Option error: '" << p << "'" << std::endl;
			opts.help = true;
		}
	}
	if(opts.verbose) {
		std::cout << "# Platform: '" << opts.platform << '\'' << std::endl;
		std::cout << "# Configuration file path: '" << conf_path << '\'' << std::endl;
		std::cout << "# Device: '" << opts.device << '\'' << std::endl;
		std::cout << "# Serial port path: '" << opts.com_path << '\'' << std::endl;
		std::cout << "# Serial port speed: " << opts.com_speed << std::endl;
	}

	// HELP 表示
	if(opts.help || opts.com_path.empty() || (opts.inp_file.empty() && !opts.device_list)
///			&& opts.sequrity_set.empty() && !opts.sequrity_get && !opts.sequrity_release)
		|| opts.com_speed.empty() || opts.device.empty()) {
		if(opts.device.empty()) {
			std::cout << "Device name null." << std::endl;
		}
		if(opts.com_speed.empty()) {
			std::cout << "Serial speed none." << std::endl;
		}
		help_(argv[0]);
		return 0;
	}

	// デバイス・リスト表示
	if(opts.device_list) {
		for(const auto& s : conf_in_.get_device_list()) {
			std::cout << s << std::endl;
		}
	}

	// 入力ファイルの読み込み
	uint32_t pageall = 0;
	if(!opts.inp_file.empty()) {
		if(opts.verbose) {
			std::cout << "# Input file path: '" << opts.inp_file << '\'' << std::endl;
		}
		if(!motsx_.load(opts.inp_file)) {
			std::cerr << "Can't open input file: '" << opts.inp_file << "'" << std::endl;
			return -1;
		}
		pageall = motsx_.get_total_page();
		if(opts.verbose) {
			motsx_.list_area_map("# ");
		}
	}

    // Windwos系シリアル・ポート(COMx)の変換
    if(!opts.com_path.empty() && opts.com_path[0] != '/') {
		std::string s = utils::to_lower_text(opts.com_path);
        if(s.size() > 3 && s[0] == 'c' && s[1] == 'o' && s[2] == 'm') {
            int val;
            if(utils::string_to_int(&s[3], val)) {
                if(val >= 1 ) {
                    --val;
                    opts.com_name = opts.com_path;
                    opts.com_path = "/dev/ttyS" + (boost::format("%d") % val).str();
                }
            }
        }
		if(opts.verbose) {
			std::cout << "# Serial port alias: " << opts.com_name << " ---> " << opts.com_path << std::endl;
		}
    }
	if(opts.com_path.empty()) {
		std::cerr << "Serial port path not found." << std::endl;
		return -1;
	}
	if(opts.verbose) {
		std::cout << "# Serial port path: '" << opts.com_path << '\'' << std::endl;
	}
	int com_speed = 0;
	if(!utils::string_to_int(opts.com_speed, com_speed)) {
		std::cerr << "Serial speed conversion error: '" << opts.com_speed << '\'' << std::endl;
		return -1;		
	}

	if(!opts.erase && !opts.write && !opts.verify) return 0;
//		&& opts.sequrity_set.empty() && !opts.sequrity_get && !opts.sequrity_release) return 0;

	rx::protocol::rx_t rx;
	{
		rx.verbose_ = opts.verbose;

		rx.cpu_type_ = opts.device;

		if(rx.cpu_type_ == "RX63T") {
			// rx.master_ = 1200;  // 12.00MHz
			// rx.sys_div_ = 8;    // x8 (96MHz)
			// rx.ext_div_ = 4;    // x4 (48MHz)
			auto devt = conf_in_.get_device();
			int32_t val = 0;;
			if(!utils::string_to_int(devt.clock_, val)) {
				std::cerr << "RX63T 'clock' tag conversion error: '" << devt.clock_ << '\'' << std::endl;
				return -1;
			}
			rx.master_ = val;

			if(!utils::string_to_int(devt.divide_sys_, val)) {
				std::cerr << "RX63T 'divide_sys' tag conversion error: '" << devt.divide_sys_ << '\'' << std::endl;
				return -1;
			}
			rx.sys_div_ = val;

			if(!utils::string_to_int(devt.divide_ext_, val)) {
				std::cerr << "RX63T 'divide_ext' tag conversion error: '" << devt.divide_ext_ << '\'' << std::endl;
				return -1;
			}
			rx.ext_div_ = val;
		}
	}

	rx::prog prog_(opts.verbose);
	if(!prog_.start(opts.com_path, com_speed, rx)) {
		prog_.end();
		return -1;
	}

	//=====================================
	if(opts.erase) {  // erase
		auto areas = motsx_.create_area_map();

		if(opts.progress) {
			std::cout << "Erase:  " << std::flush;
		}

		page_t page;
		for(const auto& a : areas) {
			uint32_t adr = a.min_ & 0xffffff00;
			uint32_t len = 0;
			while(len < (a.max_ - a.min_ + 1)) {
				if(opts.progress) {
					progress_(pageall, page);
				}
				if(!prog_.erase_page(adr)) {  // 256 バイト単位で消去要求を送る
					prog_.end();
					return -1;
				}
				adr += 256;
				len += 256;
				++page.n;
			}
		}
		if(opts.progress) {
			std::cout << std::endl << std::flush;
		}
	}

	//=====================================
	if(opts.write) {  // write
		auto areas = motsx_.create_area_map();
		if(!areas.empty()) {
			if(!prog_.start_write(true)) {
				prog_.end();
				return -1;
			}
		}
		
		if(opts.progress) {
			std::cout << "Write:  " << std::flush;
		}
		page_t page;
		for(const auto& a : areas) {
			uint32_t adr = a.min_ & 0xffffff00;
			uint32_t len = 0;
			while(len < (a.max_ - a.min_ + 1)) {
				if(opts.progress) {
					progress_(pageall, page);
				}
				/// std::cout << boost::format("%08X to %08X") % adr % (adr + 255) << std::endl;
				auto mem = motsx_.get_memory(adr);
				if(!prog_.write(adr, &mem[0])) {
					prog_.end();
					return -1;
				}
				adr += 256;
				len += 256;
				++page.n;
			}
		}
		if(opts.progress) {
			std::cout << std::endl << std::flush;
		}
		if(!prog_.final_write()) {
			prog_.end();
			return -1;
		}
	}

	//=====================================
	if(opts.verify) {  // verify
		auto areas = motsx_.create_area_map();
		if(opts.progress) {
			std::cout << "Verify: " << std::flush;
		}
		page_t page;
		for(const auto& a : areas) {
			uint32_t adr = a.min_ & 0xffffff00;
			uint32_t len = 0;
			while(len < (a.max_ - a.min_ + 1)) {
				if(opts.progress) {
					progress_(pageall, page);
				}
				/// std::cout << boost::format("%08X to %08X") % adr % (adr + 255) << std::endl;
				auto mem = motsx_.get_memory(adr);
				if(!prog_.verify_page(adr, &mem[0])) {
					prog_.end();
					return -1;
				}
				adr += 256;
				len += 256;
				++page.n;
			}
		}
		if(opts.progress) {
			std::cout << std::endl << std::flush;
		}
	}

	prog_.end();
}
void BlockchainScanner::writeBlockData(
   shared_ptr<BatchLink> batchLinkPtr)
{
   auto getGlobalOffsetForBlock = [&](unsigned height)->size_t
   {
      auto& header = blockchain_->getHeaderByHeight(height);
      size_t val = header.getBlockFileNum();
      val *= 128 * 1024 * 1024;
      val += header.getOffset();
      return val;
   };

   ProgressCalculator calc(getGlobalOffsetForBlock(
      blockchain_->top().getBlockHeight()));
   calc.advance(getGlobalOffsetForBlock(startAt_));

   auto writeHintsLambda = 
      [&](const vector<shared_ptr<BlockDataBatch>>& batchVec)->void
   { processAndCommitTxHints(batchVec); };

   while (1)
   {
      if (batchLinkPtr == nullptr)
         break;
      
      {
         unique_lock<mutex> batchIsReady(batchLinkPtr->readyToWrite_);
      }

      if (batchLinkPtr->next_ == nullptr)
         break;

      //start txhint writer thread
      thread writeHintsThreadId = 
         thread(writeHintsLambda, batchLinkPtr->batchVec_);

      auto& topheader = 
         blockchain_->getHeaderByHash(batchLinkPtr->topScannedBlockHash_);
      auto topHeight = topheader.getBlockHeight();
      
      //serialize data
      map<BinaryData, BinaryWriter> serializedSubSSH;
      map<BinaryData, BinaryWriter> serializedStxo;
      map<BinaryData, BinaryWriter> serializedTxHints;
      map<BinaryData, StoredTxHints> txHints;

      {
         for (auto& batchPtr : batchLinkPtr->batchVec_)
         {
            for (auto& ssh : batchPtr->ssh_)
            {
               for (auto& subssh : ssh.second.subHistMap_)
               {
                  //TODO: modify subssh serialization to fit our needs

                  BinaryWriter subsshkey;
                  subsshkey.put_uint8_t(DB_PREFIX_SCRIPT);
                  subsshkey.put_BinaryData(ssh.first);
                  subsshkey.put_BinaryData(subssh.first);

                  auto& bw = serializedSubSSH[subsshkey.getDataRef()];
                  subssh.second.serializeDBValue(
                     bw, db_, ARMORY_DB_BARE, DB_PRUNE_NONE);
               }
            }

            for (auto& utxomap : batchPtr->utxos_)
            {
               auto&& txHashPrefix = utxomap.first.getSliceCopy(0, 4);
               StoredTxHints& stxh = txHints[txHashPrefix];
               if (stxh.txHashPrefix_.getSize() == 0)
                  stxh.txHashPrefix_ = txHashPrefix;


               for (auto& utxo : utxomap.second)
               {
                  stxh.dbKeyList_.push_back(utxo.second.getDBKeyOfParentTx());

                  auto& bw = serializedStxo[utxo.second.getDBKey()];
                  utxo.second.serializeDBValue(
                     bw, ARMORY_DB_BARE, DB_PRUNE_NONE, true);
               }
               
               stxh.preferredDBKey_ = stxh.dbKeyList_.front();
            }
         }
      }

      //we've serialized utxos, now let's do another pass for spent txouts
      //to make sure they overwrite utxos that were found and spent within
      //the same batch
      for (auto& batchPtr : batchLinkPtr->batchVec_)
      {
         for (auto& stxo : batchPtr->spentTxOuts_)
         {
            auto& bw = serializedStxo[stxo.getDBKey()];
            if (bw.getSize() > 0)
               bw.reset();
            stxo.serializeDBValue(
               bw, ARMORY_DB_BARE, DB_PRUNE_NONE, true);
         }
      }

      //write data
      {
         //txouts
         LMDBEnv::Transaction tx;
         db_->beginDBTransaction(&tx, STXO, LMDB::ReadWrite);

         for (auto& stxo : serializedStxo)
         { 
            //TODO: dont rewrite utxos, check if they are already in DB first
            db_->putValue(STXO,
               stxo.first.getRef(),
               stxo.second.getDataRef());
         }
      }

      {
         //subssh
         LMDBEnv::Transaction tx;
         db_->beginDBTransaction(&tx, SUBSSH, LMDB::ReadWrite);

         for (auto& subssh : serializedSubSSH)
         {
            db_->putValue(
               SUBSSH,
               subssh.first.getRef(),
               subssh.second.getDataRef());
         }

         //update SUBSSH sdbi
         StoredDBInfo sdbi;
         db_->getStoredDBInfo(SUBSSH, sdbi);
         sdbi.topBlkHgt_ = batchLinkPtr->batchVec_[0]->end_;
         sdbi.topScannedBlkHash_ = batchLinkPtr->topScannedBlockHash_;
         db_->putStoredDBInfo(SUBSSH, sdbi);
      }

      //wait on writeHintsThreadId
      if (writeHintsThreadId.joinable())
         writeHintsThreadId.join();

      LOGINFO << "scanned from height #" << batchLinkPtr->batchVec_[0]->start_
         << " to #" << batchLinkPtr->batchVec_[0]->end_;

      size_t progVal = getGlobalOffsetForBlock(batchLinkPtr->batchVec_[0]->end_);
      calc.advance(progVal);
      if (reportProgress_)
         progress_(BDMPhase_Rescan,
         calc.fractionCompleted(), calc.remainingSeconds(),
         progVal);

      batchLinkPtr = batchLinkPtr->next_;
   }
}