#include "Serializer.h" #include "BitcoinUtil.h" #include "SHAMap.h" #include SHAMap::SHAMap(int leafDataSize, int leafDataOffset) : mLeafDataSize(leafDataSize), mLeafDataOffset(leafDataOffset) { ; } void SHAMap::dirtyUp(const uint256& id, const std::vector& path) { // walk the tree up from through the inner nodes to the root // update linking hashes and add nodes to dirty list std::vector::const_reverse_iterator it; it = path.rbegin(); if(it == path.rend()) return; mDirtyInnerNodes[**it]=*it; uint256 hVal=(*it)->getNodeHash(); if(hVal==0) mInnerNodeByID.erase(**it); for(++it; itsetChildHash((*it)->selectBranch(id), hVal)) return; mDirtyInnerNodes[**it]=*it; hVal = (*it)->getNodeHash(); if(hVal == 0) mInnerNodeByID.erase(**it); } assert(**it == *root); } SHAMapLeafNode::pointer SHAMap::checkCacheLeaf(const SHAMapNode& iNode) { assert(iNode.isLeaf()); return mLeafByID[iNode]; } SHAMapLeafNode::pointer SHAMap::walkToLeaf(const uint256& id, bool create, std::vector& path) { // walk down to the leaf that would contain this ID // is leaf node in cache SHAMapLeafNode::pointer ln=checkCacheLeaf(SHAMapNode(SHAMapNode::leafDepth, id)); if(ln != SHAMapLeafNode::pointer()) return ln; // walk tree to leaf SHAMapInnerNode::pointer inNode=root; path.push_back(inNode); for(int i=1; iselectBranch(id); if(branch<0) { // somehow we got on the wrong branch assert(false); return SHAMapLeafNode::pointer(); } if(inNode->isEmptyBranch(branch)) { // no nodes below this one if(!create) return SHAMapLeafNode::pointer(); return createLeaf(*inNode, id, path); } if(i!=(SHAMapNode::leafDepth)-1) { // child is another inner node inNode=getInner(inNode->getChildNodeID(branch), inNode->getChildHash(branch)); if(inNode==NULL) return SHAMapLeafNode::pointer(); // we don't have the node path.push_back(inNode); } else // child is leaf node { ln=getLeaf(inNode->getChildNodeID(branch), inNode->getChildHash(branch)); if(ln==NULL) { if(!create) return SHAMapLeafNode::pointer(); return createLeaf(*inNode, id, path); } } } return ln; } SHAMapLeafNode::pointer SHAMap::getLeaf(const SHAMapNode &id, const uint256& hash) { // retrieve a leaf whose node hash is known assert(!!hash); SHAMapLeafNode::pointer leaf=mLeafByID[id]; // is the leaf in memory if(leaf != SHAMapLeafNode::pointer()) return leaf; std::vector rawNode; // is it in backing store if(!fetchNode(hash, id, rawNode)) return leaf; Serializer s(rawNode); leaf=SHAMapLeafNode::pointer(new SHAMapLeafNode(id)); for(int i=0; iaddUpdateItem(SHAMapItem::pointer(new SHAMapItem(tag, s.getRaw(i, mLeafDataSize)))); } leaf->updateHash(); mLeafByID[*leaf]=leaf; assert(leaf->getNodeHash()==hash); return leaf; } SHAMapInnerNode::pointer SHAMap::getInner(const SHAMapNode &id, const uint256& hash) { // retrieve an inner node whose node hash is known SHAMapInnerNode::pointer node=mInnerNodeByID[id]; if(node != SHAMapInnerNode::pointer()) return node; std::vector rawNode; if(!fetchNode(hash, id, rawNode)) return node; node=SHAMapInnerNode::pointer(new SHAMapInnerNode(id, rawNode)); if(node->getNodeHash()!=hash) { badNode(hash, id); return SHAMapInnerNode::pointer(); } mInnerNodeByID[id]=node; return node; } SHAMapItem::SHAMapItem(const uint256& tag) : mTag(tag) { mData.insert(mData.end(), tag.begin(), tag.end()); } SHAMapItem::SHAMapItem(const uint256& tag, const std::vector& data) : mTag(tag), mData(data) { ; } SHAMapItem::pointer SHAMap::firstItem() { ScopedLock sl(mLock); return firstBelow(root); } SHAMapItem::pointer SHAMap::lastItem() { ScopedLock sl(mLock); return lastBelow(root); } SHAMapItem::pointer SHAMap::firstBelow(SHAMapInnerNode::pointer Node) { const uint256 zero; int i; while(Node->isChildLeaf()) { for(i=0; i<32; i++) { uint256 cHash(Node->getChildHash(i)); if(cHash!=zero) { Node=getInner(Node->getChildNodeID(i), cHash); if(Node==SHAMapInnerNode::pointer()) return SHAMapItem::pointer(); break; } } if(i==32) return SHAMapItem::pointer(); } for(int i=0; i<32; i++) { uint256 cHash=Node->getChildHash(i); if(cHash!=zero) { SHAMapLeafNode::pointer mLeaf=getLeaf(Node->getChildNodeID(i), cHash); if(mLeaf==SHAMapLeafNode::pointer()) return SHAMapItem::pointer(); return mLeaf->firstItem(); } } return SHAMapItem::pointer(); } SHAMapItem::pointer SHAMap::lastBelow(SHAMapInnerNode::pointer Node) { ScopedLock sl(mLock); const uint256 zero; int i; while(Node->isChildLeaf()) { for(i=31; i>=0; i--) { uint256 cHash(Node->getChildHash(i)); if(cHash!=0) { Node=getInner(Node->getChildNodeID(i), cHash); if(Node==SHAMapInnerNode::pointer()) return SHAMapItem::pointer(); break; } } if(i<0) return SHAMapItem::pointer(); } for(int i=31; i>=0; i--) { uint256 cHash=Node->getChildHash(i); if(cHash!=zero) { SHAMapLeafNode::pointer mLeaf=getLeaf(Node->getChildNodeID(i), cHash); if(mLeaf==SHAMapLeafNode::pointer()) return SHAMapItem::pointer(); return mLeaf->lastItem(); } } } SHAMapItem::pointer SHAMap::nextItem(const SHAMapItem &) { // WRITEME } SHAMapItem::pointer SHAMap::prevItem(const SHAMapItem &) { // WRITEME } SHAMapLeafNode::pointer SHAMap::createLeaf(const SHAMapInnerNode& lowestParent, const uint256& id, std::vector& path) { int depth=lowestParent.getDepth(); for(int depth=lowestParent.getDepth(); depth path; SHAMapLeafNode::pointer leaf=walkToLeaf(id, false, path); if(leaf == SHAMapLeafNode::pointer()) return false; SHAMapItem::pointer item=leaf->findItem(id); return item == SHAMapItem::pointer(); } bool SHAMap::delItem(const uint256& id) { // delete the item with this ID ScopedLock sl(mLock); std::vector path; SHAMapLeafNode::pointer leaf=walkToLeaf(id, false, path); if(leaf == SHAMapLeafNode::pointer()) return false; if(!leaf->delItem(id)) return false; dirtyUp(id, path); } bool SHAMap::addItem(SHAMapItem::pointer item) { // add the specified item ScopedLock sl(mLock); std::vector path; SHAMapLeafNode::pointer leaf=walkToLeaf(item->getTag(), true, path); if(leaf == SHAMapLeafNode::pointer()) return false; if(!leaf->addUpdateItem(item)) return false; dirtyUp(item->getTag(), path); } void SHAMapItem::dump() { std::cerr << "SHAMapItem(" << mTag.GetHex() << ") " << mData.size() << "bytes" << std::endl; } void SHAMap::dump() { } void TestSHAMap() { uint256 h1, h2, h3, h4, h5; h1.SetHex("436ccbac3347baa1f1e53baeef1f43334da88f1f6d70d963b833afd6dfa289fe"); h2.SetHex("b92891fe4ef6cee585fdc6fda0e09eb4d386363158ec3321b8123e5a772c6ca7"); h3.SetHex("b92891fe4ef6cee585fdc6fda0e09eb4d386363158ec3321b8123e5a772c6ca8"); h4.SetHex("a92891fe4ef6cee585fdc6fda0e09eb4d386363158ec3321b8123e5a772c6ca7"); h5.SetHex("092891fe4ef6cee585fdc6fda0e09eb4d386363158ec3321b8123e5a772c6ca7"); SHAMap sMap(32); SHAMapItem i1(h1), i2(h2), i3(h3), i4(h4), i5(h5); sMap.dump(); }