github.com/igggame/nebulas-go@v2.1.0+incompatible/nbre/fs/blockchain/trie/trie.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/blockchain/trie/trie.h" 22 #include "fs/bc_storage_session.h" 23 #include <exception> 24 25 namespace neb { 26 namespace fs { 27 28 trie_node::trie_node(trie_node_type type) { change_to_type(type); } 29 trie_node::trie_node(const neb::bytes &triepb_bytes) { 30 31 std::unique_ptr<triepb::Node> triepb_node_ptr = 32 std::make_unique<triepb::Node>(); 33 34 bool ret = triepb_node_ptr->ParseFromArray(triepb_bytes.value(), 35 triepb_bytes.size()); 36 if (!ret) { 37 throw std::runtime_error("parse triepb node failed"); 38 } 39 40 for (const std::string &v : triepb_node_ptr->val()) { 41 m_val.push_back(neb::string_to_byte(v)); 42 } 43 } 44 45 trie_node::trie_node(const std::vector<neb::bytes> &val) : m_val(val) {} 46 47 trie_node_type trie_node::get_trie_node_type() { 48 49 if (m_val.size() == 16) { 50 return trie_node_branch; 51 } 52 if (m_val.size() == 3 && !m_val[0].empty()) { 53 return static_cast<trie_node_type>(m_val[0][0]); 54 } 55 return trie_node_unknown; 56 } 57 58 void trie_node::change_to_type(trie_node_type new_type) { 59 if (new_type == get_trie_node_type()) 60 return; 61 if (new_type == trie_node_extension && 62 get_trie_node_type() == trie_node_leaf) { 63 m_val.clear(); 64 return; 65 } 66 if (new_type == trie_node_leaf && 67 get_trie_node_type() == trie_node_extension) { 68 m_val.clear(); 69 return; 70 } 71 72 if (new_type == trie_node_extension || new_type == trie_node_leaf) { 73 m_val.resize(3); 74 m_val.shrink_to_fit(); 75 return; 76 } 77 if (new_type == trie_node_leaf) { 78 m_val.resize(16); 79 m_val.shrink_to_fit(); 80 } 81 } 82 83 std::unique_ptr<triepb::Node> trie_node::to_proto() const { 84 auto ret = std::make_unique<triepb::Node>(); 85 for (const neb::bytes &v : m_val) { 86 std::string *val = ret->add_val(); 87 *val = std::to_string(v); 88 } 89 return ret; 90 } 91 92 trie::trie(const hash_t &hash) : m_root_hash(hash) {} 93 94 trie::trie() {} 95 96 trie_node_ptr trie::create_node(const std::vector<neb::bytes> &val) { 97 auto ret = std::make_unique<trie_node>(val); 98 commit_node(ret.get()); 99 return ret; 100 } 101 102 void trie::commit_node(trie_node *node) { 103 if (node == nullptr) { 104 return; 105 } 106 auto pb = node->to_proto(); 107 size_t s = pb->ByteSizeLong(); 108 neb::bytes bs(s); 109 pb->SerializeToArray(bs.value(), s); 110 111 node->hash() = crypto::sha3_256_hash(bs); 112 113 bc_storage_session::instance().put_bytes( 114 bytes(node->hash().value(), node->hash().size()), bs); 115 } 116 117 hash_t trie::put(const hash_t &key, const neb::bytes &val) { 118 auto new_hash = update(m_root_hash, key_to_route(key), val); 119 m_root_hash = new_hash; 120 return new_hash; 121 } 122 123 hash_t trie::update(const hash_t &root, const neb::bytes &route, 124 const neb::bytes &val) { 125 if (root.empty()) { 126 std::vector<neb::bytes> value( 127 {number_to_byte<bytes>(trie_node_leaf), route, val}); 128 auto node = create_node(value); 129 return node->hash(); 130 } 131 132 auto root_node = fetch_node(root); 133 auto type = root_node->get_trie_node_type(); 134 switch (type) { 135 case trie_node_extension: 136 return update_when_meet_ext(root_node.get(), route, val); 137 break; 138 case trie_node_leaf: 139 return update_when_meet_leaf(root_node.get(), route, val); 140 break; 141 case trie_node_branch: 142 return update_when_meet_branch(root_node.get(), route, val); 143 break; 144 default: 145 throw std::invalid_argument("unknown node type"); 146 } 147 } 148 hash_t trie::update_when_meet_branch(trie_node *root_node, 149 const neb::bytes &route, 150 const neb::bytes &val) { 151 auto new_hash = update(to_fix_bytes<hash_t>(root_node->val_at(route[0])), 152 neb::bytes(route.value() + 1, route.size() - 1), val); 153 154 root_node->val_at(route[0]) = from_fix_bytes(new_hash); 155 commit_node(root_node); 156 return root_node->hash(); 157 } 158 159 hash_t trie::update_when_meet_ext(trie_node *root_node, const neb::bytes &route, 160 const neb::bytes &val) { 161 bytes path = root_node->val_at(1); 162 bytes next = root_node->val_at(2); 163 if (path.size() > route.size()) { 164 throw std::invalid_argument("wrong key, too short"); 165 } 166 auto match_len = prefix_len(path, route); 167 if (match_len == path.size()) { 168 auto new_hash = 169 update(to_fix_bytes<hash_t>(next), 170 bytes(route.value() + match_len, route.size() - match_len), val); 171 root_node->val_at(2) = from_fix_bytes(new_hash); 172 commit_node(root_node); 173 return root_node->hash(); 174 } 175 std::unique_ptr<trie_node> br_node = 176 std::make_unique<trie_node>(trie_node_branch); 177 178 if (match_len > 0 || path.size() == 1) { 179 br_node->val_at(path[match_len]) = next; 180 if (match_len > 0 && match_len + 1 < path.size()) { 181 std::vector<neb::bytes> value( 182 {number_to_byte<bytes>(trie_node_extension), 183 bytes(path.value() + match_len + 1, path.size() - match_len - 1), 184 next}); 185 auto ext_node = create_node(value); 186 br_node->val_at(path[match_len]) = from_fix_bytes(ext_node->hash()); 187 } 188 189 // a branch to hold the new node 190 br_node->val_at(route[match_len]) = from_fix_bytes(update( 191 hash_t(), 192 bytes(route.value() + match_len + 1, route.size() - match_len - 1), 193 val)); 194 195 commit_node(br_node.get()); 196 197 // if no common prefix, replace the ext node with the new branch node 198 if (match_len == 0) { 199 return br_node->hash(); 200 } 201 202 // use the new branch node as the ext node's sub-trie 203 root_node->val_at(1) = bytes(path.value(), match_len); 204 root_node->val_at(2) = 205 bytes(br_node->hash().value(), br_node->hash().size()); 206 commit_node(root_node); 207 return root_node->hash(); 208 } 209 210 // 4. matchLen = 0 && len(path) > 1, 12... meets 23... => branch - ext - ... 211 root_node->val_at(1) = bytes(path.value() + 1, path.size() - 1); 212 commit_node(root_node); 213 214 br_node->val_at(path[match_len]) = from_fix_bytes(root_node->hash()); 215 br_node->val_at(route[match_len]) = from_fix_bytes(update( 216 hash_t(), 217 bytes(route.value() + match_len + 1, route.size() - match_len - 1), val)); 218 commit_node(br_node.get()); 219 return br_node->hash(); 220 } 221 222 hash_t trie::update_when_meet_leaf(trie_node *root_node, 223 const neb::bytes &route, 224 const neb::bytes &val) { 225 neb::bytes path = root_node->val_at(1); 226 neb::bytes leaf_val = root_node->val_at(2); 227 if (path.size() > route.size()) { 228 throw std::invalid_argument("wrong key, too short"); 229 } 230 auto match_len = prefix_len(path, route); 231 232 // node exists, update its value 233 if (match_len == path.size()) { 234 if (route.size() > match_len) { 235 throw std::invalid_argument("wrong key, too long"); 236 } 237 root_node->val_at(2) = val; 238 commit_node(root_node); 239 return root_node->hash(); 240 } 241 242 auto br_node = std::make_unique<trie_node>(trie_node_branch); 243 br_node->val_at(path[match_len]) = from_fix_bytes( 244 update(hash_t(), 245 bytes(path.value() + match_len + 1, path.size() - match_len - 1), 246 leaf_val)); 247 br_node->val_at(route[match_len]) = from_fix_bytes(update( 248 hash_t(), 249 bytes(route.value() + match_len + 1, route.size() - match_len - 1), val)); 250 251 commit_node(br_node.get()); 252 253 // if no common prefix, replace the leaf node with the new branch node 254 if (match_len == 0) { 255 return br_node->hash(); 256 } 257 258 root_node->change_to_type(trie_node_extension); 259 root_node->val_at(0) = number_to_byte<bytes>(trie_node_extension); 260 root_node->val_at(1) = bytes(path.value(), match_len); 261 root_node->val_at(2) = from_fix_bytes(br_node->hash()); 262 commit_node(root_node); 263 return root_node->hash(); 264 } 265 266 std::unique_ptr<trie_node> trie::fetch_node(const hash_t &hash) { 267 neb::bytes triepb_bytes = 268 bc_storage_session::instance().get_bytes(from_fix_bytes(hash)); 269 return std::make_unique<trie_node>(triepb_bytes); 270 } 271 272 std::unique_ptr<trie_node> trie::fetch_node(const neb::bytes &hash) { 273 neb::bytes triepb_bytes = bc_storage_session::instance().get_bytes(hash); 274 return std::make_unique<trie_node>(triepb_bytes); 275 } 276 277 bool trie::get_trie_node(const neb::bytes &root_hash, const neb::bytes &key, 278 neb::bytes &trie_node) { 279 auto hash = root_hash; 280 auto route = key_to_route(key); 281 282 neb::byte_t *route_ptr = route.value(); 283 size_t route_size = route.size(); 284 neb::byte_t *end_ptr = route.value() + route_size; 285 286 try { 287 288 while (route_ptr <= end_ptr) { 289 290 auto root_node = fetch_node(hash); 291 auto root_type = root_node->get_trie_node_type(); 292 if (route_ptr == end_ptr && root_type != trie_node_leaf) { 293 throw std::runtime_error("key/path too short"); 294 } 295 296 if (root_type == trie_node_branch) { 297 hash = root_node->val_at(route_ptr[0]); 298 route_ptr++; 299 300 } else if (root_type == trie_node_extension) { 301 auto key_path = root_node->val_at(1); 302 auto next_hash = root_node->val_at(2); 303 size_t left_size = end_ptr - route_ptr; 304 305 size_t matched_len = prefix_len(key_path, route_ptr, left_size); 306 if (matched_len != key_path.size()) { 307 throw std::runtime_error("node extension, key path not found"); 308 } 309 hash = next_hash; 310 route_ptr += matched_len; 311 } else if (root_type == trie_node_leaf) { 312 auto key_path = root_node->val_at(1); 313 size_t left_size = end_ptr - route_ptr; 314 size_t matched_len = prefix_len(key_path, route_ptr, left_size); 315 if (matched_len != key_path.size() || matched_len != left_size) { 316 throw std::runtime_error("node leaf, key path not found"); 317 } 318 trie_node = root_node->val_at(2); 319 return true; 320 } else { 321 throw std::runtime_error("unknown type, key path not found"); 322 } 323 } 324 325 } catch (const std::exception &e) { 326 // LOG(INFO) << e.what(); 327 return false; 328 } 329 330 throw std::runtime_error("key path not found"); 331 } 332 333 neb::bytes trie::route_to_key(const neb::bytes &route) { 334 335 size_t size = route.size() >> 1; 336 neb::bytes value(size); 337 338 if (size > 0) { 339 for (size_t i = 0; i < size; i++) { 340 byte_shared byte(route[(i << 1) + 1], route[i << 1]); 341 value[i] = byte.data(); 342 } 343 } 344 return value; 345 } 346 347 } // namespace fs 348 } // namespace neb