github.com/igggame/nebulas-go@v2.1.0+incompatible/nbre/fs/ir_manager/ir_manager.cpp (about)

     1  // Copyright (C) 2018 go-nebulas authors
     2  //
     3  // This file is part of the go-nebulas library.
     4  //
     5  // the go-nebulas library is free software: you can redistribute it and/or
     6  // modify
     7  // it under the terms of the GNU General Public License as published by
     8  // the Free Software Foundation, either version 3 of the License, or
     9  // (at your option) any later version.
    10  //
    11  // the go-nebulas library is distributed in the hope that it will be useful,
    12  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  // GNU General Public License for more details.
    15  //
    16  // You should have received a copy of the GNU General Public License
    17  // along with the go-nebulas library.  If not, see
    18  // <http://www.gnu.org/licenses/>.
    19  //
    20  
    21  #include "fs/ir_manager/ir_manager.h"
    22  #include "common/byte.h"
    23  #include "common/common.h"
    24  #include "common/configuration.h"
    25  #include "common/version.h"
    26  #include "fs/bc_storage_session.h"
    27  #include "fs/ir_manager/api/ir_api.h"
    28  #include "fs/ir_manager/ir_manager_helper.h"
    29  #include "fs/storage_holder.h"
    30  #include "jit/cpp_ir.h"
    31  #include "jit/jit_driver.h"
    32  #include "runtime/dip/dip_handler.h"
    33  #include "runtime/version.h"
    34  #include "util/json_parser.h"
    35  #include <boost/format.hpp>
    36  #include <ff/functionflow.h>
    37  
    38  namespace neb {
    39  namespace fs {
    40  
    41  ir_manager::ir_manager() {
    42    m_storage = storage_holder::instance().nbre_db_ptr();
    43  }
    44  
    45  ir_manager::~ir_manager() { m_storage->close_database(); }
    46  
    47  std::unique_ptr<nbre::NBREIR> ir_manager::read_ir(const std::string &name,
    48                                                    version_t version) {
    49    return ir_api::get_ir(name, version, m_storage).second;
    50  }
    51  
    52  std::unique_ptr<std::vector<nbre::NBREIR>>
    53  ir_manager::read_irs(const std::string &name, block_height_t height,
    54                       bool depends) {
    55    auto irs = std::make_unique<std::vector<nbre::NBREIR>>();
    56  
    57    neb::bytes bytes_versions;
    58    try {
    59      bytes_versions = m_storage->get(name);
    60    } catch (const std::exception &e) {
    61      LOG(INFO) << "get ir " << name << " failed " << e.what();
    62      return irs;
    63    }
    64  
    65    auto versions_ptr = ir_api::get_ir_versions(name, m_storage);
    66    for (auto version : *versions_ptr) {
    67      read_ir_depends(name, version, height, depends, *irs);
    68      if (!irs->empty()) {
    69        break;
    70      }
    71    }
    72  
    73    return irs;
    74  }
    75  
    76  void ir_manager::read_ir_depends(const std::string &name, version_t version,
    77                                   block_height_t height, bool depends,
    78                                   std::vector<nbre::NBREIR> &irs) {
    79  
    80    if (name == neb::configuration::instance().rt_module_name() &&
    81        neb::rt::get_version() < neb::version(version)) {
    82      throw std::runtime_error("need to update nbre runtime version");
    83    }
    84  
    85    std::unique_ptr<nbre::NBREIR> nbre_ir = std::make_unique<nbre::NBREIR>();
    86    std::unordered_set<std::string> ir_set;
    87    std::queue<std::pair<std::string, version_t>> q;
    88    q.push(std::make_pair(name, version));
    89  
    90    while (!q.empty()) {
    91      auto &ele = q.front();
    92      q.pop();
    93      std::stringstream ss;
    94      ss << ele.first << ele.second;
    95  
    96      if (ir_set.find(ss.str()) == ir_set.end()) {
    97        ir_set.insert(ss.str());
    98        neb::bytes nbre_bytes;
    99        try {
   100          nbre_bytes = m_storage->get(ss.str());
   101        } catch (const std::exception &e) {
   102          LOG(INFO) << "get ir " << ele.first << " failed " << e.what();
   103          return;
   104        }
   105  
   106        bool ret = nbre_ir->ParseFromArray(nbre_bytes.value(), nbre_bytes.size());
   107        if (!ret) {
   108          throw std::runtime_error("parse nbre failed");
   109        }
   110  
   111        if (nbre_ir->height() <= height) {
   112          if (depends) {
   113            for (auto &deps : nbre_ir->depends()) {
   114              q.push(std::make_pair(deps.name(), deps.version()));
   115            }
   116          }
   117          irs.push_back(*nbre_ir);
   118        }
   119      }
   120    }
   121  }
   122  
   123  void ir_manager::parse_irs(
   124      util::wakeable_queue<std::shared_ptr<nbre_ir_transactions_req>> &q_txs) {
   125  
   126    ir_manager_helper::load_auth_table(m_storage, m_auth_table);
   127    block_height_t last_height = ir_manager_helper::nbre_block_height(m_storage);
   128  
   129    while (!q_txs.empty()) {
   130      auto ele = q_txs.try_pop_front();
   131      if (!ele.first) {
   132        break;
   133      }
   134  
   135      auto h = ele.second->get<p_height>();
   136      if (h < last_height + 1) {
   137        continue;
   138      }
   139      if (h > last_height + 1) {
   140        parse_when_missing_block(last_height + 1, h);
   141      }
   142  
   143      const auto &txs = ele.second->get<p_ir_transactions>();
   144      parse_next_block(h, txs);
   145      last_height = h;
   146    }
   147  }
   148  
   149  void ir_manager::parse_when_missing_block(block_height_t start_height,
   150                                            block_height_t end_height) {
   151    std::string ir_tx_type = neb::configuration::instance().ir_tx_payload_type();
   152  
   153    for (block_height_t h = start_height; h < end_height; h++) {
   154      auto block = blockchain::load_block_with_height(h);
   155      std::vector<corepb::Transaction> txs;
   156  
   157      for (auto &tx : block->transactions()) {
   158        auto &data = tx.data();
   159        const std::string &type = data.type();
   160        if (type == ir_tx_type) {
   161          txs.push_back(tx);
   162        }
   163      }
   164      parse_with_height(h, txs);
   165    }
   166  }
   167  
   168  void ir_manager::parse_next_block(block_height_t height,
   169                                    const std::vector<std::string> &txs_seri) {
   170    std::vector<corepb::Transaction> txs;
   171    if (txs_seri.empty()) {
   172      parse_with_height(height, txs);
   173      return;
   174    }
   175  
   176    for (auto &tx_seri : txs_seri) {
   177      auto tx_bytes = string_to_byte(tx_seri);
   178      std::unique_ptr<corepb::Transaction> tx =
   179          std::make_unique<corepb::Transaction>();
   180      bool ret = tx->ParseFromArray(tx_bytes.value(), tx_bytes.size());
   181      if (!ret) {
   182        throw std::runtime_error("parse transaction failed");
   183      }
   184      txs.push_back(*tx);
   185    }
   186    parse_with_height(height, txs);
   187  }
   188  
   189  void ir_manager::parse_with_height(
   190      block_height_t height, const std::vector<corepb::Transaction> &txs) {
   191  
   192    std::string failed_flag =
   193        neb::configuration::instance().nbre_failed_flag_name();
   194  
   195    if (!ir_manager_helper::has_failed_flag(m_storage, failed_flag)) {
   196      ir_manager_helper::set_failed_flag(m_storage, failed_flag);
   197      parse_irs_by_height(height, txs);
   198    }
   199    m_storage->put(
   200        std::string(neb::configuration::instance().nbre_max_height_name(),
   201                    std::allocator<char>()),
   202        neb::number_to_byte<neb::bytes>(height));
   203    ir_manager_helper::del_failed_flag(m_storage, failed_flag);
   204  
   205    neb::rt::dip::dip_handler::instance().start(height);
   206  }
   207  
   208  void ir_manager::parse_irs_by_height(
   209      block_height_t height, const std::vector<corepb::Transaction> &txs) {
   210  
   211    for (auto &tx : txs) {
   212      auto &data = tx.data();
   213      const std::string &type = data.type();
   214  
   215      // ignore transaction other than transaction `protocol`
   216      std::string ir_tx_type =
   217          neb::configuration::instance().ir_tx_payload_type();
   218      if (type != ir_tx_type) {
   219        LOG(INFO) << "ignore ir with type: " << type;
   220        continue;
   221      }
   222  
   223      boost::property_tree::ptree pt;
   224      neb::util::json_parser::read_json(data.payload(), pt);
   225      neb::bytes payload_bytes =
   226          neb::bytes::from_base64(pt.get<std::string>("Data"));
   227  
   228      std::unique_ptr<nbre::NBREIR> nbre_ir = std::make_unique<nbre::NBREIR>();
   229      bool ret =
   230          nbre_ir->ParseFromArray(payload_bytes.value(), payload_bytes.size());
   231      if (!ret) {
   232        LOG(ERROR) << "parse transaction payload failed " << type;
   233        throw std::runtime_error("parse transaction payload failed");
   234      }
   235  
   236      const std::string &name = nbre_ir->name();
   237      version_t version = nbre_ir->version();
   238      if (ir_api::ir_exist(name, version, m_storage)) {
   239        LOG(INFO) << "ignore ir name: " << name << " with version: " << version;
   240        continue;
   241      }
   242  
   243      address_t from = to_address(tx.from());
   244      // deploy auth table
   245      if (neb::configuration::instance().auth_module_name() == name &&
   246          neb::configuration::instance().admin_pub_addr() == from) {
   247        ir_manager_helper::compile_payload_code(nbre_ir.get(), payload_bytes);
   248        ir_manager_helper::deploy_auth_table(m_storage, *nbre_ir.get(),
   249                                             m_auth_table, payload_bytes);
   250        continue;
   251      }
   252  
   253      auto it = m_auth_table.find(std::make_tuple(name, from));
   254      // ir not in auth table
   255      if (it == m_auth_table.end()) {
   256        LOG(INFO) << boost::str(
   257            boost::format("tuple <%1%, %2%> not in auth table") % name %
   258            std::to_string(from));
   259        ir_manager_helper::show_auth_table(m_auth_table);
   260        continue;
   261      }
   262      block_height_t ht = nbre_ir->height();
   263      // ir in auth table but already invalid
   264      if (ht < std::get<0>(it->second) || ht >= std::get<1>(it->second)) {
   265        LOG(INFO) << "ir already becomes invalid";
   266        continue;
   267      }
   268      ir_manager_helper::compile_payload_code(nbre_ir.get(), payload_bytes);
   269  
   270      // update ir list and versions
   271      ir_manager_helper::update_ir_list(name, m_storage);
   272      ir_manager_helper::update_ir_versions(name, version, m_storage);
   273  
   274      // deploy ir
   275      ir_manager_helper::deploy_ir(name, version, payload_bytes, m_storage);
   276  
   277      deploy_if_dip(name, version, ht);
   278    }
   279  }
   280  
   281  void ir_manager::deploy_if_dip(const std::string &name, version_t version,
   282                                 block_height_t available_height) {
   283    if (name != std::string("dip")) {
   284      return;
   285    }
   286    neb::rt::dip::dip_handler::instance().deploy(version, available_height);
   287  }
   288  
   289  } // namespace fs
   290  } // namespace neb