core: Add Mtree

Change-Id: I80205fb0d1f4ee5bcbc6c73651bb697fe854bf53
diff --git a/core/merkle-tree-cache.cpp b/core/merkle-tree-cache.cpp
new file mode 100644
index 0000000..a7f2dc0
--- /dev/null
+++ b/core/merkle-tree-cache.cpp
@@ -0,0 +1,353 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NSL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @author Peizhen Guo <patrick.guopz@gmail.com>
+ */
+
+#include "merkle-tree-cache.hpp"
+
+
+
+namespace nsl {
+
+typedef std::map<Index, int>::iterator tree_iter;
+typedef std::map<uint64_t, ndn::ConstBufferPtr>::iterator leaf_iter;
+
+Index
+MerkleTreeCache::findSubTree(Index nodeIndex)
+{
+  if(nodeIndex.level % 6 == 0 && nodeIndex.level != 0)
+    {
+      return nodeIndex;
+    }
+  else
+    {
+      uint8_t step = (uint64_t(nodeIndex.level / 6) + 1) * 6 - nodeIndex.level;
+      for (int i = 0; i < step; i++)
+        {
+          nodeIndex.number -= nodeIndex.number % int(pow(2, nodeIndex.level + 1));
+          nodeIndex.level += 1;
+        }
+      return nodeIndex;
+    }
+}
+
+Index
+MerkleTreeCache::getParentRootIndex(Index thisRootIndex)
+{
+  Index parentIndex;
+  parentIndex.number = thisRootIndex.number;
+  parentIndex.level = thisRootIndex.level;
+  for (int i = 0; i < 6; i++)
+    {
+      parentIndex.number -= parentIndex.number%int(pow(2, parentIndex.level + 1));
+      parentIndex.level += 1;
+    }
+  return parentIndex;
+}
+
+
+void
+MerkleTreeCache::removeSubTree()
+{
+  if (doesCacheFull() > 1)
+    {
+      // find out the least recent used subtree
+      tree_iter _i = m_timeFromLastUse.begin();
+      int idle_time_max = -1;
+      Index rm_index_max = _i->first;
+      int idle_time_min = _i->second;
+      Index rm_index_min = _i->first;
+      for (_i = m_timeFromLastUse.begin(); _i != m_timeFromLastUse.end(); _i++)
+        {
+          if (_i->second > idle_time_max && m_cachedTree[_i->first]->getRemainPosition() == 0)
+            {
+              idle_time_max = _i->second;
+              rm_index_max = _i->first;
+            }
+          if (_i->second < idle_time_min)
+            {
+              idle_time_min = _i->second;
+              rm_index_min = _i->first;
+            }
+        }
+
+      // refresh the timer
+      for (_i = m_timeFromLastUse.begin(); _i != m_timeFromLastUse.end(); _i++)
+        {
+          _i->second -= idle_time_min;
+        }
+      // update to database and remove subtree from cache and timer,only when there is full subtree
+      if (m_cachedTree[rm_index_max]->getRemainPosition() == 0 && idle_time_max >= 0)
+        {
+          m_database.addSubTree(m_cachedTree[rm_index_max]);
+          m_cachedTree.erase(rm_index_max);
+          m_timeFromLastUse.erase(rm_index_max);
+        }
+    }
+}
+
+void
+MerkleTreeCache::removeLeaf()
+{
+  if (doesCacheFull() % 2 != 0)
+    {
+      // randomly pick a old leaf to remove
+      leaf_iter _i = m_leavesData.begin();
+      while (_i->first == m_nLeaves - 1)
+        {
+          _i++;
+        }
+      m_database.addLeafInfo(_i->first, _i->second);
+      m_leavesData.erase(_i->first);
+    }
+}
+
+
+
+
+
+// Do not have to deal with NOT-IN-MEMORY issue because not full tree will not in database
+void
+MerkleTreeCache::addLeaf(Leaf newLeaf)
+{
+  ndn::ConstBufferPtr data = newLeaf.getData();
+  removeLeaf(); // test whether is full, if so, delete an old item
+  m_leavesData[newLeaf.getIndex().number] = data;
+  Index leafIndex = newLeaf.getIndex();
+  ndn::ConstBufferPtr hash = newLeaf.getHash();
+
+  Index subTreeRoot = findSubTree(leafIndex);
+  if (m_nLeaves > 0)
+    {
+      // Not full so that always in memory
+      m_cachedTree[subTreeRoot]->addNode(hash);
+      m_nLeaves += 1;
+    }
+  else
+    {
+      SubTreePtr newTree(new SubTree(subTreeRoot,
+                                     ndn::bind(&MerkleTreeCache::update, this,
+                                               subTreeRoot, _1, _2)));
+      newTree->addNode(hash);
+      removeSubTree();
+      m_cachedTree[subTreeRoot] = newTree;
+      m_nLeaves = 1;
+      m_nLevels = 1;
+    }
+
+  for (tree_iter _i = m_timeFromLastUse.begin(); _i != m_timeFromLastUse.end(); _i++)
+    {
+      _i->second += 1;
+    }
+  m_timeFromLastUse[subTreeRoot] = 0; // if not exist, automatically create one and set to 0
+}
+
+
+// Deal with loading from database
+// database update
+// consider add to database when a subtree is full
+void
+MerkleTreeCache::update(Index subRootIndex, uint8_t subRemainNum, ndn::ConstBufferPtr subRootHash)
+{
+  if ((subRootIndex.level / 6) < m_nLevels)
+    {
+      Index parentRoot = getParentRootIndex(subRootIndex);
+
+      // bring in memory if parentRoot not in
+      if (m_cachedTree.count(parentRoot) <= 0)
+        {
+          loadSubTreeFromDatabase(parentRoot);
+        }
+      m_cachedTree[parentRoot]->updateLeafHash(subRootIndex, subRootHash);
+      m_timeFromLastUse[parentRoot] = 0;
+    }
+
+  if (subRemainNum == 0) // add the current full subtree into the database
+    {
+      Index parentRoot = getParentRootIndex(subRootIndex);
+      if ((subRootIndex.level / 6) >= m_nLevels) // if it is the top subtree
+        {
+          SubTreePtr newTree(new SubTree(parentRoot,
+                                         ndn::bind(&MerkleTreeCache::update, this,
+                                                   parentRoot, _1, _2)));
+          removeSubTree();
+          m_cachedTree[parentRoot] = newTree;
+          m_nLevels += 1;
+          m_timeFromLastUse[parentRoot] = 0;
+          m_cachedTree[parentRoot]->updateLeafHash(subRootIndex, subRootHash);
+        }
+      Index newRoot;
+      newRoot.level = subRootIndex.level;
+      newRoot.number = subRootIndex.number + int(pow(2, subRootIndex.level));
+      // whether the updated subtree is already full,
+      // but its child subtree is not full.
+      // To avoid create multiple sibling new subtree
+      if (m_cachedTree.count(newRoot) == 0)
+        {
+          SubTreePtr newTree(new SubTree(newRoot,
+                                         ndn::bind(&MerkleTreeCache::update, this,
+                                                   newRoot, _1, _2)));
+          removeSubTree();
+          m_cachedTree[newRoot] = newTree;
+          m_timeFromLastUse[newRoot] = 0;
+        }
+    }
+}
+
+
+NodePtr
+MerkleTreeCache::queryNode(Index nodeIndex)
+{
+  // update timer
+  for (tree_iter _i = m_timeFromLastUse.begin(); _i != m_timeFromLastUse.end(); _i++)
+    {
+      _i->second += 1;
+    }
+
+  Index rootIndex = findSubTree(nodeIndex);
+  ndn::ConstBufferPtr hash;
+  if (m_cachedTree.count(rootIndex) == 0)
+    {
+      loadSubTreeFromDatabase(rootIndex);
+    }
+  hash = m_cachedTree[rootIndex]->getHash(nodeIndex);
+
+  if (nodeIndex.level == 0)
+    {
+      if (m_leavesData.count(nodeIndex.number) == 0)
+        {
+          loadLeafFromDatabase(nodeIndex.number);
+        }
+      NodePtr node_ptr(new Leaf(m_leavesData[nodeIndex.number],
+                                nodeIndex.number, nodeIndex.level, 0));
+      node_ptr->setHash(hash);
+      return node_ptr;
+    }
+  else
+    {
+      NodePtr node_ptr(new IntermediateNode(nodeIndex.number, nodeIndex.level, 0));
+      node_ptr->setHash(hash);
+      ((IntermediateNode*)node_ptr.get())->setIsFull(m_nLeaves);
+      return node_ptr;
+    }
+}
+
+
+bool
+MerkleTreeCache::doesNodeExist(Index nodeIndex)
+{
+  Index rootIndex = findSubTree(nodeIndex);
+  if (m_cachedTree.count(rootIndex) > 0)
+    {
+      return true;
+    }
+  else
+    {
+      bool result = m_database.doesSubTreeExist(rootIndex);
+      return result;
+    }
+}
+
+
+
+SubTreePtr
+MerkleTreeCache::decoding(std::string subTreeInfo)
+{
+  uint64_t seq = 0;
+  unsigned char tmp = 0;
+  for (int i = 7; i >= 0; i--)
+    {
+      tmp = subTreeInfo[i];
+      seq += tmp;
+      seq = seq << 8;
+    }
+  seq = seq >> 8;
+  uint64_t lev = 0;
+  for (int i = 15; i >= 8; i--)
+    {
+      tmp = subTreeInfo[i];
+      lev += tmp;
+      lev = lev << 8;
+    }
+  lev = lev >> 8;
+  Index rootIndex;
+  rootIndex.number = seq;
+  rootIndex.level = lev;
+  SubTreePtr newTree(new SubTree(rootIndex,
+                                 ndn::bind(&MerkleTreeCache::update, this,
+                                           rootIndex, _1, _2)));
+  uint8_t remain = subTreeInfo[16]; // not useful
+  if (remain == 0)
+    {
+      std::vector<ndn::BufferPtr> hashes;
+      for (int i = 0; i < 127; i++)
+        {
+          ndn::Buffer buf;
+          for(int j = 17 + 32 * i; j < 49 + 32 * i; j++)
+            {
+              buf.push_back(subTreeInfo[j]);
+            }
+          ndn::BufferPtr thisBuf = ndn::make_shared<ndn::Buffer>(buf);
+          hashes.push_back(thisBuf);
+        }
+      newTree->resumeFromString(remain, hashes);
+      return newTree;
+    }
+  else
+    {
+      std::vector<ndn::BufferPtr> hashes;
+      uint8_t lastNo = 126 - remain;
+      for (int i = 63; i <= lastNo; i++)
+        {
+          ndn::Buffer buf;
+          for(int j = 17 + 32 * i; j < 49 + 32 * i; j++)
+            {
+              buf.push_back(subTreeInfo[j]);
+            }
+          ndn::BufferPtr thisBuf = ndn::make_shared<ndn::Buffer>(buf);
+          hashes.push_back(thisBuf);
+        }
+      newTree->resumeFromString(remain, hashes);
+      return newTree;
+    }
+}
+
+
+void
+MerkleTreeCache::loadSubTreeFromDatabase(Index rootIndex)
+{
+  // Detect the cache limitation
+  removeSubTree();
+  std::string tmp_str = m_database.getSubTree(rootIndex);
+  SubTreePtr newtree = decoding(tmp_str);
+  m_cachedTree[rootIndex] = newtree;
+  m_timeFromLastUse[rootIndex] = 0;
+}
+
+void
+MerkleTreeCache::loadLeafFromDatabase(uint64_t sequence)
+{
+  // Detect the cache limitation
+  removeLeaf();
+  ndn::ConstBufferPtr newleaf = m_database.getLeafInfo(sequence);
+  m_leavesData[sequence] = newleaf;
+}
+
+
+} // namespace nsl
diff --git a/core/merkle-tree-cache.hpp b/core/merkle-tree-cache.hpp
new file mode 100644
index 0000000..97e8908
--- /dev/null
+++ b/core/merkle-tree-cache.hpp
@@ -0,0 +1,176 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NSL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @author Peizhen Guo <patrick.guopz@gmail.com>
+ */
+#ifndef NLS_CORE_MERKLE_TREE_CACHE_HPP
+#define NLS_CORE_MERKLE_TREE_CACHE_HPP
+
+#include <map>
+#include <vector>
+
+#include "sub-tree.hpp"
+#include "leaf.hpp"
+#include "intermediate-node.hpp"
+#include "merkle-tree-sqlite3.hpp"
+
+
+namespace nsl {
+
+
+typedef ndn::shared_ptr<const SubTree> ConstSubTreePtr;
+typedef ndn::shared_ptr<SubTree> SubTreePtr;
+typedef ndn::shared_ptr<const Node> ConstNodePtr;
+typedef ndn::shared_ptr<Node> NodePtr;
+
+class MerkleTreeCache
+{
+public:
+
+  MerkleTreeCache()
+    :m_nLevels(0),
+     m_nLeaves(0)
+  {
+  }
+
+  ~MerkleTreeCache()
+  {
+  }
+
+  uint8_t
+  getLevel()
+  {
+    return m_nLevels;
+  }
+
+  uint64_t
+  getLeaves()
+  {
+    return m_nLeaves;
+  }
+
+  SubTreePtr
+  getSubTree(Index rootIndex)
+  {
+    if (m_cachedTree.count(rootIndex) > 0)
+      {
+        //std::cout<<"I'm here!"<<int(m_cachedTree[rootIndex]->getRemainPosition())<<std::endl;
+        return m_cachedTree[rootIndex];
+      }
+    else
+      {
+        std::string treeString = m_database.getSubTree(rootIndex);
+        SubTreePtr newtree = decoding(treeString);
+        return newtree;
+      }
+  }
+
+  // Do the update when a subtree is full
+  // Iteratively: find parent --> check full --> ... --> if not full -->
+  // create subtree --> create subsubtree --> ... --> until down to the leaf
+  // invoke a subtree.updateHash(), and decide whether to add new subtrees according to the callback
+  // remainPosition value.
+  void
+  update(Index subRootIndex, uint8_t subRemainNum, ndn::ConstBufferPtr subRootHash);
+
+  void
+  addLeaf(Leaf newLeaf);
+
+  NodePtr
+  queryNode(Index nodeIndex);
+
+  bool
+  doesNodeExist(Index nodeIndex);
+
+  void
+  loadSubTreeFromDatabase(Index rootIndex);
+
+  void
+  loadLeafFromDatabase(uint64_t sequence);
+
+
+
+  SubTreePtr
+  decoding(std::string subTreeInfo);
+
+  // remove the comment to test sqlite3 function
+  // MerkleTreeSqlite3 m_database;
+
+  // To show the exact size of the cache
+  // std::map<Index, SubTreePtr> m_cachedTree;
+  // std::map<uint64_t, ndn::ConstBufferPtr> m_leavesData;
+
+
+private:
+
+  // find which subTree the node belongs to (not include root node)
+  Index
+  findSubTree(Index nodeIndex);
+
+  // find a subTree's parent root index
+  Index
+  getParentRootIndex(Index thisRootIndex);
+
+
+  // To be finished
+  uint8_t
+  doesCacheFull()
+  {
+    if (m_cachedTree.size() >= 3 && m_leavesData.size() >= 64)
+      {
+        return 3;
+      }
+    else if (m_cachedTree.size() >= 3 && m_leavesData.size() < 64)
+      {
+        return 2;
+      }
+    else if (m_cachedTree.size() < 3 && m_leavesData.size() >= 64)
+      {
+        return 1;
+      }
+    else
+      {
+        return 0;
+      }
+  }
+
+  // choose a cache item to remove,
+  // exactly remove items from cache only when: 1)have full subtrees 2)cache is full
+  void
+  removeSubTree();
+
+  void
+  removeLeaf();
+
+private:
+  // partly in cache, completely in db
+  std::map<Index, SubTreePtr> m_cachedTree;
+  std::map<uint64_t, ndn::ConstBufferPtr> m_leavesData; //starts from 0(same as leaf)
+
+  // completely in memory, add & delete with time
+  std::map<Index, int> m_timeFromLastUse;
+  uint8_t m_nLevels; // levels counted based on subtree unit
+  uint64_t m_nLeaves; // sequence number + 1
+
+  // sqlite3 database
+  MerkleTreeSqlite3 m_database;
+};
+
+} // namespace nsl
+
+#endif // NLS_CORE_MERKLE_TREE_CACHE_HPP
diff --git a/core/merkle-tree-sqlite3.cpp b/core/merkle-tree-sqlite3.cpp
new file mode 100644
index 0000000..1844ad4
--- /dev/null
+++ b/core/merkle-tree-sqlite3.cpp
@@ -0,0 +1,332 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NSL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @author Peizhen Guo <patrick.guopz@gmail.com>
+ */
+
+#include "merkle-tree-sqlite3.hpp"
+#include <stdlib.h>
+#include <boost/filesystem.hpp>
+
+
+namespace nsl {
+
+static const std::string INIT_SUBTREE_TABLE = "\
+CREATE TABLE IF NOT EXISTS                                           \n \
+  SubTree(                                                           \n \
+      subTree_sequence     INTEGER,                                  \n \
+      subTree_level        INTEGER,                                  \n \
+      subTree_info         BLOB,                                     \n \
+                                                                     \
+      PRIMARY KEY (subTree_sequence, subTree_level)                  \n \
+  );                                                                 \n \
+                                                                     \
+CREATE INDEX subTree_index ON SubTree(subTree_sequence);             \n \
+";
+
+static const std::string INIT_LEAF_TABLE = "\
+CREATE TABLE IF NOT EXISTS                                           \n \
+  Leaf(                                                              \n \
+      leaf_sequence     INTEGER,                                     \n \
+      leaf_info         BLOB,                                        \n \
+                                                                     \
+      PRIMARY KEY (leaf_sequence)                                    \n \
+  );                                                                 \n \
+                                                                     \
+CREATE INDEX leaf_index ON Leaf(leaf_sequence);                      \n \
+";
+
+/**
+ * A utility function to call the normal sqlite3_bind_text where the value and length are
+ * value.c_str() and value.size().
+ */
+static int sqlite3_bind_text(sqlite3_stmt* statement,
+                             int index,
+                             const std::string& value,
+                             void(*destructor)(void*))
+{
+  return sqlite3_bind_text(statement, index, value.c_str(), value.size(), destructor);
+}
+
+
+MerkleTreeSqlite3::MerkleTreeSqlite3()
+{
+  boost::filesystem::path identityDir = boost::filesystem::path("/Users/GPZ/Develop/nslDB");
+  boost::filesystem::create_directories(identityDir);
+
+  /// @todo Add define for windows/unix in wscript. The following may completely fail on windows
+  int res = sqlite3_open_v2((identityDir / "nsl-merkle-tree.db").c_str(), &m_database,
+                            SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
+#ifdef NDN_CXX_DISABLE_SQLITE3_FS_LOCKING
+                            "unix-dotfile"
+#else
+                            0
+#endif
+                            );
+
+  if (res != SQLITE_OK)
+    std::cout << "DB cannot be opened/created";
+
+  //Check if SubTree table exists;
+  sqlite3_stmt* statement;
+  sqlite3_prepare_v2(m_database,
+                     "SELECT name FROM sqlite_master WHERE type='table' And name='SubTree'",
+                     -1, &statement, 0);
+  res = sqlite3_step(statement);
+
+  bool SubTreeTableExists = false;
+  if (res == SQLITE_ROW)
+    SubTreeTableExists = true;
+
+  sqlite3_finalize(statement);
+
+  if (!SubTreeTableExists)
+    {
+      char* errorMessage = 0;
+      res = sqlite3_exec(m_database, INIT_SUBTREE_TABLE.c_str(), NULL, NULL, &errorMessage);
+
+      if (res != SQLITE_OK && errorMessage != 0)
+        {
+          sqlite3_free(errorMessage);
+        }
+    }
+
+  //Check if Leaf table exists;
+  sqlite3_prepare_v2(m_database,
+                     "SELECT name FROM sqlite_master WHERE type='table' And name='Leaf'",
+                     -1, &statement, 0);
+  res = sqlite3_step(statement);
+
+  bool LeafTableExists = false;
+  if (res == SQLITE_ROW)
+    LeafTableExists = true;
+
+  sqlite3_finalize(statement);
+
+  if (!LeafTableExists)
+    {
+      char* errorMessage = 0;
+      res = sqlite3_exec(m_database, INIT_LEAF_TABLE.c_str(), NULL, NULL, &errorMessage);
+
+      if (res != SQLITE_OK && errorMessage != 0)
+        {
+          sqlite3_free(errorMessage);
+        }
+    }
+
+}
+
+
+MerkleTreeSqlite3::~MerkleTreeSqlite3()
+{
+}
+
+
+void
+MerkleTreeSqlite3::addSubTree(SubTreePtr oldSubTree)
+{
+  Index old_idx = oldSubTree->getRootIndex();
+  std::string old_info = oldSubTree->encoding();
+
+  sqlite3_stmt* statement;
+  sqlite3_prepare_v2(m_database,
+                     "INSERT OR REPLACE INTO SubTree \
+                      (subTree_sequence, subTree_level, subTree_info)   \
+                      values (?, ?, ?)",
+                     -1, &statement, 0);
+  sqlite3_bind_int64(statement, 1, old_idx.number);
+  sqlite3_bind_int64(statement, 2, old_idx.level);
+  sqlite3_bind_text(statement, 3, old_info, SQLITE_TRANSIENT);
+  sqlite3_step(statement);
+  sqlite3_finalize(statement);
+}
+
+
+std::string
+MerkleTreeSqlite3::getSubTree(Index rootIndex)
+{
+  sqlite3_stmt* statement;
+  sqlite3_prepare_v2(m_database,
+                     "SELECT subTree_info FROM SubTree \
+                      WHERE subTree_sequence=? AND subTree_level=?",
+                     -1, &statement, 0);
+  sqlite3_bind_int64(statement, 1, rootIndex.number);
+  sqlite3_bind_int64(statement, 2, rootIndex.level);
+  int res = sqlite3_step(statement);
+  std::string result;
+  if (res == SQLITE_ROW)
+    {
+      result = std::string(reinterpret_cast<const char *>(sqlite3_column_text(statement, 0)),
+                           sqlite3_column_bytes(statement, 0));
+      sqlite3_finalize(statement);
+      return result;
+    }
+  else
+    {
+      sqlite3_finalize(statement);
+      return result;
+    }
+}
+
+
+bool
+MerkleTreeSqlite3::doesSubTreeExist(Index rootIndex)
+{
+  bool result = false;
+  sqlite3_stmt* statement;
+  sqlite3_prepare_v2(m_database,
+                     "SELECT count(*) FROM SubTree WHERE subTree_sequence=? AND subTree_level=?",
+                     -1, &statement, 0);
+  sqlite3_bind_int64(statement, 1, rootIndex.number);
+  sqlite3_bind_int64(statement, 2, rootIndex.level);
+  int res = sqlite3_step(statement);
+  if (res == SQLITE_ROW)
+    {
+      int countAll = sqlite3_column_int(statement, 0);
+      if (countAll > 0)
+        result = true;
+    }
+  sqlite3_finalize(statement);
+  return result;
+}
+
+
+void
+MerkleTreeSqlite3::deleteSubTree(Index rootIndex)
+{
+  sqlite3_stmt* stmt;
+  sqlite3_prepare_v2(m_database, "DELETE FROM SubTree WHERE subTree_sequence=? AND subTree_level=?",
+                     -1, &stmt, 0);
+  sqlite3_bind_int64(stmt, 1, rootIndex.number);
+  sqlite3_bind_int64(stmt, 2, rootIndex.level);
+  sqlite3_step(stmt);
+  sqlite3_finalize(stmt);
+}
+
+
+void
+MerkleTreeSqlite3::getAllSubTree(std::vector<std::string> subTreeInfoList)
+{
+  sqlite3_stmt* stmt;
+  sqlite3_prepare_v2(m_database,
+                     "SELECT subTree_info FROM SubTree",
+                     -1, &stmt, 0);
+  while (sqlite3_step(stmt) == SQLITE_ROW)
+    subTreeInfoList.push_back(std::string(reinterpret_cast<const char *>
+                                          (sqlite3_column_text(stmt, 0)),
+                                          sqlite3_column_bytes(stmt, 0)));
+
+  sqlite3_finalize(stmt);
+}
+
+
+// For leafInfo
+
+void
+MerkleTreeSqlite3::addLeafInfo(uint64_t sequence, ndn::ConstBufferPtr buf_ptr)
+{
+
+  sqlite3_stmt* statement;
+  sqlite3_prepare_v2(m_database,
+                     "INSERT OR REPLACE INTO Leaf  \
+                      (leaf_sequence, leaf_info)   \
+                      values (?, ?)", -1, &statement, 0);
+  sqlite3_bind_int64(statement, 1, sequence);
+  sqlite3_bind_blob(statement, 2, buf_ptr->buf(), buf_ptr->size(), SQLITE_STATIC);
+  sqlite3_step(statement);
+  sqlite3_finalize(statement);
+}
+
+
+ndn::ConstBufferPtr
+MerkleTreeSqlite3::getLeafInfo(uint64_t sequence)
+{
+  sqlite3_stmt* statement;
+  sqlite3_prepare_v2(m_database,
+                     "SELECT leaf_info FROM Leaf \
+                      WHERE leaf_sequence=?", -1, &statement, 0);
+  sqlite3_bind_int64(statement, 1, sequence);
+  int res = sqlite3_step(statement);
+  if (res == SQLITE_ROW)
+    {
+      ndn::Buffer res_buf(sqlite3_column_blob(statement, 0), sqlite3_column_bytes(statement, 0));
+      ndn::ConstBufferPtr result = ndn::make_shared<ndn::Buffer>(res_buf);
+      sqlite3_finalize(statement);
+      return result;
+    }
+  else
+    {
+      sqlite3_finalize(statement);
+      return ndn::ConstBufferPtr();
+    }
+}
+
+
+bool
+MerkleTreeSqlite3::doesLeafInfoExist(uint64_t sequence)
+{
+  bool result = false;
+  sqlite3_stmt* statement;
+  sqlite3_prepare_v2(m_database,
+                     "SELECT count(*) FROM Leaf WHERE leaf_sequence=?",
+                     -1, &statement, 0);
+  sqlite3_bind_int64(statement, 1, sequence);
+  int res = sqlite3_step(statement);
+  if (res == SQLITE_ROW)
+    {
+      int countAll = sqlite3_column_int(statement, 0);
+      if (countAll > 0)
+        result = true;
+    }
+  sqlite3_finalize(statement);
+  return result;
+}
+
+
+void
+MerkleTreeSqlite3::deleteLeafInfo(uint64_t sequence)
+{
+  sqlite3_stmt* stmt;
+  sqlite3_prepare_v2(m_database, "DELETE FROM Leaf WHERE leaf_sequence=?",
+                     -1, &stmt, 0);
+  sqlite3_bind_int64(stmt, 1, sequence);
+  sqlite3_step(stmt);
+  sqlite3_finalize(stmt);
+}
+
+
+void
+MerkleTreeSqlite3::getAllLeafInfo(std::map<uint64_t, ndn::ConstBufferPtr> leaves)
+{
+  sqlite3_stmt* stmt;
+  sqlite3_prepare_v2(m_database,
+                     "SELECT leaf_sequence, leaf_info FROM Leaf",
+                     -1, &stmt, 0);
+  while (sqlite3_step(stmt) == SQLITE_ROW)
+    {
+      uint64_t seq = sqlite3_column_int64(stmt, 0);
+      ndn::ConstBufferPtr buf = ndn::make_shared<ndn::Buffer>(sqlite3_column_blob(stmt, 1),
+                                                              sqlite3_column_bytes(stmt, 1));
+      leaves[seq] = buf;
+    }
+
+  sqlite3_finalize(stmt);
+}
+
+
+} // namespace nsl
diff --git a/core/merkle-tree-sqlite3.hpp b/core/merkle-tree-sqlite3.hpp
new file mode 100644
index 0000000..617d20c
--- /dev/null
+++ b/core/merkle-tree-sqlite3.hpp
@@ -0,0 +1,86 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NSL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @author Peizhen Guo <patrick.guopz@gmail.com>
+ */
+
+#ifndef NLS_CORE_MERKLE_TREE_SQLITE3_HPP
+#define NLS_CORE_MERKLE_TREE_SQLITE3_HPP
+
+#include <sqlite3.h>
+#include <map>
+#include "sub-tree.hpp"
+typedef ndn::shared_ptr<const nsl::SubTree> ConstSubTreePtr;
+typedef ndn::shared_ptr<nsl::SubTree> SubTreePtr;
+
+struct sqlite3;
+
+namespace nsl {
+
+class MerkleTreeSqlite3
+{
+public:
+
+  MerkleTreeSqlite3();
+
+  ~MerkleTreeSqlite3();
+
+  // SubTree
+  void
+  addSubTree(SubTreePtr oldSubTree);
+
+  std::string
+  getSubTree(Index rootIndex);
+
+  bool
+  doesSubTreeExist(Index rootIndex);
+
+  void
+  deleteSubTree(Index rootIndex);
+
+  void
+  getAllSubTree(std::vector<std::string> subTreeInfoList);
+
+
+  // LeafInfo (no need of encoding/decoding scheme)
+  void
+  addLeafInfo(uint64_t sequence, ndn::ConstBufferPtr buf_ptr);
+
+  ndn::ConstBufferPtr
+  getLeafInfo(uint64_t sequence);
+
+  bool
+  doesLeafInfoExist(uint64_t sequence);
+
+  void
+  deleteLeafInfo(uint64_t sequence);
+
+  void
+  getAllLeafInfo(std::map<uint64_t, ndn::ConstBufferPtr> leaves);
+
+
+private:
+  sqlite3* m_database;
+
+};
+
+
+} // namespace nsl
+
+
+#endif // NLS_CORE_MERKLE_TREE_SQLITE3_HPP
diff --git a/core/merkle-tree.cpp b/core/merkle-tree.cpp
new file mode 100644
index 0000000..f74af33
--- /dev/null
+++ b/core/merkle-tree.cpp
@@ -0,0 +1,140 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NSL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @author Peizhen Guo <patrick.guopz@gmail.com>
+ */
+#include "merkle-tree.hpp"
+
+namespace nsl {
+
+MerkleTree::MerkleTree()
+{
+  m_nLevels = 0;
+  m_nLeaves = 0;
+}
+
+
+ConstNodePtr
+MerkleTree::getNode(const Index& index)
+{
+  ConstNodePtr p_leav;
+  if (m_cache.doesNodeExist(index))
+    {
+      p_leav = m_cache.queryNode(index);
+      return p_leav;
+    }
+  else
+    return p_leav;
+}
+
+
+uint64_t
+MerkleTree::getLeafNum() const
+{
+  return m_nLeaves;
+}
+
+
+uint64_t
+MerkleTree::getLevel() const
+{
+  return m_nLevels;
+}
+
+
+
+uint64_t
+MerkleTree::addLeaf(ndn::ConstBufferPtr info)
+{
+  Leaf new_leaf(info, m_nLeaves, 0, 0);
+  new_leaf.computeHash(); // computeHash() has been written.
+  m_nLeaves++;
+  if (m_nLeaves > int(pow(2, int(m_nLevels) - 1)))
+    {
+      m_nLevels++;
+    }
+  m_cache.addLeaf(new_leaf);
+  return m_nLeaves - 1;
+}
+
+
+std::vector<ConstNodePtr>
+MerkleTree::generateProof(uint64_t version1, uint64_t version2)
+{
+  std::vector<ConstNodePtr> proof;
+  if (version1 >= version2)
+    {
+      return proof;
+    }
+
+  //add a memberproof from version2
+  Index this_idx;
+  this_idx.number = version2;
+  this_idx.level = 0;
+  ConstNodePtr p_leav;
+  p_leav = m_cache.queryNode(this_idx);
+  proof.push_back(p_leav);
+  if ((this_idx.number % 2) != 0)
+    {
+      this_idx.number -= 1;
+      p_leav = m_cache.queryNode(this_idx);
+      proof.push_back(p_leav);
+    }
+  this_idx.level += 1;
+  this_idx.number -= this_idx.number % 2;
+  for (int i = 1; i < m_nLevels - 1 ; i++)
+    {
+      if (this_idx.number % int(pow(2, i + 1)) != 0)
+        {
+          this_idx.number -= int(pow(2, i));
+          p_leav = m_cache.queryNode(this_idx);
+          proof.push_back(p_leav);
+        }
+      this_idx.level += 1;
+      this_idx.number -= this_idx.number % int(pow(2, i + 1));
+    }
+
+  //add another path from version1
+  this_idx.number = version1;
+  this_idx.level = 0;
+  p_leav = m_cache.queryNode(this_idx);
+  proof.push_back(p_leav);
+  if ((this_idx.number % 2) != 0)
+    {
+      this_idx.number -= 1;
+      p_leav = m_cache.queryNode(this_idx);
+      proof.push_back(p_leav);
+    }
+  this_idx.level += 1;
+  this_idx.number -= this_idx.number % 2;
+  for (int i = 1; i < m_nLevels - 1 ; i++)
+    {
+      if (this_idx.number % int(pow(2, i + 1)) != 0)
+        {
+          this_idx.number -= int(pow(2, i));
+          p_leav = m_cache.queryNode(this_idx);
+          proof.push_back(p_leav);
+        }
+      this_idx.level += 1;
+      this_idx.number -= this_idx.number % int(pow(2, i + 1));
+    }
+
+  return proof;
+}
+
+} // namespace nsl
diff --git a/core/merkle-tree.hpp b/core/merkle-tree.hpp
new file mode 100644
index 0000000..ccf73c5
--- /dev/null
+++ b/core/merkle-tree.hpp
@@ -0,0 +1,75 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NSL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @author Peizhen Guo <patrick.guopz@gmail.com>
+ */
+#ifndef NLS_CORE_MERKLE_TREE_HPP
+#define NLS_CORE_MERKLE_TREE_HPP
+
+#include <map>
+#include <vector>
+
+#include <stddef.h>
+#include <stdint.h>
+#include <time.h>
+
+#include "leaf.hpp"
+#include "intermediate-node.hpp"
+#include "merkle-tree-cache.hpp"
+
+namespace nsl {
+
+class MerkleTree
+{
+public:
+  MerkleTree();
+
+  ~MerkleTree()
+  {
+  }
+
+  ConstNodePtr
+  getNode(const Index& index);
+
+  uint64_t
+  getLeafNum() const;
+
+  uint64_t
+  getLevel() const;
+
+
+  //return root hash value
+  uint64_t
+  addLeaf(ndn::ConstBufferPtr info);
+
+
+  std::vector<ConstNodePtr>
+  generateProof(uint64_t version1, uint64_t version2); // version equals to leaf's index number
+
+
+private:
+  MerkleTreeCache m_cache;
+  uint64_t m_nLevels;
+  uint64_t m_nLeaves;
+
+};
+
+
+} // namespace nsl
+
+#endif // NLS_CORE_MERKLE_TREE_HPP
diff --git a/core/sub-tree.cpp b/core/sub-tree.cpp
new file mode 100644
index 0000000..46f3f5c
--- /dev/null
+++ b/core/sub-tree.cpp
@@ -0,0 +1,213 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NSL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @author Peizhen Guo <patrick.guopz@gmail.com>
+ */
+
+#include "sub-tree.hpp"
+#include "Auditor.hpp"
+#include <math.h>
+
+
+namespace nsl {
+
+void
+SubTree::addNode(ndn::ConstBufferPtr hash_ptr)
+{
+  if(m_remainPosition > 0)
+    {
+      uint8_t seqNo = 127 - m_remainPosition;
+      m_nodeHashes[seqNo] = ndn::make_shared<ndn::Buffer>(*hash_ptr);
+      m_remainPosition -= 1;
+      updateHash();
+    }
+}
+
+void
+SubTree::updateHash()
+{
+  uint8_t i_ = 6;
+  uint8_t lastNo = 126 - m_remainPosition;
+  for (; i_ > 0; i_--)
+    {
+      for (int i = int(pow(2, i_)) - 1; i <= lastNo; i+= 2)
+        {
+          if ((i + 1) <= lastNo)
+            {
+              uint8_t up_idx = (i-1) / 2;
+              Auditor hasher;
+              ndn::ConstBufferPtr buf = hasher.computeHash(m_nodeHashes[i],
+                                                           m_nodeHashes[i + 1]);
+              m_nodeHashes[up_idx] = ndn::make_shared<ndn::Buffer>(*buf);
+            }
+          else
+            {
+              uint8_t up_idx = (i-1) / 2;
+              Auditor hasher;
+              ndn::ConstBufferPtr buf = hasher.computeHashOneSide(m_nodeHashes[i]);
+              m_nodeHashes[up_idx] = ndn::make_shared<ndn::Buffer>(*buf);
+            }
+        }
+      lastNo = (lastNo - 1) / 2;
+    }
+  m_callBackUpdate(m_remainPosition, m_nodeHashes[0]);
+}
+
+
+
+
+void
+SubTree::updateLeafHash(Index subRootIndex, ndn::ConstBufferPtr hash)
+{
+  uint8_t lastNo = 126 - m_remainPosition;
+  uint64_t sequenceNo = subRootIndex.number;
+  uint64_t level = subRootIndex.level;
+  uint8_t indexBase = int(pow(2, m_root.level - level) - 1);
+  uint8_t indexOffset = (sequenceNo - m_root.number) / int(pow(2, level));
+  m_nodeHashes[indexBase + indexOffset] = ndn::make_shared<ndn::Buffer>(*hash);
+  if (lastNo < indexBase + indexOffset) // update value ? add new value
+    {
+      m_remainPosition -= 1;
+    }
+  updateHash();
+}
+
+ndn::ConstBufferPtr
+SubTree::getHash(Index nodeIndex)
+{
+  uint64_t sequenceNo = nodeIndex.number;
+  uint64_t level = nodeIndex.level;
+  uint8_t indexBase = int(pow(2, m_root.level - level) - 1);
+  uint8_t indexOffset = (sequenceNo - m_root.number) / int(pow(2, level));
+  return m_nodeHashes[indexBase + indexOffset];
+}
+
+
+
+
+Index
+SubTree::getRootIndex()
+{
+  return m_root;
+}
+
+uint8_t
+SubTree::getRemainPosition()
+{
+  return m_remainPosition;
+}
+
+Index
+SubTree::getParentRootIndex()
+{
+  Index parentIndex;
+  parentIndex.number = m_root.number;
+  parentIndex.level = m_root.level;
+  for (int i = 0; i < 6; i++)
+    {
+      parentIndex.number -= parentIndex.number%int(pow(2, parentIndex.level + 1));
+      parentIndex.level += 1;
+    }
+  return parentIndex;
+}
+
+
+
+std::string
+SubTree::encoding()
+{
+  std::string subTreeInfo = "";
+  uint64_t seq = m_root.number;
+  uint64_t lev = m_root.level;
+  unsigned char div_seq[8];
+  unsigned char div_lev[8];
+  for (int i = 0; i < 8; i++)
+    {
+      div_seq[i] = (seq >> (8*i)) & 0xFF;
+      div_lev[i] = (lev >> (8*i)) & 0xFF;
+    }
+  for (int i = 0; i < 8; i++)
+    {
+      subTreeInfo += div_seq[i];
+    }
+  for (int i = 0; i < 8; i++)
+    {
+      subTreeInfo += div_lev[i];
+    }
+  subTreeInfo += m_remainPosition;
+  for (int i = 0; i < 127; i++)
+    {
+      for (int j = 0; j < m_nodeHashes[i]->size(); j++)
+        {
+          subTreeInfo += (*m_nodeHashes[i])[j];
+        }
+      uint8_t flag = 0;
+      for (int j = m_nodeHashes[i]->size(); j < 32; j++)
+        {
+          subTreeInfo += flag;
+        }
+    }
+  return subTreeInfo;
+}
+
+void
+SubTree::resumeFromString(uint8_t remain, std::vector<ndn::BufferPtr> hashes)
+{
+  m_remainPosition = remain;
+  if (remain == 0)
+    {
+      for (int i = 0; i < hashes.size(); i++)
+        {
+          m_nodeHashes[i] = hashes[i];
+        }
+    }
+  else
+    {
+      for (int i = 0; i < hashes.size(); i++)
+        {
+          m_nodeHashes[63 + i] = hashes[i];
+        }
+      uint8_t i_ = 6;
+      uint8_t lastNo = 126 - m_remainPosition;
+      for (; i_ > 0; i_--)
+        {
+          for (int i = int(pow(2, i_)) - 1; i <= lastNo; i+= 2)
+            {
+              if ((i + 1) <= lastNo)
+                {
+                  uint8_t up_idx = (i-1) / 2;
+                  Auditor hasher;
+                  ndn::ConstBufferPtr buf = hasher.computeHash(m_nodeHashes[i],
+                                                               m_nodeHashes[i + 1]);
+                  m_nodeHashes[up_idx] = ndn::make_shared<ndn::Buffer>(*buf);
+                }
+              else
+                {
+                  uint8_t up_idx = (i-1) / 2;
+                  Auditor hasher;
+                  ndn::ConstBufferPtr buf = hasher.computeHashOneSide(m_nodeHashes[i]);
+                  m_nodeHashes[up_idx] = ndn::make_shared<ndn::Buffer>(*buf);
+                }
+            }
+          lastNo = (lastNo - 1) / 2;
+        }
+    }
+}
+
+
+} // namespace nsl
diff --git a/core/sub-tree.hpp b/core/sub-tree.hpp
new file mode 100644
index 0000000..55a0f53
--- /dev/null
+++ b/core/sub-tree.hpp
@@ -0,0 +1,105 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NSL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @author Peizhen Guo <patrick.guopz@gmail.com>
+ */
+#ifndef NLS_CORE_SUB_TREE_CACHE_HPP
+#define NLS_CORE_SUB_TREE_CACHE_HPP
+
+#include <ndn-cxx/encoding/buffer.hpp>
+#include <stdint.h>
+#include <string.h>
+
+#include "node.hpp"
+
+namespace nsl {
+
+typedef ndn::function<void(uint8_t, ndn::ConstBufferPtr)> CallBack;
+
+class SubTree
+{
+public:
+  SubTree()
+  {
+  }
+
+  SubTree(Index rootIndex, CallBack callBackFunction)
+    : m_root(rootIndex),
+      m_remainPosition(64),
+      m_callBackUpdate(callBackFunction)
+  {
+    for (int i = 0; i < 127; i++)
+      {
+        m_nodeHashes.push_back(ndn::BufferPtr(new ndn::Buffer));
+      }
+  }
+
+  ~SubTree()
+  {
+  }
+
+  void
+  addNode(ndn::ConstBufferPtr hash_ptr);
+
+  Index
+  getRootIndex();
+
+  uint8_t
+  getRemainPosition();
+
+  Index
+  getParentRootIndex();
+
+  ndn::ConstBufferPtr
+  getHash(Index nodeIndex);
+
+  // change when subtree's root hash below it changes
+  void
+  updateLeafHash(Index subRootIndex, ndn::ConstBufferPtr hash);
+
+
+  // decode is implemented in MerkleTreeCache class
+  std::string
+  encoding();
+
+  void
+  resumeFromString(uint8_t remain, std::vector<ndn::BufferPtr> hashes);
+
+private:
+
+  void
+  updateHash();
+
+
+private:
+
+  //Based on the following sequence number
+  //         0
+  //    1          2
+  //  3   4     5     6
+  // 7 8 9 10 11 12 13 14
+  std::vector<ndn::BufferPtr> m_nodeHashes;
+  Index m_root;
+  uint8_t m_remainPosition;
+  CallBack m_callBackUpdate;
+};
+
+
+} // namespace nsl
+
+#endif // NLS_CORE_SUB_TREE_CACHE_HPP