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