From 00ab5ed0cf3139d602b1c5e77a9991a9fd946ff3 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 5 Jul 2012 18:27:40 -0700 Subject: [PATCH] Low-level support for transaction metadata. --- src/HashPrefixes.h | 17 ++++++++++------- src/Ledger.cpp | 6 ++++-- src/LedgerNode.cpp | 4 ++-- src/SHAMap.cpp | 22 ++++++++++++---------- src/SHAMap.h | 27 +++++++++++++++------------ src/SHAMapNodes.cpp | 39 +++++++++++++++++++++++++++++++++------ src/SHAMapSync.cpp | 4 ++-- 7 files changed, 78 insertions(+), 41 deletions(-) diff --git a/src/HashPrefixes.h b/src/HashPrefixes.h index 80c3d79685..832349ec64 100644 --- a/src/HashPrefixes.h +++ b/src/HashPrefixes.h @@ -3,25 +3,28 @@ #include "types.h" -// TXN +// TXN - Hash of transaction plus signature to give transaction ID const uint32 sHP_TransactionID = 0x54584E00; -// STX +// STX - Hash of inner transaction to sign const uint32 sHP_TransactionSign = 0x53545800; -// MLN +// TND - Hash of transaction plus metadata +const uint32 sHP_TransactionNode = 0x534E4400; + +// MLN - Hash of account state const uint32 sHP_LeafNode = 0x4D4C4E00; -// MIN +// MIN - Hash of inner node in tree const uint32 sHP_InnerNode = 0x4D494E00; -// LGR +// LGR - Hash of ledger master data for signing const uint32 sHP_Ledger = 0x4C575200; -// VAL +// VAL - Hash of validation for signing const uint32 sHP_Validation = 0x56414C00; -// PRP +// PRP - Hash of proposal for signing const uint32 sHP_Proposal = 0x50525000; #endif diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 0edc03620b..728e713b23 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -186,14 +186,16 @@ bool Ledger::addTransaction(Transaction::pointer trans) Serializer s; trans->getSTransaction()->add(s); SHAMapItem::pointer item = boost::make_shared(trans->getID(), s.peekData()); - if (!mTransactionMap->addGiveItem(item, true)) return false; + if (!mTransactionMap->addGiveItem(item, true, false)) // FIXME: TX metadata + return false; return true; } bool Ledger::addTransaction(const uint256& txID, const Serializer& txn) { // low-level - just add to table SHAMapItem::pointer item = boost::make_shared(txID, txn.peekData()); - if (!mTransactionMap->addGiveItem(item, true)) return false; + if (!mTransactionMap->addGiveItem(item, true, false)) // FIXME: TX metadata + return false; return true; } diff --git a/src/LedgerNode.cpp b/src/LedgerNode.cpp index d059b9c3e7..c600c8f367 100644 --- a/src/LedgerNode.cpp +++ b/src/LedgerNode.cpp @@ -27,7 +27,7 @@ LedgerStateParms Ledger::writeBack(LedgerStateParms parms, SLE::pointer entry) if (create) { assert(!mAccountStateMap->hasItem(entry->getIndex())); - if(!mAccountStateMap->addGiveItem(item, false)) + if(!mAccountStateMap->addGiveItem(item, false, false)) // FIXME: TX metadata { assert(false); return lepERROR; @@ -35,7 +35,7 @@ LedgerStateParms Ledger::writeBack(LedgerStateParms parms, SLE::pointer entry) return lepCREATED; } - if (!mAccountStateMap->updateGiveItem(item, false)) + if (!mAccountStateMap->updateGiveItem(item, false, false)) // FIXME: TX metadata { assert(false); return lepERROR; diff --git a/src/SHAMap.cpp b/src/SHAMap.cpp index cc27ed70b6..faa27d3d98 100644 --- a/src/SHAMap.cpp +++ b/src/SHAMap.cpp @@ -488,14 +488,15 @@ bool SHAMap::delItem(const uint256& id) return true; } -bool SHAMap::addGiveItem(SHAMapItem::pointer item, bool isTransaction) +bool SHAMap::addGiveItem(SHAMapItem::pointer item, bool isTransaction, bool hasMeta) { // add the specified item, does not update #ifdef ST_DEBUG std::cerr << "aGI " << item->getTag().GetHex() << std::endl; #endif uint256 tag = item->getTag(); - SHAMapTreeNode::TNType type = isTransaction ? SHAMapTreeNode::tnTRANSACTION : SHAMapTreeNode::tnACCOUNT_STATE; + SHAMapTreeNode::TNType type = !isTransaction ? SHAMapTreeNode::tnACCOUNT_STATE : + (hasMeta ? SHAMapTreeNode::tnTRANSACTION_MD : SHAMapTreeNode::tnTRANSACTION_NM); boost::recursive_mutex::scoped_lock sl(mLock); assert(mState != Immutable); @@ -580,12 +581,12 @@ bool SHAMap::addGiveItem(SHAMapItem::pointer item, bool isTransaction) return true; } -bool SHAMap::addItem(const SHAMapItem& i, bool isTransaction) +bool SHAMap::addItem(const SHAMapItem& i, bool isTransaction, bool hasMetaData) { - return addGiveItem(boost::make_shared(i), isTransaction); + return addGiveItem(boost::make_shared(i), isTransaction, hasMetaData); } -bool SHAMap::updateGiveItem(SHAMapItem::pointer item, bool isTransaction) +bool SHAMap::updateGiveItem(SHAMapItem::pointer item, bool isTransaction, bool hasMeta) { // can't change the tag but can change the hash uint256 tag = item->getTag(); @@ -605,7 +606,8 @@ bool SHAMap::updateGiveItem(SHAMapItem::pointer item, bool isTransaction) } returnNode(node, true); - if (!node->setItem(item, isTransaction ? SHAMapTreeNode::tnTRANSACTION : SHAMapTreeNode::tnACCOUNT_STATE)) + if (!node->setItem(item, !isTransaction ? SHAMapTreeNode::tnACCOUNT_STATE : + (hasMeta ? SHAMapTreeNode::tnTRANSACTION_MD : SHAMapTreeNode::tnTRANSACTION_NM))) { Log(lsWARNING) << "SHAMap setItem, no change"; return true; @@ -747,8 +749,8 @@ BOOST_AUTO_TEST_CASE( SHAMap_test ) SHAMap sMap; SHAMapItem i1(h1, IntToVUC(1)), i2(h2, IntToVUC(2)), i3(h3, IntToVUC(3)), i4(h4, IntToVUC(4)), i5(h5, IntToVUC(5)); - if(!sMap.addItem(i2, true)) BOOST_FAIL("no add"); - if(!sMap.addItem(i1, true)) BOOST_FAIL("no add"); + if(!sMap.addItem(i2, true, false)) BOOST_FAIL("no add"); + if(!sMap.addItem(i1, true, false)) BOOST_FAIL("no add"); SHAMapItem::pointer i; @@ -759,9 +761,9 @@ BOOST_AUTO_TEST_CASE( SHAMap_test ) i = sMap.peekNextItem(i->getTag()); if (i) BOOST_FAIL("bad traverse"); - sMap.addItem(i4, true); + sMap.addItem(i4, true, false); sMap.delItem(i2.getTag()); - sMap.addItem(i3, true); + sMap.addItem(i3, true, false); i = sMap.peekFirstItem(); if (!i || (*i != i1)) BOOST_FAIL("bad traverse"); diff --git a/src/SHAMap.h b/src/SHAMap.h index 08685a6b39..a2a7ed3e0a 100644 --- a/src/SHAMap.h +++ b/src/SHAMap.h @@ -61,7 +61,7 @@ public: bool operator!=(const uint256&) const; bool operator<=(const SHAMapNode&) const; bool operator>=(const SHAMapNode&) const; - bool isRoot() const { return mDepth==0; } + bool isRoot() const { return mDepth == 0; } virtual std::string getString() const; void dump() const; @@ -133,10 +133,11 @@ public: enum TNType { - tnERROR = 0, - tnINNER = 1, - tnTRANSACTION = 2, - tnACCOUNT_STATE = 3 + tnERROR = 0, + tnINNER = 1, + tnTRANSACTION_NM = 2, // transaction, no metadata + tnTRANSACTION_MD = 3, // transaction, with metadata + tnACCOUNT_STATE = 4 }; private: @@ -173,11 +174,13 @@ public: TNType getType() const { return mType; } // type functions - bool isLeaf() const { return (mType == tnTRANSACTION) || (mType == tnACCOUNT_STATE); } + bool isLeaf() const { return (mType == tnTRANSACTION_NM) || (mType == tnTRANSACTION_MD) || + (mType == tnACCOUNT_STATE); } bool isInner() const { return mType == tnINNER; } bool isValid() const { return mType != tnERROR; } - bool isTransaction() const { return mType != tnTRANSACTION; } - bool isAccountState() const { return mType != tnACCOUNT_STATE; } + bool isTransaction() const { return (mType == tnTRANSACTION_NM) || (mType == tnTRANSACTION_MD); } + bool hasMetaData() const { return mType == tnTRANSACTION_MD; } + bool isAccountState() const { return mType == tnACCOUNT_STATE; } // inner node functions bool isInnerNode() const { return !mItem; } @@ -299,15 +302,15 @@ public: // normal hash access functions bool hasItem(const uint256& id); bool delItem(const uint256& id); - bool addItem(const SHAMapItem& i, bool isTransaction); - bool updateItem(const SHAMapItem& i, bool isTransaction); + bool addItem(const SHAMapItem& i, bool isTransaction, bool hasMeta); + bool updateItem(const SHAMapItem& i, bool isTransaction, bool hasMeta); SHAMapItem getItem(const uint256& id); uint256 getHash() const { return root->getNodeHash(); } uint256 getHash() { return root->getNodeHash(); } // save a copy if you have a temporary anyway - bool updateGiveItem(SHAMapItem::pointer, bool isTransaction); - bool addGiveItem(SHAMapItem::pointer, bool isTransaction); + bool updateGiveItem(SHAMapItem::pointer, bool isTransaction, bool hasMeta); + bool addGiveItem(SHAMapItem::pointer, bool isTransaction, bool hasMeta); // save a copy if you only need a temporary SHAMapItem::pointer peekItem(const uint256& id); diff --git a/src/SHAMapNodes.cpp b/src/SHAMapNodes.cpp index 32d9b65d80..b8edb5e20f 100644 --- a/src/SHAMapNodes.cpp +++ b/src/SHAMapNodes.cpp @@ -197,7 +197,7 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector 3)) + if ((type < 0) || (type > 4)) { #ifdef DEBUG std::cerr << "Invalid wire format node" << std::endl; @@ -210,7 +210,7 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector(s.getPrefixHash(sHP_TransactionID), s.peekData()); - mType = tnTRANSACTION; + mType = tnTRANSACTION_NM; } else if (type == 1) { // account state @@ -242,6 +242,11 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector(s.getPrefixHash(sHP_TransactionNode), s.peekData()); + mType = tnTRANSACTION_MD; + } } if (format == STN_ARF_PREFIXED) @@ -259,7 +264,7 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector(s.getSHA512Half(), s.peekData()); - mType = tnTRANSACTION; + mType = tnTRANSACTION_NM; } else if (prefix == sHP_LeafNode) { @@ -271,7 +276,7 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector(u, s.peekData()); + mItem = boost::make_shared(u, s.peekData()); mType = tnACCOUNT_STATE; } else if (prefix == sHP_InnerNode) @@ -282,6 +287,11 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector(s.getPrefixHash(sHP_TransactionNode), s.peekData()); + mType = tnTRANSACTION_MD; + } else { Log(lsINFO) << "Unknown node prefix " << std::hex << prefix << std::dec; @@ -316,10 +326,14 @@ bool SHAMapTreeNode::updateHash() s.add256(mItem->getTag()); nh = s.getSHA512Half(); } - else if (mType == tnTRANSACTION) + else if (mType == tnTRANSACTION_NM) { nh = Serializer::getPrefixHash(sHP_TransactionID, mItem->peekData()); } + else if (mType == tnTRANSACTION_MD) + { + nh = Serializer::getPrefixHash(sHP_TransactionNode, mItem->peekData()); + } else assert(false); if (nh == mHash) return false; @@ -375,7 +389,7 @@ void SHAMapTreeNode::addRaw(Serializer& s, int format) s.add8(1); } } - else if (mType == tnTRANSACTION) + else if (mType == tnTRANSACTION_NM) { if (format == STN_ARF_PREFIXED) { @@ -388,6 +402,19 @@ void SHAMapTreeNode::addRaw(Serializer& s, int format) s.add8(0); } } + else if (mType == tnTRANSACTION_MD) + { + if (format == STN_ARF_PREFIXED) + { + s.add32(sHP_TransactionNode); + mItem->addRaw(s); + } + else + { + mItem->addRaw(s); + s.add8(4); + } + } else assert(false); } diff --git a/src/SHAMapSync.cpp b/src/SHAMapSync.cpp index 763dd15147..3cc13b2995 100644 --- a/src/SHAMapSync.cpp +++ b/src/SHAMapSync.cpp @@ -362,7 +362,7 @@ static bool confuseMap(SHAMap &map, int count) { SHAMapItem::pointer item = makeRandomAS(); items.push_back(item->getTag()); - if (!map.addItem(*item, false)) + if (!map.addItem(*item, false, false)) { Log(lsFATAL) << "Unable to add item to map"; return false; @@ -423,7 +423,7 @@ BOOST_AUTO_TEST_CASE( SHAMapSync_test ) Log(lsTRACE) << "Adding random data"; int items = 10000; for (int i = 0; i < items; ++i) - source.addItem(*makeRandomAS(), false); + source.addItem(*makeRandomAS(), false, false); Log(lsTRACE) << "Adding items, then removing them"; if (!confuseMap(source, 500)) BOOST_FAIL("ConfuseMap");