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