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