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