mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
Refactor and improve the SHAMap code:
This commit combines a number of cleanups, targeting both the code structure and the code logic. Large changes include: - Using more strongly-typed classes for SHAMap nodes, instead of relying on runtime-time detection of class types. This change saves 16 bytes of memory per node. - Improving the interface of SHAMap::addGiveItem and SHAMap::addItem to avoid the need for passing two bool arguments. - Documenting the "copy-on-write" semantics that SHAMap uses to efficiently track changes in individual nodes. - Removing unused code and simplifying several APIs. - Improving function naming.
This commit is contained in:
@@ -635,7 +635,9 @@ target_sources (rippled PRIVATE
|
|||||||
src/ripple/shamap/impl/NodeFamily.cpp
|
src/ripple/shamap/impl/NodeFamily.cpp
|
||||||
src/ripple/shamap/impl/SHAMap.cpp
|
src/ripple/shamap/impl/SHAMap.cpp
|
||||||
src/ripple/shamap/impl/SHAMapDelta.cpp
|
src/ripple/shamap/impl/SHAMapDelta.cpp
|
||||||
|
src/ripple/shamap/impl/SHAMapInnerNode.cpp
|
||||||
src/ripple/shamap/impl/SHAMapItem.cpp
|
src/ripple/shamap/impl/SHAMapItem.cpp
|
||||||
|
src/ripple/shamap/impl/SHAMapLeafNode.cpp
|
||||||
src/ripple/shamap/impl/SHAMapNodeID.cpp
|
src/ripple/shamap/impl/SHAMapNodeID.cpp
|
||||||
src/ripple/shamap/impl/SHAMapSync.cpp
|
src/ripple/shamap/impl/SHAMapSync.cpp
|
||||||
src/ripple/shamap/impl/SHAMapTreeNode.cpp
|
src/ripple/shamap/impl/SHAMapTreeNode.cpp
|
||||||
|
|||||||
@@ -315,9 +315,8 @@ RCLConsensus::Adaptor::onClose(
|
|||||||
Serializer s(2048);
|
Serializer s(2048);
|
||||||
tx.first->add(s);
|
tx.first->add(s);
|
||||||
initialSet->addItem(
|
initialSet->addItem(
|
||||||
SHAMapItem(tx.first->getTransactionID(), std::move(s)),
|
SHAMapNodeType::tnTRANSACTION_NM,
|
||||||
true,
|
SHAMapItem(tx.first->getTransactionID(), std::move(s)));
|
||||||
false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add pseudo-transactions to the set
|
// Add pseudo-transactions to the set
|
||||||
|
|||||||
@@ -91,7 +91,8 @@ public:
|
|||||||
insert(Tx const& t)
|
insert(Tx const& t)
|
||||||
{
|
{
|
||||||
return map_->addItem(
|
return map_->addItem(
|
||||||
SHAMapItem{t.id(), t.tx_.peekData()}, true, false);
|
SHAMapNodeType::tnTRANSACTION_NM,
|
||||||
|
SHAMapItem{t.id(), t.tx_.peekData()});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Remove a transaction from the set.
|
/** Remove a transaction from the set.
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ AccountStateSF::gotNode(
|
|||||||
SHAMapHash const& nodeHash,
|
SHAMapHash const& nodeHash,
|
||||||
std::uint32_t ledgerSeq,
|
std::uint32_t ledgerSeq,
|
||||||
Blob&& nodeData,
|
Blob&& nodeData,
|
||||||
SHAMapTreeNode::TNType) const
|
SHAMapNodeType) const
|
||||||
{
|
{
|
||||||
db_.store(
|
db_.store(
|
||||||
hotACCOUNT_NODE, std::move(nodeData), nodeHash.as_uint256(), ledgerSeq);
|
hotACCOUNT_NODE, std::move(nodeData), nodeHash.as_uint256(), ledgerSeq);
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ public:
|
|||||||
SHAMapHash const& nodeHash,
|
SHAMapHash const& nodeHash,
|
||||||
std::uint32_t ledgerSeq,
|
std::uint32_t ledgerSeq,
|
||||||
Blob&& nodeData,
|
Blob&& nodeData,
|
||||||
SHAMapTreeNode::TNType type) const override;
|
SHAMapNodeType type) const override;
|
||||||
|
|
||||||
boost::optional<Blob>
|
boost::optional<Blob>
|
||||||
getNode(SHAMapHash const& nodeHash) const override;
|
getNode(SHAMapHash const& nodeHash) const override;
|
||||||
|
|||||||
@@ -41,14 +41,14 @@ ConsensusTransSetSF::gotNode(
|
|||||||
SHAMapHash const& nodeHash,
|
SHAMapHash const& nodeHash,
|
||||||
std::uint32_t,
|
std::uint32_t,
|
||||||
Blob&& nodeData,
|
Blob&& nodeData,
|
||||||
SHAMapTreeNode::TNType type) const
|
SHAMapNodeType type) const
|
||||||
{
|
{
|
||||||
if (fromFilter)
|
if (fromFilter)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_nodeCache.insert(nodeHash, nodeData);
|
m_nodeCache.insert(nodeHash, nodeData);
|
||||||
|
|
||||||
if ((type == SHAMapTreeNode::tnTRANSACTION_NM) && (nodeData.size() > 16))
|
if ((type == SHAMapNodeType::tnTRANSACTION_NM) && (nodeData.size() > 16))
|
||||||
{
|
{
|
||||||
// this is a transaction, and we didn't have it
|
// this is a transaction, and we didn't have it
|
||||||
JLOG(j_.debug())
|
JLOG(j_.debug())
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ public:
|
|||||||
SHAMapHash const& nodeHash,
|
SHAMapHash const& nodeHash,
|
||||||
std::uint32_t ledgerSeq,
|
std::uint32_t ledgerSeq,
|
||||||
Blob&& nodeData,
|
Blob&& nodeData,
|
||||||
SHAMapTreeNode::TNType type) const override;
|
SHAMapNodeType type) const override;
|
||||||
|
|
||||||
boost::optional<Blob>
|
boost::optional<Blob>
|
||||||
getNode(SHAMapHash const& nodeHash) const override;
|
getNode(SHAMapHash const& nodeHash) const override;
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ Ledger::Ledger(
|
|||||||
rawInsert(sle);
|
rawInsert(sle);
|
||||||
}
|
}
|
||||||
|
|
||||||
stateMap_->flushDirty(hotACCOUNT_NODE, info_.seq);
|
stateMap_->flushDirty(hotACCOUNT_NODE);
|
||||||
setImmutable(config);
|
setImmutable(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -354,7 +354,7 @@ bool
|
|||||||
Ledger::addSLE(SLE const& sle)
|
Ledger::addSLE(SLE const& sle)
|
||||||
{
|
{
|
||||||
SHAMapItem item(sle.key(), sle.getSerializer());
|
SHAMapItem item(sle.key(), sle.getSerializer());
|
||||||
return stateMap_->addItem(std::move(item), false, false);
|
return stateMap_->addItem(SHAMapNodeType::tnACCOUNT_STATE, std::move(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -499,8 +499,9 @@ Ledger::rawInsert(std::shared_ptr<SLE> const& sle)
|
|||||||
{
|
{
|
||||||
Serializer ss;
|
Serializer ss;
|
||||||
sle->add(ss);
|
sle->add(ss);
|
||||||
auto item = std::make_shared<SHAMapItem const>(sle->key(), std::move(ss));
|
if (!stateMap_->addGiveItem(
|
||||||
if (!stateMap_->addGiveItem(std::move(item), false, false))
|
SHAMapNodeType::tnACCOUNT_STATE,
|
||||||
|
std::make_shared<SHAMapItem const>(sle->key(), std::move(ss))))
|
||||||
LogicError("Ledger::rawInsert: key already exists");
|
LogicError("Ledger::rawInsert: key already exists");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -509,9 +510,9 @@ Ledger::rawReplace(std::shared_ptr<SLE> const& sle)
|
|||||||
{
|
{
|
||||||
Serializer ss;
|
Serializer ss;
|
||||||
sle->add(ss);
|
sle->add(ss);
|
||||||
auto item = std::make_shared<SHAMapItem const>(sle->key(), std::move(ss));
|
if (!stateMap_->updateGiveItem(
|
||||||
|
SHAMapNodeType::tnACCOUNT_STATE,
|
||||||
if (!stateMap_->updateGiveItem(std::move(item), false, false))
|
std::make_shared<SHAMapItem const>(sle->key(), std::move(ss))))
|
||||||
LogicError("Ledger::rawReplace: key not found");
|
LogicError("Ledger::rawReplace: key not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,8 +528,9 @@ Ledger::rawTxInsert(
|
|||||||
Serializer s(txn->getDataLength() + metaData->getDataLength() + 16);
|
Serializer s(txn->getDataLength() + metaData->getDataLength() + 16);
|
||||||
s.addVL(txn->peekData());
|
s.addVL(txn->peekData());
|
||||||
s.addVL(metaData->peekData());
|
s.addVL(metaData->peekData());
|
||||||
auto item = std::make_shared<SHAMapItem const>(key, std::move(s));
|
if (!txMap().addGiveItem(
|
||||||
if (!txMap().addGiveItem(std::move(item), true, true))
|
SHAMapNodeType::tnTRANSACTION_MD,
|
||||||
|
std::make_shared<SHAMapItem const>(key, std::move(s))))
|
||||||
LogicError("duplicate_tx: " + to_string(key));
|
LogicError("duplicate_tx: " + to_string(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ public:
|
|||||||
std::shared_ptr<STTx const>
|
std::shared_ptr<STTx const>
|
||||||
fetch(
|
fetch(
|
||||||
std::shared_ptr<SHAMapItem> const& item,
|
std::shared_ptr<SHAMapItem> const& item,
|
||||||
SHAMapTreeNode::TNType type,
|
SHAMapNodeType type,
|
||||||
std::uint32_t uCommitLedger);
|
std::uint32_t uCommitLedger);
|
||||||
|
|
||||||
// return value: true = we had the transaction already
|
// return value: true = we had the transaction already
|
||||||
|
|||||||
@@ -27,10 +27,10 @@ TransactionStateSF::gotNode(
|
|||||||
SHAMapHash const& nodeHash,
|
SHAMapHash const& nodeHash,
|
||||||
std::uint32_t ledgerSeq,
|
std::uint32_t ledgerSeq,
|
||||||
Blob&& nodeData,
|
Blob&& nodeData,
|
||||||
SHAMapTreeNode::TNType type) const
|
SHAMapNodeType type) const
|
||||||
|
|
||||||
{
|
{
|
||||||
assert(type != SHAMapTreeNode::tnTRANSACTION_NM);
|
assert(type != SHAMapNodeType::tnTRANSACTION_NM);
|
||||||
db_.store(
|
db_.store(
|
||||||
hotTRANSACTION_NODE,
|
hotTRANSACTION_NODE,
|
||||||
std::move(nodeData),
|
std::move(nodeData),
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ public:
|
|||||||
SHAMapHash const& nodeHash,
|
SHAMapHash const& nodeHash,
|
||||||
std::uint32_t ledgerSeq,
|
std::uint32_t ledgerSeq,
|
||||||
Blob&& nodeData,
|
Blob&& nodeData,
|
||||||
SHAMapTreeNode::TNType type) const override;
|
SHAMapNodeType type) const override;
|
||||||
|
|
||||||
boost::optional<Blob>
|
boost::optional<Blob>
|
||||||
getNode(SHAMapHash const& nodeHash) const override;
|
getNode(SHAMapHash const& nodeHash) const override;
|
||||||
|
|||||||
@@ -67,10 +67,8 @@ buildLedgerImpl(
|
|||||||
// Write the final version of all modified SHAMap
|
// Write the final version of all modified SHAMap
|
||||||
// nodes to the node store to preserve the new LCL
|
// nodes to the node store to preserve the new LCL
|
||||||
|
|
||||||
int const asf =
|
int const asf = built->stateMap().flushDirty(hotACCOUNT_NODE);
|
||||||
built->stateMap().flushDirty(hotACCOUNT_NODE, built->info().seq);
|
int const tmf = built->txMap().flushDirty(hotTRANSACTION_NODE);
|
||||||
int const tmf =
|
|
||||||
built->txMap().flushDirty(hotTRANSACTION_NODE, built->info().seq);
|
|
||||||
JLOG(j.debug()) << "Flushed " << asf << " accounts and " << tmf
|
JLOG(j.debug()) << "Flushed " << asf << " accounts and " << tmf
|
||||||
<< " transaction nodes";
|
<< " transaction nodes";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -235,36 +235,42 @@ InboundLedger::~InboundLedger()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint256>
|
static std::vector<uint256>
|
||||||
InboundLedger::neededTxHashes(int max, SHAMapSyncFilter* filter) const
|
neededHashes(
|
||||||
|
uint256 const& root,
|
||||||
|
SHAMap& map,
|
||||||
|
int max,
|
||||||
|
SHAMapSyncFilter* filter)
|
||||||
{
|
{
|
||||||
std::vector<uint256> ret;
|
std::vector<uint256> ret;
|
||||||
|
|
||||||
if (mLedger->info().txHash.isNonZero())
|
if (!root.isZero())
|
||||||
{
|
{
|
||||||
if (mLedger->txMap().getHash().isZero())
|
if (map.getHash().isZero())
|
||||||
ret.push_back(mLedger->info().txHash);
|
ret.push_back(root);
|
||||||
else
|
else
|
||||||
ret = mLedger->txMap().getNeededHashes(max, filter);
|
{
|
||||||
|
auto mn = map.getMissingNodes(max, filter);
|
||||||
|
ret.reserve(mn.size());
|
||||||
|
for (auto const& n : mn)
|
||||||
|
ret.push_back(n.second);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<uint256>
|
||||||
|
InboundLedger::neededTxHashes(int max, SHAMapSyncFilter* filter) const
|
||||||
|
{
|
||||||
|
return neededHashes(mLedger->info().txHash, mLedger->txMap(), max, filter);
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<uint256>
|
std::vector<uint256>
|
||||||
InboundLedger::neededStateHashes(int max, SHAMapSyncFilter* filter) const
|
InboundLedger::neededStateHashes(int max, SHAMapSyncFilter* filter) const
|
||||||
{
|
{
|
||||||
std::vector<uint256> ret;
|
return neededHashes(
|
||||||
|
mLedger->info().accountHash, mLedger->stateMap(), max, filter);
|
||||||
if (mLedger->info().accountHash.isNonZero())
|
|
||||||
{
|
|
||||||
if (mLedger->stateMap().getHash().isZero())
|
|
||||||
ret.push_back(mLedger->info().accountHash);
|
|
||||||
else
|
|
||||||
ret = mLedger->stateMap().getNeededHashes(max, filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LedgerInfo
|
LedgerInfo
|
||||||
|
|||||||
@@ -247,8 +247,8 @@ public:
|
|||||||
if (!node.has_nodeid() || !node.has_nodedata())
|
if (!node.has_nodeid() || !node.has_nodedata())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto newNode = SHAMapAbstractNode::makeFromWire(
|
auto newNode =
|
||||||
makeSlice(node.nodedata()));
|
SHAMapTreeNode::makeFromWire(makeSlice(node.nodedata()));
|
||||||
|
|
||||||
if (!newNode)
|
if (!newNode)
|
||||||
return;
|
return;
|
||||||
@@ -257,7 +257,7 @@ public:
|
|||||||
newNode->serializeWithPrefix(s);
|
newNode->serializeWithPrefix(s);
|
||||||
|
|
||||||
app_.getLedgerMaster().addFetchPack(
|
app_.getLedgerMaster().addFetchPack(
|
||||||
newNode->getNodeHash().as_uint256(),
|
newNode->getHash().as_uint256(),
|
||||||
std::make_shared<Blob>(s.begin(), s.end()));
|
std::make_shared<Blob>(s.begin(), s.end()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2033,6 +2033,64 @@ LedgerMaster::gotFetchPack(bool progress, std::uint32_t seq)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Populate a fetch pack with data from the map the recipient wants.
|
||||||
|
|
||||||
|
A recipient may or may not have the map that they are asking for. If
|
||||||
|
they do, we can optimize the transfer by not including parts of the
|
||||||
|
map that they are already have.
|
||||||
|
|
||||||
|
@param have The map that the recipient already has (if any).
|
||||||
|
@param cnt The maximum number of nodes to return.
|
||||||
|
@param into The protocol object into which we add information.
|
||||||
|
@param seq The sequence number of the ledger the map is a part of.
|
||||||
|
@param withLeaves True if leaf nodes should be included.
|
||||||
|
|
||||||
|
@note: The withLeaves parameter is configurable even though the
|
||||||
|
code, so far, only ever sets the parameter to true.
|
||||||
|
|
||||||
|
The rationale is that for transaction trees, it may make
|
||||||
|
sense to not include the leaves if the fetch pack is being
|
||||||
|
constructed for someone attempting to get a recent ledger
|
||||||
|
for which they already have the transactions.
|
||||||
|
|
||||||
|
However, for historical ledgers, which is the only use we
|
||||||
|
have for fetch packs right now, it makes sense to include
|
||||||
|
the transactions because the caller is unlikely to have
|
||||||
|
them.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
populateFetchPack(
|
||||||
|
SHAMap const& want,
|
||||||
|
SHAMap const* have,
|
||||||
|
std::uint32_t cnt,
|
||||||
|
protocol::TMGetObjectByHash* into,
|
||||||
|
std::uint32_t seq,
|
||||||
|
bool withLeaves = true)
|
||||||
|
{
|
||||||
|
assert(cnt != 0);
|
||||||
|
|
||||||
|
Serializer s(1024);
|
||||||
|
|
||||||
|
want.visitDifferences(
|
||||||
|
have,
|
||||||
|
[&s, withLeaves, &cnt, into, seq](SHAMapTreeNode const& n) -> bool {
|
||||||
|
if (!withLeaves && n.isLeaf())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
s.erase();
|
||||||
|
n.serializeWithPrefix(s);
|
||||||
|
|
||||||
|
auto const& hash = n.getHash().as_uint256();
|
||||||
|
|
||||||
|
protocol::TMIndexedObject* obj = into->add_objects();
|
||||||
|
obj->set_ledgerseq(seq);
|
||||||
|
obj->set_hash(hash.data(), hash.size());
|
||||||
|
obj->set_data(s.getDataPtr(), s.getLength());
|
||||||
|
|
||||||
|
return --cnt != 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LedgerMaster::makeFetchPack(
|
LedgerMaster::makeFetchPack(
|
||||||
std::weak_ptr<Peer> const& wPeer,
|
std::weak_ptr<Peer> const& wPeer,
|
||||||
@@ -2058,55 +2116,46 @@ LedgerMaster::makeFetchPack(
|
|||||||
if (!peer)
|
if (!peer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto haveLedger = getLedgerByHash(haveLedgerHash);
|
auto have = getLedgerByHash(haveLedgerHash);
|
||||||
|
|
||||||
if (!haveLedger)
|
if (!have)
|
||||||
{
|
{
|
||||||
JLOG(m_journal.info())
|
JLOG(m_journal.info())
|
||||||
<< "Peer requests fetch pack for ledger we don't have: "
|
<< "Peer requests fetch pack for ledger we don't have: " << have;
|
||||||
<< haveLedger;
|
|
||||||
peer->charge(Resource::feeRequestNoReply);
|
peer->charge(Resource::feeRequestNoReply);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (haveLedger->open())
|
if (have->open())
|
||||||
{
|
{
|
||||||
JLOG(m_journal.warn())
|
JLOG(m_journal.warn())
|
||||||
<< "Peer requests fetch pack from open ledger: " << haveLedger;
|
<< "Peer requests fetch pack from open ledger: " << have;
|
||||||
peer->charge(Resource::feeInvalidRequest);
|
peer->charge(Resource::feeInvalidRequest);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (haveLedger->info().seq < getEarliestFetch())
|
if (have->info().seq < getEarliestFetch())
|
||||||
{
|
{
|
||||||
JLOG(m_journal.debug()) << "Peer requests fetch pack that is too early";
|
JLOG(m_journal.debug()) << "Peer requests fetch pack that is too early";
|
||||||
peer->charge(Resource::feeInvalidRequest);
|
peer->charge(Resource::feeInvalidRequest);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto wantLedger = getLedgerByHash(haveLedger->info().parentHash);
|
auto want = getLedgerByHash(have->info().parentHash);
|
||||||
|
|
||||||
if (!wantLedger)
|
if (!want)
|
||||||
{
|
{
|
||||||
JLOG(m_journal.info())
|
JLOG(m_journal.info())
|
||||||
<< "Peer requests fetch pack for ledger whose predecessor we "
|
<< "Peer requests fetch pack for ledger whose predecessor we "
|
||||||
<< "don't have: " << haveLedger;
|
<< "don't have: " << have;
|
||||||
peer->charge(Resource::feeRequestNoReply);
|
peer->charge(Resource::feeRequestNoReply);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto fpAppender = [](protocol::TMGetObjectByHash* reply,
|
|
||||||
std::uint32_t ledgerSeq,
|
|
||||||
SHAMapHash const& hash,
|
|
||||||
const Blob& blob) {
|
|
||||||
protocol::TMIndexedObject& newObj = *(reply->add_objects());
|
|
||||||
newObj.set_ledgerseq(ledgerSeq);
|
|
||||||
newObj.set_hash(hash.as_uint256().begin(), 256 / 8);
|
|
||||||
newObj.set_data(&blob[0], blob.size());
|
|
||||||
};
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
Serializer hdr(128);
|
||||||
|
|
||||||
protocol::TMGetObjectByHash reply;
|
protocol::TMGetObjectByHash reply;
|
||||||
reply.set_query(false);
|
reply.set_query(false);
|
||||||
|
|
||||||
@@ -2121,56 +2170,49 @@ LedgerMaster::makeFetchPack(
|
|||||||
// 2. Add the nodes for the AccountStateMap of that ledger.
|
// 2. Add the nodes for the AccountStateMap of that ledger.
|
||||||
// 3. If there are transactions, add the nodes for the
|
// 3. If there are transactions, add the nodes for the
|
||||||
// transactions of the ledger.
|
// transactions of the ledger.
|
||||||
// 4. If the FetchPack now contains greater than or equal to
|
// 4. If the FetchPack now contains at least 512 entries then stop.
|
||||||
// 256 entries then stop.
|
|
||||||
// 5. If not very much time has elapsed, then loop back and repeat
|
// 5. If not very much time has elapsed, then loop back and repeat
|
||||||
// the same process adding the previous ledger to the FetchPack.
|
// the same process adding the previous ledger to the FetchPack.
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
std::uint32_t lSeq = wantLedger->info().seq;
|
std::uint32_t lSeq = want->info().seq;
|
||||||
|
|
||||||
protocol::TMIndexedObject& newObj = *reply.add_objects();
|
{
|
||||||
newObj.set_hash(wantLedger->info().hash.data(), 256 / 8);
|
// Serialize the ledger header:
|
||||||
Serializer s(256);
|
hdr.erase();
|
||||||
s.add32(HashPrefix::ledgerMaster);
|
|
||||||
addRaw(wantLedger->info(), s);
|
|
||||||
newObj.set_data(s.getDataPtr(), s.getLength());
|
|
||||||
newObj.set_ledgerseq(lSeq);
|
|
||||||
|
|
||||||
wantLedger->stateMap().getFetchPack(
|
hdr.add32(HashPrefix::ledgerMaster);
|
||||||
&haveLedger->stateMap(),
|
addRaw(want->info(), hdr);
|
||||||
true,
|
|
||||||
16384,
|
|
||||||
std::bind(
|
|
||||||
fpAppender,
|
|
||||||
&reply,
|
|
||||||
lSeq,
|
|
||||||
std::placeholders::_1,
|
|
||||||
std::placeholders::_2));
|
|
||||||
|
|
||||||
if (wantLedger->info().txHash.isNonZero())
|
// Add the data
|
||||||
wantLedger->txMap().getFetchPack(
|
protocol::TMIndexedObject* obj = reply.add_objects();
|
||||||
nullptr,
|
obj->set_hash(
|
||||||
true,
|
want->info().hash.data(), want->info().hash.size());
|
||||||
512,
|
obj->set_data(hdr.getDataPtr(), hdr.getLength());
|
||||||
std::bind(
|
obj->set_ledgerseq(lSeq);
|
||||||
fpAppender,
|
}
|
||||||
&reply,
|
|
||||||
lSeq,
|
populateFetchPack(
|
||||||
std::placeholders::_1,
|
want->stateMap(), &have->stateMap(), 16384, &reply, lSeq);
|
||||||
std::placeholders::_2));
|
|
||||||
|
// We use nullptr here because transaction maps are per ledger
|
||||||
|
// and so the requestor is unlikely to already have it.
|
||||||
|
if (want->info().txHash.isNonZero())
|
||||||
|
populateFetchPack(want->txMap(), nullptr, 512, &reply, lSeq);
|
||||||
|
|
||||||
if (reply.objects().size() >= 512)
|
if (reply.objects().size() >= 512)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// move may save a ref/unref
|
have = std::move(want);
|
||||||
haveLedger = std::move(wantLedger);
|
want = getLedgerByHash(have->info().parentHash);
|
||||||
wantLedger = getLedgerByHash(haveLedger->info().parentHash);
|
} while (want && UptimeClock::now() <= uptime + 1s);
|
||||||
} while (wantLedger && UptimeClock::now() <= uptime + 1s);
|
|
||||||
|
auto msg = std::make_shared<Message>(reply, protocol::mtGET_OBJECTS);
|
||||||
|
|
||||||
JLOG(m_journal.info())
|
JLOG(m_journal.info())
|
||||||
<< "Built fetch pack with " << reply.objects().size() << " nodes";
|
<< "Built fetch pack with " << reply.objects().size() << " nodes ("
|
||||||
auto msg = std::make_shared<Message>(reply, protocol::mtGET_OBJECTS);
|
<< msg->getBufferSize() << " bytes)";
|
||||||
|
|
||||||
peer->send(msg);
|
peer->send(msg);
|
||||||
}
|
}
|
||||||
catch (std::exception const&)
|
catch (std::exception const&)
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ TransactionMaster::fetch(
|
|||||||
std::shared_ptr<STTx const>
|
std::shared_ptr<STTx const>
|
||||||
TransactionMaster::fetch(
|
TransactionMaster::fetch(
|
||||||
std::shared_ptr<SHAMapItem> const& item,
|
std::shared_ptr<SHAMapItem> const& item,
|
||||||
SHAMapTreeNode::TNType type,
|
SHAMapNodeType type,
|
||||||
std::uint32_t uCommitLedger)
|
std::uint32_t uCommitLedger)
|
||||||
{
|
{
|
||||||
std::shared_ptr<STTx const> txn;
|
std::shared_ptr<STTx const> txn;
|
||||||
@@ -116,12 +116,12 @@ TransactionMaster::fetch(
|
|||||||
|
|
||||||
if (!iTx)
|
if (!iTx)
|
||||||
{
|
{
|
||||||
if (type == SHAMapTreeNode::tnTRANSACTION_NM)
|
if (type == SHAMapNodeType::tnTRANSACTION_NM)
|
||||||
{
|
{
|
||||||
SerialIter sit(item->slice());
|
SerialIter sit(item->slice());
|
||||||
txn = std::make_shared<STTx const>(std::ref(sit));
|
txn = std::make_shared<STTx const>(std::ref(sit));
|
||||||
}
|
}
|
||||||
else if (type == SHAMapTreeNode::tnTRANSACTION_MD)
|
else if (type == SHAMapNodeType::tnTRANSACTION_MD)
|
||||||
{
|
{
|
||||||
auto blob = SerialIter{item->data(), item->size()}.getVL();
|
auto blob = SerialIter{item->data(), item->size()}.getVL();
|
||||||
txn = std::make_shared<STTx const>(
|
txn = std::make_shared<STTx const>(
|
||||||
|
|||||||
@@ -1906,8 +1906,7 @@ ApplicationImp::loadLedgerFromFile(std::string const& name)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadLedger->stateMap().flushDirty(
|
loadLedger->stateMap().flushDirty(hotACCOUNT_NODE);
|
||||||
hotACCOUNT_NODE, loadLedger->info().seq);
|
|
||||||
|
|
||||||
loadLedger->setAccepted(
|
loadLedger->setAccepted(
|
||||||
closeTime, closeTimeResolution, !closeTimeEstimated, *config_);
|
closeTime, closeTimeResolution, !closeTimeEstimated, *config_);
|
||||||
|
|||||||
@@ -155,10 +155,9 @@ public:
|
|||||||
amendTx.add(s);
|
amendTx.add(s);
|
||||||
|
|
||||||
initialPosition->addGiveItem(
|
initialPosition->addGiveItem(
|
||||||
|
SHAMapNodeType::tnTRANSACTION_NM,
|
||||||
std::make_shared<SHAMapItem>(
|
std::make_shared<SHAMapItem>(
|
||||||
amendTx.getTransactionID(), s.peekData()),
|
amendTx.getTransactionID(), s.peekData()));
|
||||||
true,
|
|
||||||
false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -244,9 +244,9 @@ FeeVoteImpl::doVoting(
|
|||||||
Serializer s;
|
Serializer s;
|
||||||
feeTx.add(s);
|
feeTx.add(s);
|
||||||
|
|
||||||
auto tItem = std::make_shared<SHAMapItem>(txID, s.peekData());
|
if (!initialPosition->addGiveItem(
|
||||||
|
SHAMapNodeType::tnTRANSACTION_NM,
|
||||||
if (!initialPosition->addGiveItem(std::move(tItem), true, false))
|
std::make_shared<SHAMapItem>(txID, s.peekData())))
|
||||||
{
|
{
|
||||||
JLOG(journal_.warn()) << "Ledger already had fee change";
|
JLOG(journal_.warn()) << "Ledger already had fee change";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,7 +119,8 @@ NegativeUNLVote::addTx(
|
|||||||
Serializer s;
|
Serializer s;
|
||||||
negUnlTx.add(s);
|
negUnlTx.add(s);
|
||||||
if (!initialSet->addGiveItem(
|
if (!initialSet->addGiveItem(
|
||||||
std::make_shared<SHAMapItem>(txID, s.peekData()), true, false))
|
SHAMapNodeType::tnTRANSACTION_NM,
|
||||||
|
std::make_shared<SHAMapItem>(txID, s.peekData())))
|
||||||
{
|
{
|
||||||
JLOG(j_.warn()) << "N-UNL: ledger seq=" << seq
|
JLOG(j_.warn()) << "N-UNL: ledger seq=" << seq
|
||||||
<< ", add ttUNL_MODIFY tx failed";
|
<< ", add ttUNL_MODIFY tx failed";
|
||||||
|
|||||||
@@ -299,12 +299,10 @@ SHAMapStoreImp::fdRequired() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SHAMapStoreImp::copyNode(
|
SHAMapStoreImp::copyNode(std::uint64_t& nodeCount, SHAMapTreeNode const& node)
|
||||||
std::uint64_t& nodeCount,
|
|
||||||
SHAMapAbstractNode const& node)
|
|
||||||
{
|
{
|
||||||
// Copy a single record from node to dbRotating_
|
// Copy a single record from node to dbRotating_
|
||||||
dbRotating_->fetchNodeObject(node.getNodeHash().as_uint256());
|
dbRotating_->fetchNodeObject(node.getHash().as_uint256());
|
||||||
if (!(++nodeCount % checkHealthInterval_))
|
if (!(++nodeCount % checkHealthInterval_))
|
||||||
{
|
{
|
||||||
if (health())
|
if (health())
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
// callback for visitNodes
|
// callback for visitNodes
|
||||||
bool
|
bool
|
||||||
copyNode(std::uint64_t& nodeCount, SHAMapAbstractNode const& node);
|
copyNode(std::uint64_t& nodeCount, SHAMapTreeNode const& node);
|
||||||
void
|
void
|
||||||
run();
|
run();
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -244,11 +244,11 @@ Database::storeLedger(
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool error = false;
|
bool error = false;
|
||||||
auto visit = [&](SHAMapAbstractNode& node) {
|
auto visit = [&](SHAMapTreeNode& node) {
|
||||||
if (!isStopping())
|
if (!isStopping())
|
||||||
{
|
{
|
||||||
if (auto nodeObject = srcDB.fetchNodeObject(
|
if (auto nodeObject = srcDB.fetchNodeObject(
|
||||||
node.getNodeHash().as_uint256(), srcLedger.info().seq))
|
node.getHash().as_uint256(), srcLedger.info().seq))
|
||||||
{
|
{
|
||||||
batch.emplace_back(std::move(nodeObject));
|
batch.emplace_back(std::move(nodeObject));
|
||||||
if (batch.size() < batchWritePreallocationSize || storeBatch())
|
if (batch.size() < batchWritePreallocationSize || storeBatch())
|
||||||
|
|||||||
@@ -405,11 +405,11 @@ Shard::storeLedger(
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool error = false;
|
bool error = false;
|
||||||
auto visit = [&](SHAMapAbstractNode& node) {
|
auto visit = [&](SHAMapTreeNode const& node) {
|
||||||
if (!stop_)
|
if (!stop_)
|
||||||
{
|
{
|
||||||
if (auto nodeObject = srcDB.fetchNodeObject(
|
if (auto nodeObject = srcDB.fetchNodeObject(
|
||||||
node.getNodeHash().as_uint256(), srcLedger->info().seq))
|
node.getHash().as_uint256(), srcLedger->info().seq))
|
||||||
{
|
{
|
||||||
batch.emplace_back(std::move(nodeObject));
|
batch.emplace_back(std::move(nodeObject));
|
||||||
if (batch.size() < batchWritePreallocationSize || storeBatch())
|
if (batch.size() < batchWritePreallocationSize || storeBatch())
|
||||||
@@ -1288,10 +1288,10 @@ Shard::verifyLedger(
|
|||||||
return fail("Invalid ledger account hash");
|
return fail("Invalid ledger account hash");
|
||||||
|
|
||||||
bool error{false};
|
bool error{false};
|
||||||
auto visit = [this, &error](SHAMapAbstractNode& node) {
|
auto visit = [this, &error](SHAMapTreeNode const& node) {
|
||||||
if (stop_)
|
if (stop_)
|
||||||
return false;
|
return false;
|
||||||
if (!verifyFetch(node.getNodeHash().as_uint256()))
|
if (!verifyFetch(node.getHash().as_uint256()))
|
||||||
error = true;
|
error = true;
|
||||||
return !error;
|
return !error;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -64,6 +64,10 @@ public:
|
|||||||
int type,
|
int type,
|
||||||
boost::optional<PublicKey> const& validator = {});
|
boost::optional<PublicKey> const& validator = {});
|
||||||
|
|
||||||
|
/** Retrieve the size of the packed but uncompressed message data. */
|
||||||
|
std::size_t
|
||||||
|
getBufferSize();
|
||||||
|
|
||||||
/** Retrieve the packed message data. If compressed message is requested but
|
/** Retrieve the packed message data. If compressed message is requested but
|
||||||
* the message is not compressible then the uncompressed buffer is returned.
|
* the message is not compressible then the uncompressed buffer is returned.
|
||||||
* @param compressed Request compressed (Compress::On) or
|
* @param compressed Request compressed (Compress::On) or
|
||||||
|
|||||||
@@ -177,6 +177,12 @@ Message::setHeader(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::size_t
|
||||||
|
Message::getBufferSize()
|
||||||
|
{
|
||||||
|
return buffer_.size();
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> const&
|
std::vector<uint8_t> const&
|
||||||
Message::getBuffer(Compressed tryCompressed)
|
Message::getBuffer(Compressed tryCompressed)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -49,24 +49,6 @@ isValidated(LedgerMaster& ledgerMaster, std::uint32_t seq, uint256 const& hash)
|
|||||||
return ledgerMaster.getHashBySeq(seq) == hash;
|
return ledgerMaster.getHashBySeq(seq) == hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
getMetaHex(Ledger const& ledger, uint256 const& transID, std::string& hex)
|
|
||||||
{
|
|
||||||
SHAMapTreeNode::TNType type;
|
|
||||||
auto const item = ledger.txMap().peekItem(transID, type);
|
|
||||||
|
|
||||||
if (!item)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (type != SHAMapTreeNode::tnTRANSACTION_MD)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
SerialIter it(item->slice());
|
|
||||||
it.getVL(); // skip transaction
|
|
||||||
hex = strHex(makeSlice(it.getVL()));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TxResult
|
struct TxResult
|
||||||
{
|
{
|
||||||
Transaction::pointer txn;
|
Transaction::pointer txn;
|
||||||
|
|||||||
@@ -17,14 +17,14 @@ or account state can be used to navigate the trie.
|
|||||||
A `SHAMap` is a trie with two node types:
|
A `SHAMap` is a trie with two node types:
|
||||||
|
|
||||||
1. SHAMapInnerNode
|
1. SHAMapInnerNode
|
||||||
2. SHAMapTreeNode
|
2. SHAMapLeafNode
|
||||||
|
|
||||||
Both of these nodes directly inherit from SHAMapAbstractNode which holds data
|
Both of these nodes directly inherit from SHAMapTreeNode which holds data
|
||||||
common to both of the node types.
|
common to both of the node types.
|
||||||
|
|
||||||
All non-leaf nodes have type SHAMapInnerNode.
|
All non-leaf nodes have type SHAMapInnerNode.
|
||||||
|
|
||||||
All leaf nodes have type SHAMapTreeNode.
|
All leaf nodes have type SHAMapLeafNode.
|
||||||
|
|
||||||
The root node is always a SHAMapInnerNode.
|
The root node is always a SHAMapInnerNode.
|
||||||
|
|
||||||
@@ -193,7 +193,7 @@ continues, unless the path indicates a child that does not exist. And in this
|
|||||||
case, `nullptr` is returned to indicate no leaf node along the given path
|
case, `nullptr` is returned to indicate no leaf node along the given path
|
||||||
exists. Otherwise a leaf node is found and a (non-owning) pointer to it is
|
exists. Otherwise a leaf node is found and a (non-owning) pointer to it is
|
||||||
returned. At each step, if a stack is requested, a
|
returned. At each step, if a stack is requested, a
|
||||||
`pair<shared_ptr<SHAMapAbstractNode>, SHAMapNodeID>` is pushed onto the stack.
|
`pair<shared_ptr<SHAMapTreeNode>, SHAMapNodeID>` is pushed onto the stack.
|
||||||
|
|
||||||
When a child node is found by `selectBranch`, the traversal to that node
|
When a child node is found by `selectBranch`, the traversal to that node
|
||||||
consists of two steps:
|
consists of two steps:
|
||||||
@@ -220,11 +220,11 @@ is this case stands for 'No Throw'.
|
|||||||
|
|
||||||
The `fetchNodeNT()` method goes through three phases:
|
The `fetchNodeNT()` method goes through three phases:
|
||||||
|
|
||||||
1. By calling `getCache()` we attempt to locate the missing node in the
|
1. By calling `cacheLookup()` we attempt to locate the missing node in the
|
||||||
TreeNodeCache. The TreeNodeCache is a cache of immutable SHAMapTreeNodes
|
TreeNodeCache. The TreeNodeCache is a cache of immutable SHAMapTreeNodes
|
||||||
that are shared across all `SHAMap`s.
|
that are shared across all `SHAMap`s.
|
||||||
|
|
||||||
Any SHAMapTreeNode that is immutable has a sequence number of zero
|
Any SHAMapLeafNode that is immutable has a sequence number of zero
|
||||||
(sharable). When a mutable `SHAMap` is created then its SHAMapTreeNodes are
|
(sharable). When a mutable `SHAMap` is created then its SHAMapTreeNodes are
|
||||||
given non-zero sequence numbers (unsharable). But all nodes in the
|
given non-zero sequence numbers (unsharable). But all nodes in the
|
||||||
TreeNodeCache are immutable, so if one is found here, its sequence number
|
TreeNodeCache are immutable, so if one is found here, its sequence number
|
||||||
@@ -250,17 +250,17 @@ the `SHAMap`, node `TreeNodeCache` or database, then we don't create duplicates
|
|||||||
by favoring the copy already in the `TreeNodeCache`.
|
by favoring the copy already in the `TreeNodeCache`.
|
||||||
|
|
||||||
By using `canonicalize()` we manage a thread race condition where two different
|
By using `canonicalize()` we manage a thread race condition where two different
|
||||||
threads might both recognize the lack of a SHAMapTreeNode at the same time
|
threads might both recognize the lack of a SHAMapLeafNode at the same time
|
||||||
(during a fetch). If they both attempt to insert the node into the `SHAMap`, then
|
(during a fetch). If they both attempt to insert the node into the `SHAMap`, then
|
||||||
`canonicalize` makes sure that the first node in wins and the slower thread
|
`canonicalize` makes sure that the first node in wins and the slower thread
|
||||||
receives back a pointer to the node inserted by the faster thread. Recall
|
receives back a pointer to the node inserted by the faster thread. Recall
|
||||||
that these two `SHAMap`s will share the same `TreeNodeCache`.
|
that these two `SHAMap`s will share the same `TreeNodeCache`.
|
||||||
|
|
||||||
## TreeNodeCache ##
|
## `TreeNodeCache` ##
|
||||||
|
|
||||||
The `TreeNodeCache` is a `std::unordered_map` keyed on the hash of the
|
The `TreeNodeCache` is a `std::unordered_map` keyed on the hash of the
|
||||||
`SHAMap` node. The stored type consists of `shared_ptr<SHAMapAbstractNode>`,
|
`SHAMap` node. The stored type consists of `shared_ptr<SHAMapTreeNode>`,
|
||||||
`weak_ptr<SHAMapAbstractNode>`, and a time point indicating the most recent
|
`weak_ptr<SHAMapTreeNode>`, and a time point indicating the most recent
|
||||||
access of this node in the cache. The time point is based on
|
access of this node in the cache. The time point is based on
|
||||||
`std::chrono::steady_clock`.
|
`std::chrono::steady_clock`.
|
||||||
|
|
||||||
@@ -271,7 +271,7 @@ and logging, and a target age for the contained nodes. When the target age
|
|||||||
for a node is exceeded, and there are no more references to the node, the
|
for a node is exceeded, and there are no more references to the node, the
|
||||||
node is removed from the `TreeNodeCache`.
|
node is removed from the `TreeNodeCache`.
|
||||||
|
|
||||||
## FullBelowCache ##
|
## `FullBelowCache` ##
|
||||||
|
|
||||||
This cache remembers which trie keys have all of their children resident in a
|
This cache remembers which trie keys have all of their children resident in a
|
||||||
`SHAMap`. This optimizes the process of acquiring a complete trie. This is used
|
`SHAMap`. This optimizes the process of acquiring a complete trie. This is used
|
||||||
@@ -284,38 +284,51 @@ nodes, and thus that subtree does not need to be walked. These nodes are stored
|
|||||||
in the FullBelowCache. Subsequent walks check the FullBelowCache first when
|
in the FullBelowCache. Subsequent walks check the FullBelowCache first when
|
||||||
encountering a node, and ignore that subtree if found.
|
encountering a node, and ignore that subtree if found.
|
||||||
|
|
||||||
## SHAMapAbstractNode ##
|
## `SHAMapTreeNode` ##
|
||||||
|
|
||||||
This is a base class for the two concrete node types. It holds the following
|
This is an abstract base class for the concrete node types. It holds the
|
||||||
common data:
|
following common data:
|
||||||
|
|
||||||
1. A node type, one of:
|
1. A hash
|
||||||
a. error
|
2. An identifier used to perform copy-on-write operations
|
||||||
b. inner
|
|
||||||
c. transaction with no metadata
|
|
||||||
d. transaction with metadata
|
|
||||||
e. account state
|
|
||||||
2. A hash
|
|
||||||
3. A sequence number
|
|
||||||
|
|
||||||
|
|
||||||
## SHAMapInnerNode ##
|
### `SHAMapInnerNode` ###
|
||||||
|
|
||||||
SHAMapInnerNode publicly inherits directly from SHAMapAbstractNode. It holds
|
`SHAMapInnerNode` publicly inherits directly from `SHAMapTreeNode`. It holds
|
||||||
the following data:
|
the following data:
|
||||||
|
|
||||||
1. Up to 16 child nodes, each held with a shared_ptr.
|
1. Up to 16 child nodes, each held with a shared_ptr.
|
||||||
2. A hash for each child.
|
2. A hash for each child.
|
||||||
3. A 16-bit bitset with a 1 bit set for each child that exists.
|
3. A bitset to indicate which of the 16 children exist.
|
||||||
4. Flag to aid online delete and consistency with data on disk.
|
4. An identifier used to determine whether the map below this node is
|
||||||
|
fully populated
|
||||||
|
|
||||||
## SHAMapTreeNode ##
|
### `SHAMapLeafNode` ###
|
||||||
|
|
||||||
SHAMapTreeNode publicly inherits directly from SHAMapAbstractNode. It holds the
|
`SHAMapLeafNode` is an abstract class which publicly inherits directly from
|
||||||
|
`SHAMapTreeNode`. It isIt holds the
|
||||||
following data:
|
following data:
|
||||||
|
|
||||||
1. A shared_ptr to a const SHAMapItem.
|
1. A shared_ptr to a const SHAMapItem.
|
||||||
|
|
||||||
|
#### `SHAMapAccountStateLeafNode` ####
|
||||||
|
|
||||||
|
`SHAMapAccountStateLeafNode` is a class which publicly inherits directly from
|
||||||
|
`SHAMapLeafNode`. It is used to represent entries (i.e. account objects, escrow
|
||||||
|
objects, trust lines, etc.) in a state map.
|
||||||
|
|
||||||
|
#### `SHAMapTxLeafNode` ####
|
||||||
|
|
||||||
|
`SHAMapTxLeafNode` is a class which publicly inherits directly from
|
||||||
|
`SHAMapLeafNode`. It is used to represent transactions in a state map.
|
||||||
|
|
||||||
|
#### `SHAMapTxPlusMetaLeafNode` ####
|
||||||
|
|
||||||
|
`SHAMapTxPlusMetaLeafNode` is a class which publicly inherits directly from
|
||||||
|
`SHAMapLeafNode`. It is used to represent transactions along with metadata
|
||||||
|
associated with this transaction in a state map.
|
||||||
|
|
||||||
## SHAMapItem ##
|
## SHAMapItem ##
|
||||||
|
|
||||||
This holds the following data:
|
This holds the following data:
|
||||||
@@ -323,27 +336,4 @@ This holds the following data:
|
|||||||
1. uint256. The hash of the data.
|
1. uint256. The hash of the data.
|
||||||
2. vector<unsigned char>. The data (transactions, account info).
|
2. vector<unsigned char>. The data (transactions, account info).
|
||||||
|
|
||||||
## SHAMap Improvements ##
|
|
||||||
|
|
||||||
Here's a simple one: the SHAMapTreeNode::mAccessSeq member is currently not used
|
|
||||||
and could be removed.
|
|
||||||
|
|
||||||
Here's a more important change. The trie structure is currently embedded in the
|
|
||||||
SHAMapTreeNodes themselves. It doesn't have to be that way, and that should be
|
|
||||||
fixed.
|
|
||||||
|
|
||||||
When we navigate the trie (say, like `SHAMap::walkTo()`) we currently ask each
|
|
||||||
node for information that we could determine locally. We know the depth because
|
|
||||||
we know how many nodes we have traversed. We know the ID that we need because
|
|
||||||
that's how we're steering. So we don't need to store the ID in the node. The
|
|
||||||
next refactor should remove all calls to `SHAMapTreeNode::GetID()`.
|
|
||||||
|
|
||||||
Then we can remove the NodeID member from SHAMapTreeNode.
|
|
||||||
|
|
||||||
Then we can change the `SHAMap::mTNBtID` member to be `mTNByHash`.
|
|
||||||
|
|
||||||
An additional possible refactor would be to have a base type, SHAMapTreeNode,
|
|
||||||
and derive from that InnerNode and LeafNode types. That would remove some
|
|
||||||
storage (the array of 16 hashes) from the LeafNodes. That refactor would also
|
|
||||||
have the effect of simplifying methods like `isLeaf()` and `hasItem()`.
|
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,9 @@
|
|||||||
#include <ripple/shamap/Family.h>
|
#include <ripple/shamap/Family.h>
|
||||||
#include <ripple/shamap/FullBelowCache.h>
|
#include <ripple/shamap/FullBelowCache.h>
|
||||||
#include <ripple/shamap/SHAMapAddNode.h>
|
#include <ripple/shamap/SHAMapAddNode.h>
|
||||||
|
#include <ripple/shamap/SHAMapInnerNode.h>
|
||||||
#include <ripple/shamap/SHAMapItem.h>
|
#include <ripple/shamap/SHAMapItem.h>
|
||||||
|
#include <ripple/shamap/SHAMapLeafNode.h>
|
||||||
#include <ripple/shamap/SHAMapMissingNode.h>
|
#include <ripple/shamap/SHAMapMissingNode.h>
|
||||||
#include <ripple/shamap/SHAMapTreeNode.h>
|
#include <ripple/shamap/SHAMapTreeNode.h>
|
||||||
#include <ripple/shamap/TreeNodeCache.h>
|
#include <ripple/shamap/TreeNodeCache.h>
|
||||||
@@ -95,13 +97,18 @@ class SHAMap
|
|||||||
private:
|
private:
|
||||||
Family& f_;
|
Family& f_;
|
||||||
beast::Journal journal_;
|
beast::Journal journal_;
|
||||||
std::uint32_t seq_;
|
|
||||||
std::uint32_t ledgerSeq_ = 0; // sequence number of ledger this is part of
|
/** ID to distinguish this map for all others we're sharing nodes with. */
|
||||||
std::shared_ptr<SHAMapAbstractNode> root_;
|
std::uint32_t cowid_ = 1;
|
||||||
|
|
||||||
|
/** The sequence of the ledger that this map references, if any. */
|
||||||
|
std::uint32_t ledgerSeq_ = 0;
|
||||||
|
|
||||||
|
std::shared_ptr<SHAMapTreeNode> root_;
|
||||||
mutable SHAMapState state_;
|
mutable SHAMapState state_;
|
||||||
SHAMapType type_;
|
SHAMapType const type_;
|
||||||
bool backed_ = true; // Map is backed by the database
|
bool backed_ = true; // Map is backed by the database
|
||||||
bool full_ = false; // Map is believed complete in database
|
mutable bool full_ = false; // Map is believed complete in database
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Each non-leaf node has 16 children (the 'radix tree' part of the map) */
|
/** Each non-leaf node has 16 children (the 'radix tree' part of the map) */
|
||||||
@@ -115,7 +122,6 @@ public:
|
|||||||
std::shared_ptr<SHAMapItem const>>;
|
std::shared_ptr<SHAMapItem const>>;
|
||||||
using Delta = std::map<uint256, DeltaItem>;
|
using Delta = std::map<uint256, DeltaItem>;
|
||||||
|
|
||||||
~SHAMap();
|
|
||||||
SHAMap(SHAMap const&) = delete;
|
SHAMap(SHAMap const&) = delete;
|
||||||
SHAMap&
|
SHAMap&
|
||||||
operator=(SHAMap const&) = delete;
|
operator=(SHAMap const&) = delete;
|
||||||
@@ -125,6 +131,8 @@ public:
|
|||||||
|
|
||||||
SHAMap(SHAMapType t, uint256 const& hash, Family& f);
|
SHAMap(SHAMapType t, uint256 const& hash, Family& f);
|
||||||
|
|
||||||
|
~SHAMap() = default;
|
||||||
|
|
||||||
Family const&
|
Family const&
|
||||||
family() const
|
family() const
|
||||||
{
|
{
|
||||||
@@ -171,26 +179,26 @@ public:
|
|||||||
fetchRoot(SHAMapHash const& hash, SHAMapSyncFilter* filter);
|
fetchRoot(SHAMapHash const& hash, SHAMapSyncFilter* filter);
|
||||||
|
|
||||||
// normal hash access functions
|
// normal hash access functions
|
||||||
|
|
||||||
|
/** Does the tree have an item with the given ID? */
|
||||||
bool
|
bool
|
||||||
hasItem(uint256 const& id) const;
|
hasItem(uint256 const& id) const;
|
||||||
|
|
||||||
bool
|
bool
|
||||||
delItem(uint256 const& id);
|
delItem(uint256 const& id);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
addItem(SHAMapItem&& i, bool isTransaction, bool hasMeta);
|
addItem(SHAMapNodeType type, SHAMapItem&& i);
|
||||||
|
|
||||||
SHAMapHash
|
SHAMapHash
|
||||||
getHash() const;
|
getHash() const;
|
||||||
|
|
||||||
// save a copy if you have a temporary anyway
|
// save a copy if you have a temporary anyway
|
||||||
bool
|
bool
|
||||||
updateGiveItem(
|
updateGiveItem(SHAMapNodeType type, std::shared_ptr<SHAMapItem const>);
|
||||||
std::shared_ptr<SHAMapItem const>,
|
|
||||||
bool isTransaction,
|
|
||||||
bool hasMeta);
|
|
||||||
bool
|
bool
|
||||||
addGiveItem(
|
addGiveItem(SHAMapNodeType type, std::shared_ptr<SHAMapItem const> item);
|
||||||
std::shared_ptr<SHAMapItem const>,
|
|
||||||
bool isTransaction,
|
|
||||||
bool hasMeta);
|
|
||||||
|
|
||||||
// Save a copy if you need to extend the life
|
// Save a copy if you need to extend the life
|
||||||
// of the SHAMapItem beyond this SHAMap
|
// of the SHAMapItem beyond this SHAMap
|
||||||
@@ -198,8 +206,6 @@ public:
|
|||||||
peekItem(uint256 const& id) const;
|
peekItem(uint256 const& id) const;
|
||||||
std::shared_ptr<SHAMapItem const> const&
|
std::shared_ptr<SHAMapItem const> const&
|
||||||
peekItem(uint256 const& id, SHAMapHash& hash) const;
|
peekItem(uint256 const& id, SHAMapHash& hash) const;
|
||||||
std::shared_ptr<SHAMapItem const> const&
|
|
||||||
peekItem(uint256 const& id, SHAMapTreeNode::TNType& type) const;
|
|
||||||
|
|
||||||
// traverse functions
|
// traverse functions
|
||||||
const_iterator
|
const_iterator
|
||||||
@@ -211,7 +217,7 @@ public:
|
|||||||
If function returns false, visitNodes exits.
|
If function returns false, visitNodes exits.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
visitNodes(std::function<bool(SHAMapAbstractNode&)> const& function) const;
|
visitNodes(std::function<bool(SHAMapTreeNode&)> const& function) const;
|
||||||
|
|
||||||
/** Visit every node in this SHAMap that
|
/** Visit every node in this SHAMap that
|
||||||
is not present in the specified SHAMap
|
is not present in the specified SHAMap
|
||||||
@@ -222,7 +228,7 @@ public:
|
|||||||
void
|
void
|
||||||
visitDifferences(
|
visitDifferences(
|
||||||
SHAMap const* have,
|
SHAMap const* have,
|
||||||
std::function<bool(SHAMapAbstractNode&)>) const;
|
std::function<bool(SHAMapTreeNode const&)>) const;
|
||||||
|
|
||||||
/** Visit every leaf node in this SHAMap
|
/** Visit every leaf node in this SHAMap
|
||||||
|
|
||||||
@@ -250,9 +256,9 @@ public:
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
getNodeFat(
|
getNodeFat(
|
||||||
SHAMapNodeID node,
|
SHAMapNodeID const& wanted,
|
||||||
std::vector<SHAMapNodeID>& nodeIDs,
|
std::vector<SHAMapNodeID>& nodeIDs,
|
||||||
std::vector<Blob>& rawNode,
|
std::vector<Blob>& rawNodes,
|
||||||
bool fatLeaves,
|
bool fatLeaves,
|
||||||
std::uint32_t depth) const;
|
std::uint32_t depth) const;
|
||||||
|
|
||||||
@@ -260,8 +266,6 @@ public:
|
|||||||
void
|
void
|
||||||
serializeRoot(Serializer& s) const;
|
serializeRoot(Serializer& s) const;
|
||||||
|
|
||||||
std::vector<uint256>
|
|
||||||
getNeededHashes(int max, SHAMapSyncFilter* filter);
|
|
||||||
SHAMapAddNode
|
SHAMapAddNode
|
||||||
addRootNode(
|
addRootNode(
|
||||||
SHAMapHash const& hash,
|
SHAMapHash const& hash,
|
||||||
@@ -290,26 +294,21 @@ public:
|
|||||||
bool
|
bool
|
||||||
compare(SHAMap const& otherMap, Delta& differences, int maxCount) const;
|
compare(SHAMap const& otherMap, Delta& differences, int maxCount) const;
|
||||||
|
|
||||||
|
/** Convert any modified nodes to shared. */
|
||||||
int
|
int
|
||||||
flushDirty(NodeObjectType t, std::uint32_t seq);
|
unshare();
|
||||||
|
|
||||||
|
/** Flush modified nodes to the nodestore and convert them to shared. */
|
||||||
|
int
|
||||||
|
flushDirty(NodeObjectType t);
|
||||||
|
|
||||||
void
|
void
|
||||||
walkMap(std::vector<SHAMapMissingNode>& missingNodes, int maxMissing) const;
|
walkMap(std::vector<SHAMapMissingNode>& missingNodes, int maxMissing) const;
|
||||||
bool
|
bool
|
||||||
deepCompare(SHAMap& other) const; // Intended for debug/test only
|
deepCompare(SHAMap& other) const; // Intended for debug/test only
|
||||||
|
|
||||||
using fetchPackEntry_t = std::pair<uint256, Blob>;
|
|
||||||
|
|
||||||
void
|
|
||||||
getFetchPack(
|
|
||||||
SHAMap const* have,
|
|
||||||
bool includeLeaves,
|
|
||||||
int max,
|
|
||||||
std::function<void(SHAMapHash const&, const Blob&)>) const;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
setUnbacked();
|
setUnbacked();
|
||||||
int
|
|
||||||
unshare();
|
|
||||||
|
|
||||||
void
|
void
|
||||||
dump(bool withHashes = false) const;
|
dump(bool withHashes = false) const;
|
||||||
@@ -317,29 +316,29 @@ public:
|
|||||||
invariants() const;
|
invariants() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using SharedPtrNodeStack = std::stack<
|
using SharedPtrNodeStack =
|
||||||
std::pair<std::shared_ptr<SHAMapAbstractNode>, SHAMapNodeID>>;
|
std::stack<std::pair<std::shared_ptr<SHAMapTreeNode>, SHAMapNodeID>>;
|
||||||
using DeltaRef = std::pair<
|
using DeltaRef = std::pair<
|
||||||
std::shared_ptr<SHAMapItem const> const&,
|
std::shared_ptr<SHAMapItem const> const&,
|
||||||
std::shared_ptr<SHAMapItem const> const&>;
|
std::shared_ptr<SHAMapItem const> const&>;
|
||||||
|
|
||||||
// tree node cache operations
|
// tree node cache operations
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
getCache(SHAMapHash const& hash) const;
|
cacheLookup(SHAMapHash const& hash) const;
|
||||||
void
|
void
|
||||||
canonicalize(SHAMapHash const& hash, std::shared_ptr<SHAMapAbstractNode>&)
|
canonicalize(SHAMapHash const& hash, std::shared_ptr<SHAMapTreeNode>&)
|
||||||
const;
|
const;
|
||||||
|
|
||||||
// database operations
|
// database operations
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
fetchNodeFromDB(SHAMapHash const& hash) const;
|
fetchNodeFromDB(SHAMapHash const& hash) const;
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
fetchNodeNT(SHAMapHash const& hash) const;
|
fetchNodeNT(SHAMapHash const& hash) const;
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
fetchNodeNT(SHAMapHash const& hash, SHAMapSyncFilter* filter) const;
|
fetchNodeNT(SHAMapHash const& hash, SHAMapSyncFilter* filter) const;
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
fetchNode(SHAMapHash const& hash) const;
|
fetchNode(SHAMapHash const& hash) const;
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
checkFilter(SHAMapHash const& hash, SHAMapSyncFilter* filter) const;
|
checkFilter(SHAMapHash const& hash, SHAMapSyncFilter* filter) const;
|
||||||
|
|
||||||
/** Update hashes up to the root */
|
/** Update hashes up to the root */
|
||||||
@@ -347,16 +346,16 @@ private:
|
|||||||
dirtyUp(
|
dirtyUp(
|
||||||
SharedPtrNodeStack& stack,
|
SharedPtrNodeStack& stack,
|
||||||
uint256 const& target,
|
uint256 const& target,
|
||||||
std::shared_ptr<SHAMapAbstractNode> terminal);
|
std::shared_ptr<SHAMapTreeNode> terminal);
|
||||||
|
|
||||||
/** Walk towards the specified id, returning the node. Caller must check
|
/** Walk towards the specified id, returning the node. Caller must check
|
||||||
if the return is nullptr, and if not, if the node->peekItem()->key() ==
|
if the return is nullptr, and if not, if the node->peekItem()->key() ==
|
||||||
id */
|
id */
|
||||||
SHAMapTreeNode*
|
SHAMapLeafNode*
|
||||||
walkTowardsKey(uint256 const& id, SharedPtrNodeStack* stack = nullptr)
|
walkTowardsKey(uint256 const& id, SharedPtrNodeStack* stack = nullptr)
|
||||||
const;
|
const;
|
||||||
/** Return nullptr if key not found */
|
/** Return nullptr if key not found */
|
||||||
SHAMapTreeNode*
|
SHAMapLeafNode*
|
||||||
findKey(uint256 const& id) const;
|
findKey(uint256 const& id) const;
|
||||||
|
|
||||||
/** Unshare the node, allowing it to be modified */
|
/** Unshare the node, allowing it to be modified */
|
||||||
@@ -370,38 +369,35 @@ private:
|
|||||||
preFlushNode(std::shared_ptr<Node> node) const;
|
preFlushNode(std::shared_ptr<Node> node) const;
|
||||||
|
|
||||||
/** write and canonicalize modified node */
|
/** write and canonicalize modified node */
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
writeNode(
|
writeNode(NodeObjectType t, std::shared_ptr<SHAMapTreeNode> node) const;
|
||||||
NodeObjectType t,
|
|
||||||
std::uint32_t seq,
|
|
||||||
std::shared_ptr<SHAMapAbstractNode> node) const;
|
|
||||||
|
|
||||||
SHAMapTreeNode*
|
SHAMapLeafNode*
|
||||||
firstBelow(
|
firstBelow(
|
||||||
std::shared_ptr<SHAMapAbstractNode>,
|
std::shared_ptr<SHAMapTreeNode>,
|
||||||
SharedPtrNodeStack& stack,
|
SharedPtrNodeStack& stack,
|
||||||
int branch = 0) const;
|
int branch = 0) const;
|
||||||
|
|
||||||
// Simple descent
|
// Simple descent
|
||||||
// Get a child of the specified node
|
// Get a child of the specified node
|
||||||
SHAMapAbstractNode*
|
SHAMapTreeNode*
|
||||||
descend(SHAMapInnerNode*, int branch) const;
|
descend(SHAMapInnerNode*, int branch) const;
|
||||||
SHAMapAbstractNode*
|
SHAMapTreeNode*
|
||||||
descendThrow(SHAMapInnerNode*, int branch) const;
|
descendThrow(SHAMapInnerNode*, int branch) const;
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
descend(std::shared_ptr<SHAMapInnerNode> const&, int branch) const;
|
descend(std::shared_ptr<SHAMapInnerNode> const&, int branch) const;
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
descendThrow(std::shared_ptr<SHAMapInnerNode> const&, int branch) const;
|
descendThrow(std::shared_ptr<SHAMapInnerNode> const&, int branch) const;
|
||||||
|
|
||||||
// Descend with filter
|
// Descend with filter
|
||||||
SHAMapAbstractNode*
|
SHAMapTreeNode*
|
||||||
descendAsync(
|
descendAsync(
|
||||||
SHAMapInnerNode* parent,
|
SHAMapInnerNode* parent,
|
||||||
int branch,
|
int branch,
|
||||||
SHAMapSyncFilter* filter,
|
SHAMapSyncFilter* filter,
|
||||||
bool& pending) const;
|
bool& pending) const;
|
||||||
|
|
||||||
std::pair<SHAMapAbstractNode*, SHAMapNodeID>
|
std::pair<SHAMapTreeNode*, SHAMapNodeID>
|
||||||
descend(
|
descend(
|
||||||
SHAMapInnerNode* parent,
|
SHAMapInnerNode* parent,
|
||||||
SHAMapNodeID const& parentID,
|
SHAMapNodeID const& parentID,
|
||||||
@@ -410,31 +406,31 @@ private:
|
|||||||
|
|
||||||
// Non-storing
|
// Non-storing
|
||||||
// Does not hook the returned node to its parent
|
// Does not hook the returned node to its parent
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
descendNoStore(std::shared_ptr<SHAMapInnerNode> const&, int branch) const;
|
descendNoStore(std::shared_ptr<SHAMapInnerNode> const&, int branch) const;
|
||||||
|
|
||||||
/** If there is only one leaf below this node, get its contents */
|
/** If there is only one leaf below this node, get its contents */
|
||||||
std::shared_ptr<SHAMapItem const> const&
|
std::shared_ptr<SHAMapItem const> const&
|
||||||
onlyBelow(SHAMapAbstractNode*) const;
|
onlyBelow(SHAMapTreeNode*) const;
|
||||||
|
|
||||||
bool
|
bool
|
||||||
hasInnerNode(SHAMapNodeID const& nodeID, SHAMapHash const& hash) const;
|
hasInnerNode(SHAMapNodeID const& nodeID, SHAMapHash const& hash) const;
|
||||||
bool
|
bool
|
||||||
hasLeafNode(uint256 const& tag, SHAMapHash const& hash) const;
|
hasLeafNode(uint256 const& tag, SHAMapHash const& hash) const;
|
||||||
|
|
||||||
SHAMapTreeNode const*
|
SHAMapLeafNode const*
|
||||||
peekFirstItem(SharedPtrNodeStack& stack) const;
|
peekFirstItem(SharedPtrNodeStack& stack) const;
|
||||||
SHAMapTreeNode const*
|
SHAMapLeafNode const*
|
||||||
peekNextItem(uint256 const& id, SharedPtrNodeStack& stack) const;
|
peekNextItem(uint256 const& id, SharedPtrNodeStack& stack) const;
|
||||||
bool
|
bool
|
||||||
walkBranch(
|
walkBranch(
|
||||||
SHAMapAbstractNode* node,
|
SHAMapTreeNode* node,
|
||||||
std::shared_ptr<SHAMapItem const> const& otherMapItem,
|
std::shared_ptr<SHAMapItem const> const& otherMapItem,
|
||||||
bool isFirstMap,
|
bool isFirstMap,
|
||||||
Delta& differences,
|
Delta& differences,
|
||||||
int& maxCount) const;
|
int& maxCount) const;
|
||||||
int
|
int
|
||||||
walkSubTree(bool doWrite, NodeObjectType t, std::uint32_t seq);
|
walkSubTree(bool doWrite, NodeObjectType t);
|
||||||
|
|
||||||
// Structure to track information about call to
|
// Structure to track information about call to
|
||||||
// getMissingNodes while it's in progress
|
// getMissingNodes while it's in progress
|
||||||
|
|||||||
93
src/ripple/shamap/SHAMapAccountStateLeafNode.h
Normal file
93
src/ripple/shamap/SHAMapAccountStateLeafNode.h
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef RIPPLE_SHAMAP_SHAMAPACCOUNTSTATELEAFNODE_H_INCLUDED
|
||||||
|
#define RIPPLE_SHAMAP_SHAMAPACCOUNTSTATELEAFNODE_H_INCLUDED
|
||||||
|
|
||||||
|
#include <ripple/basics/CountedObject.h>
|
||||||
|
#include <ripple/protocol/HashPrefix.h>
|
||||||
|
#include <ripple/protocol/digest.h>
|
||||||
|
#include <ripple/shamap/SHAMapItem.h>
|
||||||
|
#include <ripple/shamap/SHAMapLeafNode.h>
|
||||||
|
#include <ripple/shamap/SHAMapNodeID.h>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
/** A leaf node for a state object. */
|
||||||
|
class SHAMapAccountStateLeafNode final
|
||||||
|
: public SHAMapLeafNode,
|
||||||
|
public CountedObject<SHAMapAccountStateLeafNode>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SHAMapAccountStateLeafNode(
|
||||||
|
std::shared_ptr<SHAMapItem const> item,
|
||||||
|
std::uint32_t cowid)
|
||||||
|
: SHAMapLeafNode(std::move(item), cowid)
|
||||||
|
{
|
||||||
|
updateHash();
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAMapAccountStateLeafNode(
|
||||||
|
std::shared_ptr<SHAMapItem const> item,
|
||||||
|
std::uint32_t cowid,
|
||||||
|
SHAMapHash const& hash)
|
||||||
|
: SHAMapLeafNode(std::move(item), cowid, hash)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
|
clone(std::uint32_t cowid) const final override
|
||||||
|
{
|
||||||
|
return std::make_shared<SHAMapAccountStateLeafNode>(
|
||||||
|
item_, cowid, hash_);
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAMapNodeType
|
||||||
|
getType() const final override
|
||||||
|
{
|
||||||
|
return SHAMapNodeType::tnACCOUNT_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
updateHash() final override
|
||||||
|
{
|
||||||
|
hash_ = SHAMapHash{sha512Half(
|
||||||
|
HashPrefix::leafNode, makeSlice(item_->peekData()), item_->key())};
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
serializeForWire(Serializer& s) const final override
|
||||||
|
{
|
||||||
|
s.addRaw(item_->peekData());
|
||||||
|
s.addBitString(item_->key());
|
||||||
|
s.add8(wireTypeAccountState);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
serializeWithPrefix(Serializer& s) const final override
|
||||||
|
{
|
||||||
|
s.add32(HashPrefix::leafNode);
|
||||||
|
s.addRaw(item_->peekData());
|
||||||
|
s.addBitString(item_->key());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ripple
|
||||||
|
|
||||||
|
#endif
|
||||||
155
src/ripple/shamap/SHAMapInnerNode.h
Normal file
155
src/ripple/shamap/SHAMapInnerNode.h
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef RIPPLE_SHAMAP_SHAMAPINNERNODE_H_INCLUDED
|
||||||
|
#define RIPPLE_SHAMAP_SHAMAPINNERNODE_H_INCLUDED
|
||||||
|
|
||||||
|
#include <ripple/basics/TaggedCache.h>
|
||||||
|
#include <ripple/beast/utility/Journal.h>
|
||||||
|
#include <ripple/shamap/SHAMapItem.h>
|
||||||
|
#include <ripple/shamap/SHAMapNodeID.h>
|
||||||
|
#include <ripple/shamap/SHAMapTreeNode.h>
|
||||||
|
|
||||||
|
#include <bitset>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
class SHAMapInnerNode final : public SHAMapTreeNode,
|
||||||
|
public CountedObject<SHAMapInnerNode>
|
||||||
|
{
|
||||||
|
std::array<SHAMapHash, 16> mHashes;
|
||||||
|
std::shared_ptr<SHAMapTreeNode> mChildren[16];
|
||||||
|
int mIsBranch = 0;
|
||||||
|
std::uint32_t mFullBelowGen = 0;
|
||||||
|
|
||||||
|
static std::mutex childLock;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SHAMapInnerNode(std::uint32_t cowid);
|
||||||
|
|
||||||
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
|
clone(std::uint32_t cowid) const override;
|
||||||
|
|
||||||
|
SHAMapNodeType
|
||||||
|
getType() const override
|
||||||
|
{
|
||||||
|
return SHAMapNodeType::tnINNER;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
isLeaf() const override
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
isInner() const override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
isEmpty() const;
|
||||||
|
bool
|
||||||
|
isEmptyBranch(int m) const;
|
||||||
|
int
|
||||||
|
getBranchCount() const;
|
||||||
|
SHAMapHash const&
|
||||||
|
getChildHash(int m) const;
|
||||||
|
|
||||||
|
void
|
||||||
|
setChild(int m, std::shared_ptr<SHAMapTreeNode> const& child);
|
||||||
|
void
|
||||||
|
shareChild(int m, std::shared_ptr<SHAMapTreeNode> const& child);
|
||||||
|
SHAMapTreeNode*
|
||||||
|
getChildPointer(int branch);
|
||||||
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
|
getChild(int branch);
|
||||||
|
virtual std::shared_ptr<SHAMapTreeNode>
|
||||||
|
canonicalizeChild(int branch, std::shared_ptr<SHAMapTreeNode> node);
|
||||||
|
|
||||||
|
// sync functions
|
||||||
|
bool
|
||||||
|
isFullBelow(std::uint32_t generation) const;
|
||||||
|
void
|
||||||
|
setFullBelowGen(std::uint32_t gen);
|
||||||
|
|
||||||
|
void
|
||||||
|
updateHash() override;
|
||||||
|
|
||||||
|
/** Recalculate the hash of all children and this node. */
|
||||||
|
void
|
||||||
|
updateHashDeep();
|
||||||
|
|
||||||
|
void
|
||||||
|
serializeForWire(Serializer&) const override;
|
||||||
|
|
||||||
|
void
|
||||||
|
serializeWithPrefix(Serializer&) const override;
|
||||||
|
|
||||||
|
std::string
|
||||||
|
getString(SHAMapNodeID const&) const override;
|
||||||
|
|
||||||
|
void
|
||||||
|
invariants(bool is_root = false) const override;
|
||||||
|
|
||||||
|
static std::shared_ptr<SHAMapTreeNode>
|
||||||
|
makeFullInner(Slice data, SHAMapHash const& hash, bool hashValid);
|
||||||
|
|
||||||
|
static std::shared_ptr<SHAMapTreeNode>
|
||||||
|
makeCompressedInner(Slice data);
|
||||||
|
};
|
||||||
|
|
||||||
|
inline SHAMapInnerNode::SHAMapInnerNode(std::uint32_t cowid)
|
||||||
|
: SHAMapTreeNode(cowid)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
SHAMapInnerNode::isEmptyBranch(int m) const
|
||||||
|
{
|
||||||
|
return (mIsBranch & (1 << m)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline SHAMapHash const&
|
||||||
|
SHAMapInnerNode::getChildHash(int m) const
|
||||||
|
{
|
||||||
|
assert(m >= 0 && m < 16);
|
||||||
|
return mHashes[m];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
SHAMapInnerNode::isFullBelow(std::uint32_t generation) const
|
||||||
|
{
|
||||||
|
return mFullBelowGen == generation;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
SHAMapInnerNode::setFullBelowGen(std::uint32_t gen)
|
||||||
|
{
|
||||||
|
mFullBelowGen = gen;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ripple
|
||||||
|
#endif
|
||||||
82
src/ripple/shamap/SHAMapLeafNode.h
Normal file
82
src/ripple/shamap/SHAMapLeafNode.h
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef RIPPLE_SHAMAP_SHAMAPLEAFNODE_H_INCLUDED
|
||||||
|
#define RIPPLE_SHAMAP_SHAMAPLEAFNODE_H_INCLUDED
|
||||||
|
|
||||||
|
#include <ripple/shamap/SHAMapItem.h>
|
||||||
|
#include <ripple/shamap/SHAMapNodeID.h>
|
||||||
|
#include <ripple/shamap/SHAMapTreeNode.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
class SHAMapLeafNode : public SHAMapTreeNode
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
std::shared_ptr<SHAMapItem const> item_;
|
||||||
|
|
||||||
|
SHAMapLeafNode(std::shared_ptr<SHAMapItem const> item, std::uint32_t cowid);
|
||||||
|
SHAMapLeafNode(
|
||||||
|
std::shared_ptr<SHAMapItem const> item,
|
||||||
|
std::uint32_t cowid,
|
||||||
|
SHAMapHash const& hash);
|
||||||
|
|
||||||
|
public:
|
||||||
|
SHAMapLeafNode(const SHAMapLeafNode&) = delete;
|
||||||
|
SHAMapLeafNode&
|
||||||
|
operator=(const SHAMapLeafNode&) = delete;
|
||||||
|
|
||||||
|
bool
|
||||||
|
isLeaf() const final override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
isInner() const final override
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
invariants(bool is_root = false) const final override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::shared_ptr<SHAMapItem const> const&
|
||||||
|
peekItem() const;
|
||||||
|
|
||||||
|
/** Set the item that this node points to and update the node's hash.
|
||||||
|
|
||||||
|
@param i the new item
|
||||||
|
@return false if the change was, effectively, a noop (that is, if the
|
||||||
|
hash was unchanged); true otherwise.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
setItem(std::shared_ptr<SHAMapItem const> i);
|
||||||
|
|
||||||
|
std::string
|
||||||
|
getString(SHAMapNodeID const&) const final override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ripple
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -41,7 +41,8 @@ public:
|
|||||||
SHAMapNodeID(SHAMapNodeID const& other) = default;
|
SHAMapNodeID(SHAMapNodeID const& other) = default;
|
||||||
SHAMapNodeID(unsigned int depth, uint256 const& hash);
|
SHAMapNodeID(unsigned int depth, uint256 const& hash);
|
||||||
|
|
||||||
SHAMapNodeID& operator=(SHAMapNodeID const& other) = default;
|
SHAMapNodeID&
|
||||||
|
operator=(SHAMapNodeID const& other) = default;
|
||||||
|
|
||||||
bool
|
bool
|
||||||
isRoot() const
|
isRoot() const
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public:
|
|||||||
SHAMapHash const& nodeHash,
|
SHAMapHash const& nodeHash,
|
||||||
std::uint32_t ledgerSeq,
|
std::uint32_t ledgerSeq,
|
||||||
Blob&& nodeData,
|
Blob&& nodeData,
|
||||||
SHAMapTreeNode::TNType type) const = 0;
|
SHAMapNodeType type) const = 0;
|
||||||
|
|
||||||
virtual boost::optional<Blob>
|
virtual boost::optional<Blob>
|
||||||
getNode(SHAMapHash const& nodeHash) const = 0;
|
getNode(SHAMapHash const& nodeHash) const = 0;
|
||||||
|
|||||||
@@ -33,8 +33,17 @@
|
|||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
|
// These are wire-protocol identifiers used during serialization to encode the
|
||||||
|
// type of a node. They should not be arbitrarily be changed.
|
||||||
|
static constexpr unsigned char const wireTypeTransaction = 0;
|
||||||
|
static constexpr unsigned char const wireTypeAccountState = 1;
|
||||||
|
static constexpr unsigned char const wireTypeInner = 2;
|
||||||
|
static constexpr unsigned char const wireTypeCompressedInner = 3;
|
||||||
|
static constexpr unsigned char const wireTypeTransactionWithMeta = 4;
|
||||||
|
|
||||||
// A SHAMapHash is the hash of a node in a SHAMap, and also the
|
// A SHAMapHash is the hash of a node in a SHAMap, and also the
|
||||||
// type of the hash of the entire SHAMap.
|
// type of the hash of the entire SHAMap.
|
||||||
|
|
||||||
class SHAMapHash
|
class SHAMapHash
|
||||||
{
|
{
|
||||||
uint256 hash_;
|
uint256 hash_;
|
||||||
@@ -114,49 +123,120 @@ operator!=(SHAMapHash const& x, SHAMapHash const& y)
|
|||||||
return !(x == y);
|
return !(x == y);
|
||||||
}
|
}
|
||||||
|
|
||||||
class SHAMapAbstractNode
|
enum class SHAMapNodeType {
|
||||||
|
tnINNER = 1,
|
||||||
|
tnTRANSACTION_NM = 2, // transaction, no metadata
|
||||||
|
tnTRANSACTION_MD = 3, // transaction, with metadata
|
||||||
|
tnACCOUNT_STATE = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
class SHAMapTreeNode
|
||||||
{
|
{
|
||||||
public:
|
protected:
|
||||||
enum TNType {
|
SHAMapHash hash_;
|
||||||
tnINNER = 1,
|
|
||||||
tnTRANSACTION_NM = 2, // transaction, no metadata
|
/** Determines the owning SHAMap, if any. Used for copy-on-write semantics.
|
||||||
tnTRANSACTION_MD = 3, // transaction, with metadata
|
|
||||||
tnACCOUNT_STATE = 4
|
If this value is 0, the node is not dirty and does not need to be
|
||||||
};
|
flushed. It is eligible for sharing and may be included multiple
|
||||||
|
SHAMap instances.
|
||||||
|
*/
|
||||||
|
std::uint32_t cowid_;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
TNType mType;
|
SHAMapTreeNode(SHAMapTreeNode const&) = delete;
|
||||||
SHAMapHash mHash;
|
SHAMapTreeNode&
|
||||||
std::uint32_t mSeq;
|
operator=(SHAMapTreeNode const&) = delete;
|
||||||
|
|
||||||
protected:
|
/** Construct a node
|
||||||
virtual ~SHAMapAbstractNode() = 0;
|
|
||||||
SHAMapAbstractNode(SHAMapAbstractNode const&) = delete;
|
|
||||||
SHAMapAbstractNode&
|
|
||||||
operator=(SHAMapAbstractNode const&) = delete;
|
|
||||||
|
|
||||||
SHAMapAbstractNode(TNType type, std::uint32_t seq);
|
@param cowid The identifier of a SHAMap. For more, see #cowid_
|
||||||
SHAMapAbstractNode(TNType type, std::uint32_t seq, SHAMapHash const& hash);
|
@param hash The hash associated with this node, if any.
|
||||||
|
*/
|
||||||
|
/** @{ */
|
||||||
|
explicit SHAMapTreeNode(std::uint32_t cowid) noexcept : cowid_(cowid)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit SHAMapTreeNode(
|
||||||
|
std::uint32_t cowid,
|
||||||
|
SHAMapHash const& hash) noexcept
|
||||||
|
: hash_(hash), cowid_(cowid)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
/** @} */
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
virtual ~SHAMapTreeNode() noexcept = default;
|
||||||
|
|
||||||
|
/** \defgroup SHAMap Copy-on-Write Support
|
||||||
|
|
||||||
|
By nature, a node may appear in multiple SHAMap instances. Rather than
|
||||||
|
actually duplicating these nodes, SHAMap opts to be memory efficient
|
||||||
|
and uses copy-on-write semantics for nodes.
|
||||||
|
|
||||||
|
Only nodes that are not modified and don't need to be flushed back can
|
||||||
|
be shared. Once a node needs to be changed, it must first be copied and
|
||||||
|
the copy must marked as not shareable.
|
||||||
|
|
||||||
|
Note that just because a node may not be *owned* by a given SHAMap
|
||||||
|
instance does not mean that the node is NOT a part of any SHAMap. It
|
||||||
|
only means that the node is not owned exclusively by any one SHAMap.
|
||||||
|
|
||||||
|
For more on copy-on-write, check out:
|
||||||
|
https://en.wikipedia.org/wiki/Copy-on-write
|
||||||
|
*/
|
||||||
|
/** @{ */
|
||||||
|
/** Returns the SHAMap that owns this node.
|
||||||
|
|
||||||
|
@return the ID of the SHAMap that owns this node, or 0 if the node
|
||||||
|
is not owned by any SHAMap and is a candidate for sharing.
|
||||||
|
*/
|
||||||
std::uint32_t
|
std::uint32_t
|
||||||
getSeq() const;
|
cowid() const
|
||||||
void
|
{
|
||||||
setSeq(std::uint32_t s);
|
return cowid_;
|
||||||
SHAMapHash const&
|
}
|
||||||
getNodeHash() const;
|
|
||||||
TNType
|
|
||||||
getType() const;
|
|
||||||
bool
|
|
||||||
isLeaf() const;
|
|
||||||
bool
|
|
||||||
isInner() const;
|
|
||||||
bool
|
|
||||||
isInBounds(SHAMapNodeID const& id) const;
|
|
||||||
|
|
||||||
virtual bool
|
/** If this node is shared with another map, mark it as no longer shared.
|
||||||
|
|
||||||
|
Only nodes that are not modified and do not need to be flushed back
|
||||||
|
should be marked as unshared.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
unshare()
|
||||||
|
{
|
||||||
|
cowid_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Make a copy of this node, setting the owner. */
|
||||||
|
virtual std::shared_ptr<SHAMapTreeNode>
|
||||||
|
clone(std::uint32_t cowid) const = 0;
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/** Recalculate the hash of this node. */
|
||||||
|
virtual void
|
||||||
updateHash() = 0;
|
updateHash() = 0;
|
||||||
|
|
||||||
|
/** Return the hash of this node. */
|
||||||
|
SHAMapHash const&
|
||||||
|
getHash() const
|
||||||
|
{
|
||||||
|
return hash_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Determines the type of node. */
|
||||||
|
virtual SHAMapNodeType
|
||||||
|
getType() const = 0;
|
||||||
|
|
||||||
|
/** Determines if this is a leaf node. */
|
||||||
|
virtual bool
|
||||||
|
isLeaf() const = 0;
|
||||||
|
|
||||||
|
/** Determines if this is an inner node. */
|
||||||
|
virtual bool
|
||||||
|
isInner() const = 0;
|
||||||
|
|
||||||
/** Serialize the node in a format appropriate for sending over the wire */
|
/** Serialize the node in a format appropriate for sending over the wire */
|
||||||
virtual void
|
virtual void
|
||||||
serializeForWire(Serializer&) const = 0;
|
serializeForWire(Serializer&) const = 0;
|
||||||
@@ -167,268 +247,27 @@ public:
|
|||||||
|
|
||||||
virtual std::string
|
virtual std::string
|
||||||
getString(SHAMapNodeID const&) const;
|
getString(SHAMapNodeID const&) const;
|
||||||
virtual std::shared_ptr<SHAMapAbstractNode>
|
|
||||||
clone(std::uint32_t seq) const = 0;
|
|
||||||
virtual uint256 const&
|
|
||||||
key() const = 0;
|
|
||||||
virtual void
|
virtual void
|
||||||
invariants(bool is_root = false) const = 0;
|
invariants(bool is_root = false) const = 0;
|
||||||
|
|
||||||
static std::shared_ptr<SHAMapAbstractNode>
|
static std::shared_ptr<SHAMapTreeNode>
|
||||||
makeFromPrefix(Slice rawNode, SHAMapHash const& hash);
|
makeFromPrefix(Slice rawNode, SHAMapHash const& hash);
|
||||||
|
|
||||||
static std::shared_ptr<SHAMapAbstractNode>
|
static std::shared_ptr<SHAMapTreeNode>
|
||||||
makeFromWire(Slice rawNode);
|
makeFromWire(Slice rawNode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::shared_ptr<SHAMapAbstractNode>
|
static std::shared_ptr<SHAMapTreeNode>
|
||||||
makeTransaction(
|
makeTransaction(Slice data, SHAMapHash const& hash, bool hashValid);
|
||||||
Slice data,
|
|
||||||
std::uint32_t seq,
|
|
||||||
SHAMapHash const& hash,
|
|
||||||
bool hashValid);
|
|
||||||
|
|
||||||
static std::shared_ptr<SHAMapAbstractNode>
|
static std::shared_ptr<SHAMapTreeNode>
|
||||||
makeAccountState(
|
makeAccountState(Slice data, SHAMapHash const& hash, bool hashValid);
|
||||||
Slice data,
|
|
||||||
std::uint32_t seq,
|
|
||||||
SHAMapHash const& hash,
|
|
||||||
bool hashValid);
|
|
||||||
|
|
||||||
static std::shared_ptr<SHAMapAbstractNode>
|
static std::shared_ptr<SHAMapTreeNode>
|
||||||
makeTransactionWithMeta(
|
makeTransactionWithMeta(Slice data, SHAMapHash const& hash, bool hashValid);
|
||||||
Slice data,
|
|
||||||
std::uint32_t seq,
|
|
||||||
SHAMapHash const& hash,
|
|
||||||
bool hashValid);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class SHAMapInnerNode : public SHAMapAbstractNode,
|
|
||||||
public CountedObject<SHAMapInnerNode>
|
|
||||||
{
|
|
||||||
std::array<SHAMapHash, 16> mHashes;
|
|
||||||
std::shared_ptr<SHAMapAbstractNode> mChildren[16];
|
|
||||||
int mIsBranch = 0;
|
|
||||||
std::uint32_t mFullBelowGen = 0;
|
|
||||||
|
|
||||||
static std::mutex childLock;
|
|
||||||
|
|
||||||
public:
|
|
||||||
SHAMapInnerNode(std::uint32_t seq);
|
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
|
||||||
clone(std::uint32_t seq) const override;
|
|
||||||
|
|
||||||
bool
|
|
||||||
isEmpty() const;
|
|
||||||
bool
|
|
||||||
isEmptyBranch(int m) const;
|
|
||||||
int
|
|
||||||
getBranchCount() const;
|
|
||||||
SHAMapHash const&
|
|
||||||
getChildHash(int m) const;
|
|
||||||
|
|
||||||
void
|
|
||||||
setChild(int m, std::shared_ptr<SHAMapAbstractNode> const& child);
|
|
||||||
void
|
|
||||||
shareChild(int m, std::shared_ptr<SHAMapAbstractNode> const& child);
|
|
||||||
SHAMapAbstractNode*
|
|
||||||
getChildPointer(int branch);
|
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
|
||||||
getChild(int branch);
|
|
||||||
virtual std::shared_ptr<SHAMapAbstractNode>
|
|
||||||
canonicalizeChild(int branch, std::shared_ptr<SHAMapAbstractNode> node);
|
|
||||||
|
|
||||||
// sync functions
|
|
||||||
bool
|
|
||||||
isFullBelow(std::uint32_t generation) const;
|
|
||||||
void
|
|
||||||
setFullBelowGen(std::uint32_t gen);
|
|
||||||
|
|
||||||
bool
|
|
||||||
updateHash() override;
|
|
||||||
void
|
|
||||||
updateHashDeep();
|
|
||||||
|
|
||||||
void
|
|
||||||
serializeForWire(Serializer&) const override;
|
|
||||||
|
|
||||||
void
|
|
||||||
serializeWithPrefix(Serializer&) const override;
|
|
||||||
|
|
||||||
std::string
|
|
||||||
getString(SHAMapNodeID const&) const override;
|
|
||||||
uint256 const&
|
|
||||||
key() const override;
|
|
||||||
void
|
|
||||||
invariants(bool is_root = false) const override;
|
|
||||||
|
|
||||||
static std::shared_ptr<SHAMapAbstractNode>
|
|
||||||
makeFullInner(
|
|
||||||
Slice data,
|
|
||||||
std::uint32_t seq,
|
|
||||||
SHAMapHash const& hash,
|
|
||||||
bool hashValid);
|
|
||||||
|
|
||||||
static std::shared_ptr<SHAMapAbstractNode>
|
|
||||||
makeCompressedInner(Slice data, std::uint32_t seq);
|
|
||||||
};
|
|
||||||
|
|
||||||
// SHAMapTreeNode represents a leaf, and may eventually be renamed to reflect
|
|
||||||
// that.
|
|
||||||
class SHAMapTreeNode : public SHAMapAbstractNode,
|
|
||||||
public CountedObject<SHAMapTreeNode>
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
std::shared_ptr<SHAMapItem const> mItem;
|
|
||||||
|
|
||||||
public:
|
|
||||||
SHAMapTreeNode(const SHAMapTreeNode&) = delete;
|
|
||||||
SHAMapTreeNode&
|
|
||||||
operator=(const SHAMapTreeNode&) = delete;
|
|
||||||
|
|
||||||
SHAMapTreeNode(
|
|
||||||
std::shared_ptr<SHAMapItem const> item,
|
|
||||||
TNType type,
|
|
||||||
std::uint32_t seq);
|
|
||||||
SHAMapTreeNode(
|
|
||||||
std::shared_ptr<SHAMapItem const> item,
|
|
||||||
TNType type,
|
|
||||||
std::uint32_t seq,
|
|
||||||
SHAMapHash const& hash);
|
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
|
||||||
clone(std::uint32_t seq) const override;
|
|
||||||
|
|
||||||
void
|
|
||||||
serializeForWire(Serializer&) const override;
|
|
||||||
|
|
||||||
void
|
|
||||||
serializeWithPrefix(Serializer&) const override;
|
|
||||||
|
|
||||||
uint256 const&
|
|
||||||
key() const override;
|
|
||||||
void
|
|
||||||
invariants(bool is_root = false) const override;
|
|
||||||
|
|
||||||
public: // public only to SHAMap
|
|
||||||
// item node function
|
|
||||||
bool
|
|
||||||
hasItem() const;
|
|
||||||
std::shared_ptr<SHAMapItem const> const&
|
|
||||||
peekItem() const;
|
|
||||||
bool
|
|
||||||
setItem(std::shared_ptr<SHAMapItem const> i, TNType type);
|
|
||||||
|
|
||||||
std::string
|
|
||||||
getString(SHAMapNodeID const&) const override;
|
|
||||||
bool
|
|
||||||
updateHash() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
// SHAMapAbstractNode
|
|
||||||
|
|
||||||
inline SHAMapAbstractNode::SHAMapAbstractNode(TNType type, std::uint32_t seq)
|
|
||||||
: mType(type), mSeq(seq)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline SHAMapAbstractNode::SHAMapAbstractNode(
|
|
||||||
TNType type,
|
|
||||||
std::uint32_t seq,
|
|
||||||
SHAMapHash const& hash)
|
|
||||||
: mType(type), mHash(hash), mSeq(seq)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::uint32_t
|
|
||||||
SHAMapAbstractNode::getSeq() const
|
|
||||||
{
|
|
||||||
return mSeq;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
SHAMapAbstractNode::setSeq(std::uint32_t s)
|
|
||||||
{
|
|
||||||
mSeq = s;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline SHAMapHash const&
|
|
||||||
SHAMapAbstractNode::getNodeHash() const
|
|
||||||
{
|
|
||||||
return mHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline SHAMapAbstractNode::TNType
|
|
||||||
SHAMapAbstractNode::getType() const
|
|
||||||
{
|
|
||||||
return mType;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool
|
|
||||||
SHAMapAbstractNode::isLeaf() const
|
|
||||||
{
|
|
||||||
return (mType == tnTRANSACTION_NM) || (mType == tnTRANSACTION_MD) ||
|
|
||||||
(mType == tnACCOUNT_STATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool
|
|
||||||
SHAMapAbstractNode::isInner() const
|
|
||||||
{
|
|
||||||
return mType == tnINNER;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool
|
|
||||||
SHAMapAbstractNode::isInBounds(SHAMapNodeID const& id) const
|
|
||||||
{
|
|
||||||
// Nodes at depth 64 must be leaves
|
|
||||||
return (!isInner() || (id.getDepth() < 64));
|
|
||||||
}
|
|
||||||
|
|
||||||
// SHAMapInnerNode
|
|
||||||
|
|
||||||
inline SHAMapInnerNode::SHAMapInnerNode(std::uint32_t seq)
|
|
||||||
: SHAMapAbstractNode(tnINNER, seq)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool
|
|
||||||
SHAMapInnerNode::isEmptyBranch(int m) const
|
|
||||||
{
|
|
||||||
return (mIsBranch & (1 << m)) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline SHAMapHash const&
|
|
||||||
SHAMapInnerNode::getChildHash(int m) const
|
|
||||||
{
|
|
||||||
assert((m >= 0) && (m < 16) && (getType() == tnINNER));
|
|
||||||
return mHashes[m];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool
|
|
||||||
SHAMapInnerNode::isFullBelow(std::uint32_t generation) const
|
|
||||||
{
|
|
||||||
return mFullBelowGen == generation;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
SHAMapInnerNode::setFullBelowGen(std::uint32_t gen)
|
|
||||||
{
|
|
||||||
mFullBelowGen = gen;
|
|
||||||
}
|
|
||||||
|
|
||||||
// SHAMapTreeNode
|
|
||||||
|
|
||||||
inline bool
|
|
||||||
SHAMapTreeNode::hasItem() const
|
|
||||||
{
|
|
||||||
return bool(mItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::shared_ptr<SHAMapItem const> const&
|
|
||||||
SHAMapTreeNode::peekItem() const
|
|
||||||
{
|
|
||||||
return mItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ripple
|
} // namespace ripple
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
89
src/ripple/shamap/SHAMapTxLeafNode.h
Normal file
89
src/ripple/shamap/SHAMapTxLeafNode.h
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef RIPPLE_SHAMAP_SHAMAPTXLEAFNODE_H_INCLUDED
|
||||||
|
#define RIPPLE_SHAMAP_SHAMAPTXLEAFNODE_H_INCLUDED
|
||||||
|
|
||||||
|
#include <ripple/basics/CountedObject.h>
|
||||||
|
#include <ripple/protocol/HashPrefix.h>
|
||||||
|
#include <ripple/protocol/digest.h>
|
||||||
|
#include <ripple/shamap/SHAMapItem.h>
|
||||||
|
#include <ripple/shamap/SHAMapLeafNode.h>
|
||||||
|
#include <ripple/shamap/SHAMapNodeID.h>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
/** A leaf node for a transaction. No metadata is included. */
|
||||||
|
class SHAMapTxLeafNode final : public SHAMapLeafNode,
|
||||||
|
public CountedObject<SHAMapTxLeafNode>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SHAMapTxLeafNode(
|
||||||
|
std::shared_ptr<SHAMapItem const> item,
|
||||||
|
std::uint32_t cowid)
|
||||||
|
: SHAMapLeafNode(std::move(item), cowid)
|
||||||
|
{
|
||||||
|
updateHash();
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAMapTxLeafNode(
|
||||||
|
std::shared_ptr<SHAMapItem const> item,
|
||||||
|
std::uint32_t cowid,
|
||||||
|
SHAMapHash const& hash)
|
||||||
|
: SHAMapLeafNode(std::move(item), cowid, hash)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
|
clone(std::uint32_t cowid) const final override
|
||||||
|
{
|
||||||
|
return std::make_shared<SHAMapTxLeafNode>(item_, cowid, hash_);
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAMapNodeType
|
||||||
|
getType() const final override
|
||||||
|
{
|
||||||
|
return SHAMapNodeType::tnTRANSACTION_NM;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
updateHash() final override
|
||||||
|
{
|
||||||
|
hash_ = SHAMapHash{sha512Half(
|
||||||
|
HashPrefix::transactionID, makeSlice(item_->peekData()))};
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
serializeForWire(Serializer& s) const final override
|
||||||
|
{
|
||||||
|
s.addRaw(item_->peekData());
|
||||||
|
s.add8(wireTypeTransaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
serializeWithPrefix(Serializer& s) const final override
|
||||||
|
{
|
||||||
|
s.add32(HashPrefix::transactionID);
|
||||||
|
s.addRaw(item_->peekData());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ripple
|
||||||
|
|
||||||
|
#endif
|
||||||
92
src/ripple/shamap/SHAMapTxPlusMetaLeafNode.h
Normal file
92
src/ripple/shamap/SHAMapTxPlusMetaLeafNode.h
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef RIPPLE_SHAMAP_SHAMAPLEAFTXPLUSMETANODE_H_INCLUDED
|
||||||
|
#define RIPPLE_SHAMAP_SHAMAPLEAFTXPLUSMETANODE_H_INCLUDED
|
||||||
|
|
||||||
|
#include <ripple/basics/CountedObject.h>
|
||||||
|
#include <ripple/protocol/HashPrefix.h>
|
||||||
|
#include <ripple/protocol/digest.h>
|
||||||
|
#include <ripple/shamap/SHAMapItem.h>
|
||||||
|
#include <ripple/shamap/SHAMapLeafNode.h>
|
||||||
|
#include <ripple/shamap/SHAMapNodeID.h>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
/** A leaf node for a transaction and its associated metadata. */
|
||||||
|
class SHAMapTxPlusMetaLeafNode final
|
||||||
|
: public SHAMapLeafNode,
|
||||||
|
public CountedObject<SHAMapTxPlusMetaLeafNode>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SHAMapTxPlusMetaLeafNode(
|
||||||
|
std::shared_ptr<SHAMapItem const> item,
|
||||||
|
std::uint32_t cowid)
|
||||||
|
: SHAMapLeafNode(std::move(item), cowid)
|
||||||
|
{
|
||||||
|
updateHash();
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAMapTxPlusMetaLeafNode(
|
||||||
|
std::shared_ptr<SHAMapItem const> item,
|
||||||
|
std::uint32_t cowid,
|
||||||
|
SHAMapHash const& hash)
|
||||||
|
: SHAMapLeafNode(std::move(item), cowid, hash)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
|
clone(std::uint32_t cowid) const override
|
||||||
|
{
|
||||||
|
return std::make_shared<SHAMapTxPlusMetaLeafNode>(item_, cowid, hash_);
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAMapNodeType
|
||||||
|
getType() const override
|
||||||
|
{
|
||||||
|
return SHAMapNodeType::tnTRANSACTION_MD;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
updateHash() final override
|
||||||
|
{
|
||||||
|
hash_ = SHAMapHash{sha512Half(
|
||||||
|
HashPrefix::txNode, makeSlice(item_->peekData()), item_->key())};
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
serializeForWire(Serializer& s) const final override
|
||||||
|
{
|
||||||
|
s.addRaw(item_->peekData());
|
||||||
|
s.addBitString(item_->key());
|
||||||
|
s.add8(wireTypeTransactionWithMeta);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
serializeWithPrefix(Serializer& s) const final override
|
||||||
|
{
|
||||||
|
s.add32(HashPrefix::txNode);
|
||||||
|
s.addRaw(item_->peekData());
|
||||||
|
s.addBitString(item_->key());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ripple
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
using TreeNodeCache = TaggedCache<uint256, SHAMapAbstractNode>;
|
using TreeNodeCache = TaggedCache<uint256, SHAMapTreeNode>;
|
||||||
|
|
||||||
} // namespace ripple
|
} // namespace ripple
|
||||||
|
|
||||||
|
|||||||
@@ -19,19 +19,41 @@
|
|||||||
|
|
||||||
#include <ripple/basics/contract.h>
|
#include <ripple/basics/contract.h>
|
||||||
#include <ripple/shamap/SHAMap.h>
|
#include <ripple/shamap/SHAMap.h>
|
||||||
|
#include <ripple/shamap/SHAMapAccountStateLeafNode.h>
|
||||||
#include <ripple/shamap/SHAMapNodeID.h>
|
#include <ripple/shamap/SHAMapNodeID.h>
|
||||||
#include <ripple/shamap/SHAMapSyncFilter.h>
|
#include <ripple/shamap/SHAMapSyncFilter.h>
|
||||||
|
#include <ripple/shamap/SHAMapTxLeafNode.h>
|
||||||
|
#include <ripple/shamap/SHAMapTxPlusMetaLeafNode.h>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
SHAMap::SHAMap(SHAMapType t, Family& f)
|
[[nodiscard]] std::shared_ptr<SHAMapLeafNode>
|
||||||
: f_(f)
|
makeTypedLeaf(
|
||||||
, journal_(f.journal())
|
SHAMapNodeType type,
|
||||||
, seq_(1)
|
std::shared_ptr<SHAMapItem const> item,
|
||||||
, state_(SHAMapState::Modifying)
|
std::uint32_t owner)
|
||||||
, type_(t)
|
|
||||||
{
|
{
|
||||||
root_ = std::make_shared<SHAMapInnerNode>(seq_);
|
if (type == SHAMapNodeType::tnTRANSACTION_NM)
|
||||||
|
return std::make_shared<SHAMapTxLeafNode>(std::move(item), owner);
|
||||||
|
|
||||||
|
if (type == SHAMapNodeType::tnTRANSACTION_MD)
|
||||||
|
return std::make_shared<SHAMapTxPlusMetaLeafNode>(
|
||||||
|
std::move(item), owner);
|
||||||
|
|
||||||
|
if (type == SHAMapNodeType::tnACCOUNT_STATE)
|
||||||
|
return std::make_shared<SHAMapAccountStateLeafNode>(
|
||||||
|
std::move(item), owner);
|
||||||
|
|
||||||
|
LogicError(
|
||||||
|
"Attempt to create leaf node of unknown type " +
|
||||||
|
std::to_string(
|
||||||
|
static_cast<std::underlying_type_t<SHAMapNodeType>>(type)));
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAMap::SHAMap(SHAMapType t, Family& f)
|
||||||
|
: f_(f), journal_(f.journal()), state_(SHAMapState::Modifying), type_(t)
|
||||||
|
{
|
||||||
|
root_ = std::make_shared<SHAMapInnerNode>(cowid_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The `hash` parameter is unused. It is part of the interface so it's clear
|
// The `hash` parameter is unused. It is part of the interface so it's clear
|
||||||
@@ -39,18 +61,9 @@ SHAMap::SHAMap(SHAMapType t, Family& f)
|
|||||||
// known. The fact that the parameter is unused is an implementation detail that
|
// known. The fact that the parameter is unused is an implementation detail that
|
||||||
// should not change the interface.
|
// should not change the interface.
|
||||||
SHAMap::SHAMap(SHAMapType t, uint256 const& hash, Family& f)
|
SHAMap::SHAMap(SHAMapType t, uint256 const& hash, Family& f)
|
||||||
: f_(f)
|
: f_(f), journal_(f.journal()), state_(SHAMapState::Synching), type_(t)
|
||||||
, journal_(f.journal())
|
|
||||||
, seq_(1)
|
|
||||||
, state_(SHAMapState::Synching)
|
|
||||||
, type_(t)
|
|
||||||
{
|
{
|
||||||
root_ = std::make_shared<SHAMapInnerNode>(seq_);
|
root_ = std::make_shared<SHAMapInnerNode>(cowid_);
|
||||||
}
|
|
||||||
|
|
||||||
SHAMap::~SHAMap()
|
|
||||||
{
|
|
||||||
state_ = SHAMapState::Invalid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<SHAMap>
|
std::shared_ptr<SHAMap>
|
||||||
@@ -62,7 +75,7 @@ SHAMap::snapShot(bool isMutable) const
|
|||||||
if (!isMutable)
|
if (!isMutable)
|
||||||
newMap.state_ = SHAMapState::Immutable;
|
newMap.state_ = SHAMapState::Immutable;
|
||||||
|
|
||||||
newMap.seq_ = seq_ + 1;
|
newMap.cowid_ = cowid_ + 1;
|
||||||
newMap.ledgerSeq_ = ledgerSeq_;
|
newMap.ledgerSeq_ = ledgerSeq_;
|
||||||
newMap.root_ = root_;
|
newMap.root_ = root_;
|
||||||
newMap.backed_ = backed_;
|
newMap.backed_ = backed_;
|
||||||
@@ -81,7 +94,7 @@ void
|
|||||||
SHAMap::dirtyUp(
|
SHAMap::dirtyUp(
|
||||||
SharedPtrNodeStack& stack,
|
SharedPtrNodeStack& stack,
|
||||||
uint256 const& target,
|
uint256 const& target,
|
||||||
std::shared_ptr<SHAMapAbstractNode> child)
|
std::shared_ptr<SHAMapTreeNode> child)
|
||||||
{
|
{
|
||||||
// walk the tree up from through the inner nodes to the root_
|
// walk the tree up from through the inner nodes to the root_
|
||||||
// update hashes and links
|
// update hashes and links
|
||||||
@@ -91,7 +104,7 @@ SHAMap::dirtyUp(
|
|||||||
assert(
|
assert(
|
||||||
(state_ != SHAMapState::Synching) &&
|
(state_ != SHAMapState::Synching) &&
|
||||||
(state_ != SHAMapState::Immutable));
|
(state_ != SHAMapState::Immutable));
|
||||||
assert(child && (child->getSeq() == seq_));
|
assert(child && (child->cowid() == cowid_));
|
||||||
|
|
||||||
while (!stack.empty())
|
while (!stack.empty())
|
||||||
{
|
{
|
||||||
@@ -111,7 +124,7 @@ SHAMap::dirtyUp(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SHAMapTreeNode*
|
SHAMapLeafNode*
|
||||||
SHAMap::walkTowardsKey(uint256 const& id, SharedPtrNodeStack* stack) const
|
SHAMap::walkTowardsKey(uint256 const& id, SharedPtrNodeStack* stack) const
|
||||||
{
|
{
|
||||||
assert(stack == nullptr || stack->empty());
|
assert(stack == nullptr || stack->empty());
|
||||||
@@ -134,22 +147,22 @@ SHAMap::walkTowardsKey(uint256 const& id, SharedPtrNodeStack* stack) const
|
|||||||
|
|
||||||
if (stack != nullptr)
|
if (stack != nullptr)
|
||||||
stack->push({inNode, nodeID});
|
stack->push({inNode, nodeID});
|
||||||
return static_cast<SHAMapTreeNode*>(inNode.get());
|
return static_cast<SHAMapLeafNode*>(inNode.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
SHAMapTreeNode*
|
SHAMapLeafNode*
|
||||||
SHAMap::findKey(uint256 const& id) const
|
SHAMap::findKey(uint256 const& id) const
|
||||||
{
|
{
|
||||||
SHAMapTreeNode* leaf = walkTowardsKey(id);
|
SHAMapLeafNode* leaf = walkTowardsKey(id);
|
||||||
if (leaf && leaf->peekItem()->key() != id)
|
if (leaf && leaf->peekItem()->key() != id)
|
||||||
leaf = nullptr;
|
leaf = nullptr;
|
||||||
return leaf;
|
return leaf;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
SHAMap::fetchNodeFromDB(SHAMapHash const& hash) const
|
SHAMap::fetchNodeFromDB(SHAMapHash const& hash) const
|
||||||
{
|
{
|
||||||
std::shared_ptr<SHAMapAbstractNode> node;
|
std::shared_ptr<SHAMapTreeNode> node;
|
||||||
|
|
||||||
if (backed_)
|
if (backed_)
|
||||||
{
|
{
|
||||||
@@ -158,7 +171,7 @@ SHAMap::fetchNodeFromDB(SHAMapHash const& hash) const
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
node = SHAMapAbstractNode::makeFromPrefix(
|
node = SHAMapTreeNode::makeFromPrefix(
|
||||||
makeSlice(nodeObject->getData()), hash);
|
makeSlice(nodeObject->getData()), hash);
|
||||||
if (node)
|
if (node)
|
||||||
canonicalize(hash, node);
|
canonicalize(hash, node);
|
||||||
@@ -166,13 +179,13 @@ SHAMap::fetchNodeFromDB(SHAMapHash const& hash) const
|
|||||||
catch (std::exception const&)
|
catch (std::exception const&)
|
||||||
{
|
{
|
||||||
JLOG(journal_.warn()) << "Invalid DB node " << hash;
|
JLOG(journal_.warn()) << "Invalid DB node " << hash;
|
||||||
return std::shared_ptr<SHAMapTreeNode>();
|
return std::shared_ptr<SHAMapLeafNode>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (full_)
|
else if (full_)
|
||||||
{
|
{
|
||||||
|
full_ = false;
|
||||||
f_.missingNode(ledgerSeq_);
|
f_.missingNode(ledgerSeq_);
|
||||||
const_cast<bool&>(full_) = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,7 +193,7 @@ SHAMap::fetchNodeFromDB(SHAMapHash const& hash) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// See if a sync filter has a node
|
// See if a sync filter has a node
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
SHAMap::checkFilter(SHAMapHash const& hash, SHAMapSyncFilter* filter) const
|
SHAMap::checkFilter(SHAMapHash const& hash, SHAMapSyncFilter* filter) const
|
||||||
{
|
{
|
||||||
if (auto nodeData = filter->getNode(hash))
|
if (auto nodeData = filter->getNode(hash))
|
||||||
@@ -188,7 +201,7 @@ SHAMap::checkFilter(SHAMapHash const& hash, SHAMapSyncFilter* filter) const
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto node =
|
auto node =
|
||||||
SHAMapAbstractNode::makeFromPrefix(makeSlice(*nodeData), hash);
|
SHAMapTreeNode::makeFromPrefix(makeSlice(*nodeData), hash);
|
||||||
if (node)
|
if (node)
|
||||||
{
|
{
|
||||||
filter->gotNode(
|
filter->gotNode(
|
||||||
@@ -213,10 +226,10 @@ SHAMap::checkFilter(SHAMapHash const& hash, SHAMapSyncFilter* filter) const
|
|||||||
|
|
||||||
// Get a node without throwing
|
// Get a node without throwing
|
||||||
// Used on maps where missing nodes are expected
|
// Used on maps where missing nodes are expected
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
SHAMap::fetchNodeNT(SHAMapHash const& hash, SHAMapSyncFilter* filter) const
|
SHAMap::fetchNodeNT(SHAMapHash const& hash, SHAMapSyncFilter* filter) const
|
||||||
{
|
{
|
||||||
std::shared_ptr<SHAMapAbstractNode> node = getCache(hash);
|
auto node = cacheLookup(hash);
|
||||||
if (node)
|
if (node)
|
||||||
return node;
|
return node;
|
||||||
|
|
||||||
@@ -236,10 +249,10 @@ SHAMap::fetchNodeNT(SHAMapHash const& hash, SHAMapSyncFilter* filter) const
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
SHAMap::fetchNodeNT(SHAMapHash const& hash) const
|
SHAMap::fetchNodeNT(SHAMapHash const& hash) const
|
||||||
{
|
{
|
||||||
auto node = getCache(hash);
|
auto node = cacheLookup(hash);
|
||||||
|
|
||||||
if (!node && backed_)
|
if (!node && backed_)
|
||||||
node = fetchNodeFromDB(hash);
|
node = fetchNodeFromDB(hash);
|
||||||
@@ -248,7 +261,7 @@ SHAMap::fetchNodeNT(SHAMapHash const& hash) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Throw if the node is missing
|
// Throw if the node is missing
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
SHAMap::fetchNode(SHAMapHash const& hash) const
|
SHAMap::fetchNode(SHAMapHash const& hash) const
|
||||||
{
|
{
|
||||||
auto node = fetchNodeNT(hash);
|
auto node = fetchNodeNT(hash);
|
||||||
@@ -259,10 +272,10 @@ SHAMap::fetchNode(SHAMapHash const& hash) const
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
SHAMapAbstractNode*
|
SHAMapTreeNode*
|
||||||
SHAMap::descendThrow(SHAMapInnerNode* parent, int branch) const
|
SHAMap::descendThrow(SHAMapInnerNode* parent, int branch) const
|
||||||
{
|
{
|
||||||
SHAMapAbstractNode* ret = descend(parent, branch);
|
SHAMapTreeNode* ret = descend(parent, branch);
|
||||||
|
|
||||||
if (!ret && !parent->isEmptyBranch(branch))
|
if (!ret && !parent->isEmptyBranch(branch))
|
||||||
Throw<SHAMapMissingNode>(type_, parent->getChildHash(branch));
|
Throw<SHAMapMissingNode>(type_, parent->getChildHash(branch));
|
||||||
@@ -270,11 +283,11 @@ SHAMap::descendThrow(SHAMapInnerNode* parent, int branch) const
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
SHAMap::descendThrow(std::shared_ptr<SHAMapInnerNode> const& parent, int branch)
|
SHAMap::descendThrow(std::shared_ptr<SHAMapInnerNode> const& parent, int branch)
|
||||||
const
|
const
|
||||||
{
|
{
|
||||||
std::shared_ptr<SHAMapAbstractNode> ret = descend(parent, branch);
|
std::shared_ptr<SHAMapTreeNode> ret = descend(parent, branch);
|
||||||
|
|
||||||
if (!ret && !parent->isEmptyBranch(branch))
|
if (!ret && !parent->isEmptyBranch(branch))
|
||||||
Throw<SHAMapMissingNode>(type_, parent->getChildHash(branch));
|
Throw<SHAMapMissingNode>(type_, parent->getChildHash(branch));
|
||||||
@@ -282,14 +295,14 @@ SHAMap::descendThrow(std::shared_ptr<SHAMapInnerNode> const& parent, int branch)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
SHAMapAbstractNode*
|
SHAMapTreeNode*
|
||||||
SHAMap::descend(SHAMapInnerNode* parent, int branch) const
|
SHAMap::descend(SHAMapInnerNode* parent, int branch) const
|
||||||
{
|
{
|
||||||
SHAMapAbstractNode* ret = parent->getChildPointer(branch);
|
SHAMapTreeNode* ret = parent->getChildPointer(branch);
|
||||||
if (ret || !backed_)
|
if (ret || !backed_)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
std::shared_ptr<SHAMapAbstractNode> node =
|
std::shared_ptr<SHAMapTreeNode> node =
|
||||||
fetchNodeNT(parent->getChildHash(branch));
|
fetchNodeNT(parent->getChildHash(branch));
|
||||||
if (!node)
|
if (!node)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -298,11 +311,11 @@ SHAMap::descend(SHAMapInnerNode* parent, int branch) const
|
|||||||
return node.get();
|
return node.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
SHAMap::descend(std::shared_ptr<SHAMapInnerNode> const& parent, int branch)
|
SHAMap::descend(std::shared_ptr<SHAMapInnerNode> const& parent, int branch)
|
||||||
const
|
const
|
||||||
{
|
{
|
||||||
std::shared_ptr<SHAMapAbstractNode> node = parent->getChild(branch);
|
std::shared_ptr<SHAMapTreeNode> node = parent->getChild(branch);
|
||||||
if (node || !backed_)
|
if (node || !backed_)
|
||||||
return node;
|
return node;
|
||||||
|
|
||||||
@@ -316,18 +329,18 @@ SHAMap::descend(std::shared_ptr<SHAMapInnerNode> const& parent, int branch)
|
|||||||
|
|
||||||
// Gets the node that would be hooked to this branch,
|
// Gets the node that would be hooked to this branch,
|
||||||
// but doesn't hook it up.
|
// but doesn't hook it up.
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
SHAMap::descendNoStore(
|
SHAMap::descendNoStore(
|
||||||
std::shared_ptr<SHAMapInnerNode> const& parent,
|
std::shared_ptr<SHAMapInnerNode> const& parent,
|
||||||
int branch) const
|
int branch) const
|
||||||
{
|
{
|
||||||
std::shared_ptr<SHAMapAbstractNode> ret = parent->getChild(branch);
|
std::shared_ptr<SHAMapTreeNode> ret = parent->getChild(branch);
|
||||||
if (!ret && backed_)
|
if (!ret && backed_)
|
||||||
ret = fetchNode(parent->getChildHash(branch));
|
ret = fetchNode(parent->getChildHash(branch));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<SHAMapAbstractNode*, SHAMapNodeID>
|
std::pair<SHAMapTreeNode*, SHAMapNodeID>
|
||||||
SHAMap::descend(
|
SHAMap::descend(
|
||||||
SHAMapInnerNode* parent,
|
SHAMapInnerNode* parent,
|
||||||
SHAMapNodeID const& parentID,
|
SHAMapNodeID const& parentID,
|
||||||
@@ -338,12 +351,12 @@ SHAMap::descend(
|
|||||||
assert((branch >= 0) && (branch < branchFactor));
|
assert((branch >= 0) && (branch < branchFactor));
|
||||||
assert(!parent->isEmptyBranch(branch));
|
assert(!parent->isEmptyBranch(branch));
|
||||||
|
|
||||||
SHAMapAbstractNode* child = parent->getChildPointer(branch);
|
SHAMapTreeNode* child = parent->getChildPointer(branch);
|
||||||
|
|
||||||
if (!child)
|
if (!child)
|
||||||
{
|
{
|
||||||
auto const& childHash = parent->getChildHash(branch);
|
auto const& childHash = parent->getChildHash(branch);
|
||||||
std::shared_ptr<SHAMapAbstractNode> childNode =
|
std::shared_ptr<SHAMapTreeNode> childNode =
|
||||||
fetchNodeNT(childHash, filter);
|
fetchNodeNT(childHash, filter);
|
||||||
|
|
||||||
if (childNode)
|
if (childNode)
|
||||||
@@ -356,7 +369,7 @@ SHAMap::descend(
|
|||||||
return std::make_pair(child, parentID.getChildNodeID(branch));
|
return std::make_pair(child, parentID.getChildNodeID(branch));
|
||||||
}
|
}
|
||||||
|
|
||||||
SHAMapAbstractNode*
|
SHAMapTreeNode*
|
||||||
SHAMap::descendAsync(
|
SHAMap::descendAsync(
|
||||||
SHAMapInnerNode* parent,
|
SHAMapInnerNode* parent,
|
||||||
int branch,
|
int branch,
|
||||||
@@ -365,13 +378,13 @@ SHAMap::descendAsync(
|
|||||||
{
|
{
|
||||||
pending = false;
|
pending = false;
|
||||||
|
|
||||||
SHAMapAbstractNode* ret = parent->getChildPointer(branch);
|
SHAMapTreeNode* ret = parent->getChildPointer(branch);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
auto const& hash = parent->getChildHash(branch);
|
auto const& hash = parent->getChildHash(branch);
|
||||||
|
|
||||||
std::shared_ptr<SHAMapAbstractNode> ptr = getCache(hash);
|
auto ptr = cacheLookup(hash);
|
||||||
if (!ptr)
|
if (!ptr)
|
||||||
{
|
{
|
||||||
if (filter)
|
if (filter)
|
||||||
@@ -388,8 +401,8 @@ SHAMap::descendAsync(
|
|||||||
if (!obj)
|
if (!obj)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
ptr = SHAMapAbstractNode::makeFromPrefix(
|
ptr =
|
||||||
makeSlice(obj->getData()), hash);
|
SHAMapTreeNode::makeFromPrefix(makeSlice(obj->getData()), hash);
|
||||||
if (ptr && backed_)
|
if (ptr && backed_)
|
||||||
canonicalize(hash, ptr);
|
canonicalize(hash, ptr);
|
||||||
}
|
}
|
||||||
@@ -406,28 +419,28 @@ std::shared_ptr<Node>
|
|||||||
SHAMap::unshareNode(std::shared_ptr<Node> node, SHAMapNodeID const& nodeID)
|
SHAMap::unshareNode(std::shared_ptr<Node> node, SHAMapNodeID const& nodeID)
|
||||||
{
|
{
|
||||||
// make sure the node is suitable for the intended operation (copy on write)
|
// make sure the node is suitable for the intended operation (copy on write)
|
||||||
assert(node->getSeq() <= seq_);
|
assert(node->cowid() <= cowid_);
|
||||||
if (node->getSeq() != seq_)
|
if (node->cowid() != cowid_)
|
||||||
{
|
{
|
||||||
// have a CoW
|
// have a CoW
|
||||||
assert(state_ != SHAMapState::Immutable);
|
assert(state_ != SHAMapState::Immutable);
|
||||||
node = std::static_pointer_cast<Node>(node->clone(seq_));
|
node = std::static_pointer_cast<Node>(node->clone(cowid_));
|
||||||
if (nodeID.isRoot())
|
if (nodeID.isRoot())
|
||||||
root_ = node;
|
root_ = node;
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
SHAMapTreeNode*
|
SHAMapLeafNode*
|
||||||
SHAMap::firstBelow(
|
SHAMap::firstBelow(
|
||||||
std::shared_ptr<SHAMapAbstractNode> node,
|
std::shared_ptr<SHAMapTreeNode> node,
|
||||||
SharedPtrNodeStack& stack,
|
SharedPtrNodeStack& stack,
|
||||||
int branch) const
|
int branch) const
|
||||||
{
|
{
|
||||||
// Return the first item at or below this node
|
// Return the first item at or below this node
|
||||||
if (node->isLeaf())
|
if (node->isLeaf())
|
||||||
{
|
{
|
||||||
auto n = std::static_pointer_cast<SHAMapTreeNode>(node);
|
auto n = std::static_pointer_cast<SHAMapLeafNode>(node);
|
||||||
stack.push({node, {leafDepth, n->peekItem()->key()}});
|
stack.push({node, {leafDepth, n->peekItem()->key()}});
|
||||||
return n.get();
|
return n.get();
|
||||||
}
|
}
|
||||||
@@ -444,7 +457,7 @@ SHAMap::firstBelow(
|
|||||||
assert(!stack.empty());
|
assert(!stack.empty());
|
||||||
if (node->isLeaf())
|
if (node->isLeaf())
|
||||||
{
|
{
|
||||||
auto n = std::static_pointer_cast<SHAMapTreeNode>(node);
|
auto n = std::static_pointer_cast<SHAMapLeafNode>(node);
|
||||||
stack.push({n, {leafDepth, n->peekItem()->key()}});
|
stack.push({n, {leafDepth, n->peekItem()->key()}});
|
||||||
return n.get();
|
return n.get();
|
||||||
}
|
}
|
||||||
@@ -461,13 +474,13 @@ SHAMap::firstBelow(
|
|||||||
static const std::shared_ptr<SHAMapItem const> no_item;
|
static const std::shared_ptr<SHAMapItem const> no_item;
|
||||||
|
|
||||||
std::shared_ptr<SHAMapItem const> const&
|
std::shared_ptr<SHAMapItem const> const&
|
||||||
SHAMap::onlyBelow(SHAMapAbstractNode* node) const
|
SHAMap::onlyBelow(SHAMapTreeNode* node) const
|
||||||
{
|
{
|
||||||
// If there is only one item below this node, return it
|
// If there is only one item below this node, return it
|
||||||
|
|
||||||
while (!node->isLeaf())
|
while (!node->isLeaf())
|
||||||
{
|
{
|
||||||
SHAMapAbstractNode* nextNode = nullptr;
|
SHAMapTreeNode* nextNode = nullptr;
|
||||||
auto inner = static_cast<SHAMapInnerNode*>(node);
|
auto inner = static_cast<SHAMapInnerNode*>(node);
|
||||||
for (int i = 0; i < branchFactor; ++i)
|
for (int i = 0; i < branchFactor; ++i)
|
||||||
{
|
{
|
||||||
@@ -491,17 +504,16 @@ SHAMap::onlyBelow(SHAMapAbstractNode* node) const
|
|||||||
|
|
||||||
// An inner node must have at least one leaf
|
// An inner node must have at least one leaf
|
||||||
// below it, unless it's the root_
|
// below it, unless it's the root_
|
||||||
auto leaf = static_cast<SHAMapTreeNode*>(node);
|
auto const leaf = static_cast<SHAMapLeafNode const*>(node);
|
||||||
assert(leaf->hasItem() || (leaf == root_.get()));
|
assert(leaf->peekItem() || (leaf == root_.get()));
|
||||||
|
|
||||||
return leaf->peekItem();
|
return leaf->peekItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
SHAMapTreeNode const*
|
SHAMapLeafNode const*
|
||||||
SHAMap::peekFirstItem(SharedPtrNodeStack& stack) const
|
SHAMap::peekFirstItem(SharedPtrNodeStack& stack) const
|
||||||
{
|
{
|
||||||
assert(stack.empty());
|
assert(stack.empty());
|
||||||
SHAMapTreeNode* node = firstBelow(root_, stack);
|
SHAMapLeafNode* node = firstBelow(root_, stack);
|
||||||
if (!node)
|
if (!node)
|
||||||
{
|
{
|
||||||
while (!stack.empty())
|
while (!stack.empty())
|
||||||
@@ -511,7 +523,7 @@ SHAMap::peekFirstItem(SharedPtrNodeStack& stack) const
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
SHAMapTreeNode const*
|
SHAMapLeafNode const*
|
||||||
SHAMap::peekNextItem(uint256 const& id, SharedPtrNodeStack& stack) const
|
SHAMap::peekNextItem(uint256 const& id, SharedPtrNodeStack& stack) const
|
||||||
{
|
{
|
||||||
assert(!stack.empty());
|
assert(!stack.empty());
|
||||||
@@ -543,7 +555,7 @@ SHAMap::peekNextItem(uint256 const& id, SharedPtrNodeStack& stack) const
|
|||||||
std::shared_ptr<SHAMapItem const> const&
|
std::shared_ptr<SHAMapItem const> const&
|
||||||
SHAMap::peekItem(uint256 const& id) const
|
SHAMap::peekItem(uint256 const& id) const
|
||||||
{
|
{
|
||||||
SHAMapTreeNode* leaf = findKey(id);
|
SHAMapLeafNode* leaf = findKey(id);
|
||||||
|
|
||||||
if (!leaf)
|
if (!leaf)
|
||||||
return no_item;
|
return no_item;
|
||||||
@@ -551,27 +563,15 @@ SHAMap::peekItem(uint256 const& id) const
|
|||||||
return leaf->peekItem();
|
return leaf->peekItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<SHAMapItem const> const&
|
|
||||||
SHAMap::peekItem(uint256 const& id, SHAMapTreeNode::TNType& type) const
|
|
||||||
{
|
|
||||||
SHAMapTreeNode* leaf = findKey(id);
|
|
||||||
|
|
||||||
if (!leaf)
|
|
||||||
return no_item;
|
|
||||||
|
|
||||||
type = leaf->getType();
|
|
||||||
return leaf->peekItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<SHAMapItem const> const&
|
std::shared_ptr<SHAMapItem const> const&
|
||||||
SHAMap::peekItem(uint256 const& id, SHAMapHash& hash) const
|
SHAMap::peekItem(uint256 const& id, SHAMapHash& hash) const
|
||||||
{
|
{
|
||||||
SHAMapTreeNode* leaf = findKey(id);
|
SHAMapLeafNode* leaf = findKey(id);
|
||||||
|
|
||||||
if (!leaf)
|
if (!leaf)
|
||||||
return no_item;
|
return no_item;
|
||||||
|
|
||||||
hash = leaf->getNodeHash();
|
hash = leaf->getHash();
|
||||||
return leaf->peekItem();
|
return leaf->peekItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -587,7 +587,7 @@ SHAMap::upper_bound(uint256 const& id) const
|
|||||||
auto [node, nodeID] = stack.top();
|
auto [node, nodeID] = stack.top();
|
||||||
if (node->isLeaf())
|
if (node->isLeaf())
|
||||||
{
|
{
|
||||||
auto leaf = static_cast<SHAMapTreeNode*>(node.get());
|
auto leaf = static_cast<SHAMapLeafNode*>(node.get());
|
||||||
if (leaf->peekItem()->key() > id)
|
if (leaf->peekItem()->key() > id)
|
||||||
return const_iterator(
|
return const_iterator(
|
||||||
this, leaf->peekItem().get(), std::move(stack));
|
this, leaf->peekItem().get(), std::move(stack));
|
||||||
@@ -618,9 +618,7 @@ SHAMap::upper_bound(uint256 const& id) const
|
|||||||
bool
|
bool
|
||||||
SHAMap::hasItem(uint256 const& id) const
|
SHAMap::hasItem(uint256 const& id) const
|
||||||
{
|
{
|
||||||
// does the tree have an item with this ID
|
return (findKey(id) != nullptr);
|
||||||
SHAMapTreeNode* leaf = findKey(id);
|
|
||||||
return (leaf != nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -635,17 +633,17 @@ SHAMap::delItem(uint256 const& id)
|
|||||||
if (stack.empty())
|
if (stack.empty())
|
||||||
Throw<SHAMapMissingNode>(type_, id);
|
Throw<SHAMapMissingNode>(type_, id);
|
||||||
|
|
||||||
auto leaf = std::dynamic_pointer_cast<SHAMapTreeNode>(stack.top().first);
|
auto leaf = std::dynamic_pointer_cast<SHAMapLeafNode>(stack.top().first);
|
||||||
stack.pop();
|
stack.pop();
|
||||||
|
|
||||||
if (!leaf || (leaf->peekItem()->key() != id))
|
if (!leaf || (leaf->peekItem()->key() != id))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
SHAMapTreeNode::TNType type = leaf->getType();
|
SHAMapNodeType type = leaf->getType();
|
||||||
|
|
||||||
// What gets attached to the end of the chain
|
// What gets attached to the end of the chain
|
||||||
// (For now, nothing, since we deleted the leaf)
|
// (For now, nothing, since we deleted the leaf)
|
||||||
std::shared_ptr<SHAMapAbstractNode> prevNode;
|
std::shared_ptr<SHAMapTreeNode> prevNode;
|
||||||
|
|
||||||
while (!stack.empty())
|
while (!stack.empty())
|
||||||
{
|
{
|
||||||
@@ -682,8 +680,8 @@ SHAMap::delItem(uint256 const& id)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
prevNode = std::make_shared<SHAMapTreeNode>(
|
|
||||||
item, type, node->getSeq());
|
prevNode = makeTypedLeaf(type, item, node->cowid());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -702,19 +700,13 @@ SHAMap::delItem(uint256 const& id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SHAMap::addGiveItem(
|
SHAMap::addGiveItem(SHAMapNodeType type, std::shared_ptr<SHAMapItem const> item)
|
||||||
std::shared_ptr<SHAMapItem const> item,
|
|
||||||
bool isTransaction,
|
|
||||||
bool hasMeta)
|
|
||||||
{
|
{
|
||||||
|
assert(state_ != SHAMapState::Immutable);
|
||||||
|
assert(type != SHAMapNodeType::tnINNER);
|
||||||
|
|
||||||
// add the specified item, does not update
|
// add the specified item, does not update
|
||||||
uint256 tag = item->key();
|
uint256 tag = item->key();
|
||||||
SHAMapTreeNode::TNType type = !isTransaction
|
|
||||||
? SHAMapTreeNode::tnACCOUNT_STATE
|
|
||||||
: (hasMeta ? SHAMapTreeNode::tnTRANSACTION_MD
|
|
||||||
: SHAMapTreeNode::tnTRANSACTION_NM);
|
|
||||||
|
|
||||||
assert(state_ != SHAMapState::Immutable);
|
|
||||||
|
|
||||||
SharedPtrNodeStack stack;
|
SharedPtrNodeStack stack;
|
||||||
walkTowardsKey(tag, &stack);
|
walkTowardsKey(tag, &stack);
|
||||||
@@ -727,7 +719,7 @@ SHAMap::addGiveItem(
|
|||||||
|
|
||||||
if (node->isLeaf())
|
if (node->isLeaf())
|
||||||
{
|
{
|
||||||
auto leaf = std::static_pointer_cast<SHAMapTreeNode>(node);
|
auto leaf = std::static_pointer_cast<SHAMapLeafNode>(node);
|
||||||
if (leaf->peekItem()->key() == tag)
|
if (leaf->peekItem()->key() == tag)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -738,21 +730,20 @@ SHAMap::addGiveItem(
|
|||||||
auto inner = std::static_pointer_cast<SHAMapInnerNode>(node);
|
auto inner = std::static_pointer_cast<SHAMapInnerNode>(node);
|
||||||
int branch = selectBranch(nodeID, tag);
|
int branch = selectBranch(nodeID, tag);
|
||||||
assert(inner->isEmptyBranch(branch));
|
assert(inner->isEmptyBranch(branch));
|
||||||
auto newNode =
|
auto newNode = makeTypedLeaf(type, std::move(item), cowid_);
|
||||||
std::make_shared<SHAMapTreeNode>(std::move(item), type, seq_);
|
|
||||||
inner->setChild(branch, newNode);
|
inner->setChild(branch, newNode);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// this is a leaf node that has to be made an inner node holding two
|
// this is a leaf node that has to be made an inner node holding two
|
||||||
// items
|
// items
|
||||||
auto leaf = std::static_pointer_cast<SHAMapTreeNode>(node);
|
auto leaf = std::static_pointer_cast<SHAMapLeafNode>(node);
|
||||||
std::shared_ptr<SHAMapItem const> otherItem = leaf->peekItem();
|
std::shared_ptr<SHAMapItem const> otherItem = leaf->peekItem();
|
||||||
assert(otherItem && (tag != otherItem->key()));
|
assert(otherItem && (tag != otherItem->key()));
|
||||||
|
|
||||||
node = std::make_shared<SHAMapInnerNode>(node->getSeq());
|
node = std::make_shared<SHAMapInnerNode>(node->cowid());
|
||||||
|
|
||||||
int b1, b2;
|
unsigned int b1, b2;
|
||||||
|
|
||||||
while ((b1 = selectBranch(nodeID, tag)) ==
|
while ((b1 = selectBranch(nodeID, tag)) ==
|
||||||
(b2 = selectBranch(nodeID, otherItem->key())))
|
(b2 = selectBranch(nodeID, otherItem->key())))
|
||||||
@@ -762,22 +753,15 @@ SHAMap::addGiveItem(
|
|||||||
// we need a new inner node, since both go on same branch at this
|
// we need a new inner node, since both go on same branch at this
|
||||||
// level
|
// level
|
||||||
nodeID = nodeID.getChildNodeID(b1);
|
nodeID = nodeID.getChildNodeID(b1);
|
||||||
node = std::make_shared<SHAMapInnerNode>(seq_);
|
node = std::make_shared<SHAMapInnerNode>(cowid_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// we can add the two leaf nodes here
|
// we can add the two leaf nodes here
|
||||||
assert(node->isInner());
|
assert(node->isInner());
|
||||||
|
|
||||||
std::shared_ptr<SHAMapTreeNode> newNode =
|
auto inner = static_cast<SHAMapInnerNode*>(node.get());
|
||||||
std::make_shared<SHAMapTreeNode>(std::move(item), type, seq_);
|
inner->setChild(b1, makeTypedLeaf(type, std::move(item), cowid_));
|
||||||
assert(newNode->isLeaf());
|
inner->setChild(b2, makeTypedLeaf(type, std::move(otherItem), cowid_));
|
||||||
auto inner = std::static_pointer_cast<SHAMapInnerNode>(node);
|
|
||||||
inner->setChild(b1, newNode);
|
|
||||||
|
|
||||||
newNode =
|
|
||||||
std::make_shared<SHAMapTreeNode>(std::move(otherItem), type, seq_);
|
|
||||||
assert(newNode->isLeaf());
|
|
||||||
inner->setChild(b2, newNode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dirtyUp(stack, tag, node);
|
dirtyUp(stack, tag, node);
|
||||||
@@ -785,31 +769,27 @@ SHAMap::addGiveItem(
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SHAMap::addItem(SHAMapItem&& i, bool isTransaction, bool hasMetaData)
|
SHAMap::addItem(SHAMapNodeType type, SHAMapItem&& i)
|
||||||
{
|
{
|
||||||
return addGiveItem(
|
return addGiveItem(type, std::make_shared<SHAMapItem const>(std::move(i)));
|
||||||
std::make_shared<SHAMapItem const>(std::move(i)),
|
|
||||||
isTransaction,
|
|
||||||
hasMetaData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SHAMapHash
|
SHAMapHash
|
||||||
SHAMap::getHash() const
|
SHAMap::getHash() const
|
||||||
{
|
{
|
||||||
auto hash = root_->getNodeHash();
|
auto hash = root_->getHash();
|
||||||
if (hash.isZero())
|
if (hash.isZero())
|
||||||
{
|
{
|
||||||
const_cast<SHAMap&>(*this).unshare();
|
const_cast<SHAMap&>(*this).unshare();
|
||||||
hash = root_->getNodeHash();
|
hash = root_->getHash();
|
||||||
}
|
}
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SHAMap::updateGiveItem(
|
SHAMap::updateGiveItem(
|
||||||
std::shared_ptr<SHAMapItem const> item,
|
SHAMapNodeType type,
|
||||||
bool isTransaction,
|
std::shared_ptr<SHAMapItem const> item)
|
||||||
bool hasMeta)
|
|
||||||
{
|
{
|
||||||
// can't change the tag but can change the hash
|
// can't change the tag but can change the hash
|
||||||
uint256 tag = item->key();
|
uint256 tag = item->key();
|
||||||
@@ -822,7 +802,7 @@ SHAMap::updateGiveItem(
|
|||||||
if (stack.empty())
|
if (stack.empty())
|
||||||
Throw<SHAMapMissingNode>(type_, tag);
|
Throw<SHAMapMissingNode>(type_, tag);
|
||||||
|
|
||||||
auto node = std::dynamic_pointer_cast<SHAMapTreeNode>(stack.top().first);
|
auto node = std::dynamic_pointer_cast<SHAMapLeafNode>(stack.top().first);
|
||||||
auto nodeID = stack.top().second;
|
auto nodeID = stack.top().second;
|
||||||
stack.pop();
|
stack.pop();
|
||||||
|
|
||||||
@@ -832,26 +812,24 @@ SHAMap::updateGiveItem(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
node = unshareNode(std::move(node), nodeID);
|
if (node->getType() != type)
|
||||||
|
|
||||||
if (!node->setItem(
|
|
||||||
std::move(item),
|
|
||||||
!isTransaction ? SHAMapTreeNode::tnACCOUNT_STATE
|
|
||||||
: (hasMeta ? SHAMapTreeNode::tnTRANSACTION_MD
|
|
||||||
: SHAMapTreeNode::tnTRANSACTION_NM)))
|
|
||||||
{
|
{
|
||||||
JLOG(journal_.trace()) << "SHAMap setItem, no change";
|
JLOG(journal_.fatal()) << "SHAMap::setItem: cross-type change!";
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
dirtyUp(stack, tag, node);
|
node = unshareNode(std::move(node), nodeID);
|
||||||
|
|
||||||
|
if (node->setItem(std::move(item)))
|
||||||
|
dirtyUp(stack, tag, node);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SHAMap::fetchRoot(SHAMapHash const& hash, SHAMapSyncFilter* filter)
|
SHAMap::fetchRoot(SHAMapHash const& hash, SHAMapSyncFilter* filter)
|
||||||
{
|
{
|
||||||
if (hash == root_->getNodeHash())
|
if (hash == root_->getHash())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (auto stream = journal_.trace())
|
if (auto stream = journal_.trace())
|
||||||
@@ -875,42 +853,37 @@ SHAMap::fetchRoot(SHAMapHash const& hash, SHAMapSyncFilter* filter)
|
|||||||
if (newRoot)
|
if (newRoot)
|
||||||
{
|
{
|
||||||
root_ = newRoot;
|
root_ = newRoot;
|
||||||
assert(root_->getNodeHash() == hash);
|
assert(root_->getHash() == hash);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace a node with a shareable node.
|
/** Replace a node with a shareable node.
|
||||||
//
|
|
||||||
// This code handles two cases:
|
|
||||||
//
|
|
||||||
// 1) An unshared, unshareable node needs to be made shareable
|
|
||||||
// so immutable SHAMap's can have references to it.
|
|
||||||
//
|
|
||||||
// 2) An unshareable node is shared. This happens when you make
|
|
||||||
// a mutable snapshot of a mutable SHAMap.
|
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
|
||||||
SHAMap::writeNode(
|
|
||||||
NodeObjectType t,
|
|
||||||
std::uint32_t seq,
|
|
||||||
std::shared_ptr<SHAMapAbstractNode> node) const
|
|
||||||
{
|
|
||||||
// Node is ours, so we can just make it shareable
|
|
||||||
assert(node->getSeq() == seq_);
|
|
||||||
assert(backed_);
|
|
||||||
node->setSeq(0);
|
|
||||||
|
|
||||||
canonicalize(node->getNodeHash(), node);
|
This code handles two cases:
|
||||||
|
|
||||||
|
1) An unshared, unshareable node needs to be made shareable
|
||||||
|
so immutable SHAMap's can have references to it.
|
||||||
|
2) An unshareable node is shared. This happens when you make
|
||||||
|
a mutable snapshot of a mutable SHAMap.
|
||||||
|
|
||||||
|
@note The node must have already been unshared by having the caller
|
||||||
|
first call SHAMapTreeNode::unshare().
|
||||||
|
*/
|
||||||
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
|
SHAMap::writeNode(NodeObjectType t, std::shared_ptr<SHAMapTreeNode> node) const
|
||||||
|
{
|
||||||
|
assert(node->cowid() == 0);
|
||||||
|
assert(backed_);
|
||||||
|
|
||||||
|
canonicalize(node->getHash(), node);
|
||||||
|
|
||||||
Serializer s;
|
Serializer s;
|
||||||
node->serializeWithPrefix(s);
|
node->serializeWithPrefix(s);
|
||||||
f_.db().store(
|
f_.db().store(
|
||||||
t,
|
t, std::move(s.modData()), node->getHash().as_uint256(), ledgerSeq_);
|
||||||
std::move(s.modData()),
|
|
||||||
node->getNodeHash().as_uint256(),
|
|
||||||
ledgerSeq_);
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -923,13 +896,13 @@ SHAMap::preFlushNode(std::shared_ptr<Node> node) const
|
|||||||
{
|
{
|
||||||
// A shared node should never need to be flushed
|
// A shared node should never need to be flushed
|
||||||
// because that would imply someone modified it
|
// because that would imply someone modified it
|
||||||
assert(node->getSeq() != 0);
|
assert(node->cowid() != 0);
|
||||||
|
|
||||||
if (node->getSeq() != seq_)
|
if (node->cowid() != cowid_)
|
||||||
{
|
{
|
||||||
// Node is not uniquely ours, so unshare it before
|
// Node is not uniquely ours, so unshare it before
|
||||||
// possibly modifying it
|
// possibly modifying it
|
||||||
node = std::static_pointer_cast<Node>(node->clone(seq_));
|
node = std::static_pointer_cast<Node>(node->clone(cowid_));
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
@@ -937,35 +910,36 @@ SHAMap::preFlushNode(std::shared_ptr<Node> node) const
|
|||||||
int
|
int
|
||||||
SHAMap::unshare()
|
SHAMap::unshare()
|
||||||
{
|
{
|
||||||
// Don't share nodes wth parent map
|
// Don't share nodes with parent map
|
||||||
return walkSubTree(false, hotUNKNOWN, 0);
|
return walkSubTree(false, hotUNKNOWN);
|
||||||
}
|
|
||||||
|
|
||||||
/** Convert all modified nodes to shared nodes */
|
|
||||||
// If requested, write them to the node store
|
|
||||||
int
|
|
||||||
SHAMap::flushDirty(NodeObjectType t, std::uint32_t seq)
|
|
||||||
{
|
|
||||||
return walkSubTree(true, t, seq);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
SHAMap::walkSubTree(bool doWrite, NodeObjectType t, std::uint32_t seq)
|
SHAMap::flushDirty(NodeObjectType t)
|
||||||
{
|
{
|
||||||
|
// We only write back if this map is backed.
|
||||||
|
return walkSubTree(backed_, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
SHAMap::walkSubTree(bool doWrite, NodeObjectType t)
|
||||||
|
{
|
||||||
|
assert(!doWrite || backed_);
|
||||||
|
|
||||||
int flushed = 0;
|
int flushed = 0;
|
||||||
Serializer s;
|
|
||||||
|
|
||||||
if (!root_ || (root_->getSeq() == 0))
|
if (!root_ || (root_->cowid() == 0))
|
||||||
return flushed;
|
return flushed;
|
||||||
|
|
||||||
if (root_->isLeaf())
|
if (root_->isLeaf())
|
||||||
{ // special case -- root_ is leaf
|
{ // special case -- root_ is leaf
|
||||||
root_ = preFlushNode(std::move(root_));
|
root_ = preFlushNode(std::move(root_));
|
||||||
root_->updateHash();
|
root_->updateHash();
|
||||||
if (doWrite && backed_)
|
root_->unshare();
|
||||||
root_ = writeNode(t, seq, std::move(root_));
|
|
||||||
else
|
if (doWrite)
|
||||||
root_->setSeq(0);
|
root_ = writeNode(t, std::move(root_));
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1002,7 +976,7 @@ SHAMap::walkSubTree(bool doWrite, NodeObjectType t, std::uint32_t seq)
|
|||||||
int branch = pos;
|
int branch = pos;
|
||||||
auto child = node->getChild(pos++);
|
auto child = node->getChild(pos++);
|
||||||
|
|
||||||
if (child && (child->getSeq() != 0))
|
if (child && (child->cowid() != 0))
|
||||||
{
|
{
|
||||||
// This is a node that needs to be flushed
|
// This is a node that needs to be flushed
|
||||||
|
|
||||||
@@ -1025,13 +999,12 @@ SHAMap::walkSubTree(bool doWrite, NodeObjectType t, std::uint32_t seq)
|
|||||||
// flush this leaf
|
// flush this leaf
|
||||||
++flushed;
|
++flushed;
|
||||||
|
|
||||||
assert(node->getSeq() == seq_);
|
assert(node->cowid() == cowid_);
|
||||||
child->updateHash();
|
child->updateHash();
|
||||||
|
child->unshare();
|
||||||
|
|
||||||
if (doWrite && backed_)
|
if (doWrite)
|
||||||
child = writeNode(t, seq, std::move(child));
|
child = writeNode(t, std::move(child));
|
||||||
else
|
|
||||||
child->setSeq(0);
|
|
||||||
|
|
||||||
node->shareChild(branch, child);
|
node->shareChild(branch, child);
|
||||||
}
|
}
|
||||||
@@ -1043,11 +1016,11 @@ SHAMap::walkSubTree(bool doWrite, NodeObjectType t, std::uint32_t seq)
|
|||||||
node->updateHashDeep();
|
node->updateHashDeep();
|
||||||
|
|
||||||
// This inner node can now be shared
|
// This inner node can now be shared
|
||||||
if (doWrite && backed_)
|
node->unshare();
|
||||||
|
|
||||||
|
if (doWrite)
|
||||||
node = std::static_pointer_cast<SHAMapInnerNode>(
|
node = std::static_pointer_cast<SHAMapInnerNode>(
|
||||||
writeNode(t, seq, std::move(node)));
|
writeNode(t, std::move(node)));
|
||||||
else
|
|
||||||
node->setSeq(0);
|
|
||||||
|
|
||||||
++flushed;
|
++flushed;
|
||||||
|
|
||||||
@@ -1059,7 +1032,7 @@ SHAMap::walkSubTree(bool doWrite, NodeObjectType t, std::uint32_t seq)
|
|||||||
stack.pop();
|
stack.pop();
|
||||||
|
|
||||||
// Hook this inner node to its parent
|
// Hook this inner node to its parent
|
||||||
assert(parent->getSeq() == seq_);
|
assert(parent->cowid() == cowid_);
|
||||||
parent->shareChild(pos, node);
|
parent->shareChild(pos, node);
|
||||||
|
|
||||||
// Continue with parent's next child, if any
|
// Continue with parent's next child, if any
|
||||||
@@ -1079,7 +1052,7 @@ SHAMap::dump(bool hash) const
|
|||||||
int leafCount = 0;
|
int leafCount = 0;
|
||||||
JLOG(journal_.info()) << " MAP Contains";
|
JLOG(journal_.info()) << " MAP Contains";
|
||||||
|
|
||||||
std::stack<std::pair<SHAMapAbstractNode*, SHAMapNodeID>> stack;
|
std::stack<std::pair<SHAMapTreeNode*, SHAMapNodeID>> stack;
|
||||||
stack.push({root_.get(), SHAMapNodeID()});
|
stack.push({root_.get(), SHAMapNodeID()});
|
||||||
|
|
||||||
do
|
do
|
||||||
@@ -1090,7 +1063,7 @@ SHAMap::dump(bool hash) const
|
|||||||
JLOG(journal_.info()) << node->getString(nodeID);
|
JLOG(journal_.info()) << node->getString(nodeID);
|
||||||
if (hash)
|
if (hash)
|
||||||
{
|
{
|
||||||
JLOG(journal_.info()) << "Hash: " << node->getNodeHash();
|
JLOG(journal_.info()) << "Hash: " << node->getHash();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->isInner())
|
if (node->isInner())
|
||||||
@@ -1103,7 +1076,7 @@ SHAMap::dump(bool hash) const
|
|||||||
auto child = inner->getChildPointer(i);
|
auto child = inner->getChildPointer(i);
|
||||||
if (child)
|
if (child)
|
||||||
{
|
{
|
||||||
assert(child->getNodeHash() == inner->getChildHash(i));
|
assert(child->getHash() == inner->getChildHash(i));
|
||||||
stack.push({child, nodeID.getChildNodeID(i)});
|
stack.push({child, nodeID.getChildNodeID(i)});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1116,22 +1089,22 @@ SHAMap::dump(bool hash) const
|
|||||||
JLOG(journal_.info()) << leafCount << " resident leaves";
|
JLOG(journal_.info()) << leafCount << " resident leaves";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
SHAMap::getCache(SHAMapHash const& hash) const
|
SHAMap::cacheLookup(SHAMapHash const& hash) const
|
||||||
{
|
{
|
||||||
auto ret = f_.getTreeNodeCache(ledgerSeq_)->fetch(hash.as_uint256());
|
auto ret = f_.getTreeNodeCache(ledgerSeq_)->fetch(hash.as_uint256());
|
||||||
assert(!ret || !ret->getSeq());
|
assert(!ret || !ret->cowid());
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SHAMap::canonicalize(
|
SHAMap::canonicalize(
|
||||||
SHAMapHash const& hash,
|
SHAMapHash const& hash,
|
||||||
std::shared_ptr<SHAMapAbstractNode>& node) const
|
std::shared_ptr<SHAMapTreeNode>& node) const
|
||||||
{
|
{
|
||||||
assert(backed_);
|
assert(backed_);
|
||||||
assert(node->getSeq() == 0);
|
assert(node->cowid() == 0);
|
||||||
assert(node->getNodeHash() == hash);
|
assert(node->getHash() == hash);
|
||||||
|
|
||||||
f_.getTreeNodeCache(ledgerSeq_)
|
f_.getTreeNodeCache(ledgerSeq_)
|
||||||
->canonicalize_replace_client(hash.as_uint256(), node);
|
->canonicalize_replace_client(hash.as_uint256(), node);
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ namespace ripple {
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
SHAMap::walkBranch(
|
SHAMap::walkBranch(
|
||||||
SHAMapAbstractNode* node,
|
SHAMapTreeNode* node,
|
||||||
std::shared_ptr<SHAMapItem const> const& otherMapItem,
|
std::shared_ptr<SHAMapItem const> const& otherMapItem,
|
||||||
bool isFirstMap,
|
bool isFirstMap,
|
||||||
Delta& differences,
|
Delta& differences,
|
||||||
@@ -40,7 +40,7 @@ SHAMap::walkBranch(
|
|||||||
{
|
{
|
||||||
// Walk a branch of a SHAMap that's matched by an empty branch or single
|
// Walk a branch of a SHAMap that's matched by an empty branch or single
|
||||||
// item in the other map
|
// item in the other map
|
||||||
std::stack<SHAMapAbstractNode*, std::vector<SHAMapAbstractNode*>> nodeStack;
|
std::stack<SHAMapTreeNode*, std::vector<SHAMapTreeNode*>> nodeStack;
|
||||||
nodeStack.push(node);
|
nodeStack.push(node);
|
||||||
|
|
||||||
bool emptyBranch = !otherMapItem;
|
bool emptyBranch = !otherMapItem;
|
||||||
@@ -61,7 +61,7 @@ SHAMap::walkBranch(
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// This is a leaf node, process its item
|
// This is a leaf node, process its item
|
||||||
auto item = static_cast<SHAMapTreeNode*>(node)->peekItem();
|
auto item = static_cast<SHAMapLeafNode*>(node)->peekItem();
|
||||||
|
|
||||||
if (emptyBranch || (item->key() != otherMapItem->key()))
|
if (emptyBranch || (item->key() != otherMapItem->key()))
|
||||||
{
|
{
|
||||||
@@ -133,7 +133,7 @@ SHAMap::compare(SHAMap const& otherMap, Delta& differences, int maxCount) const
|
|||||||
if (getHash() == otherMap.getHash())
|
if (getHash() == otherMap.getHash())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
using StackEntry = std::pair<SHAMapAbstractNode*, SHAMapAbstractNode*>;
|
using StackEntry = std::pair<SHAMapTreeNode*, SHAMapTreeNode*>;
|
||||||
std::stack<StackEntry, std::vector<StackEntry>>
|
std::stack<StackEntry, std::vector<StackEntry>>
|
||||||
nodeStack; // track nodes we've pushed
|
nodeStack; // track nodes we've pushed
|
||||||
|
|
||||||
@@ -152,8 +152,8 @@ SHAMap::compare(SHAMap const& otherMap, Delta& differences, int maxCount) const
|
|||||||
if (ourNode->isLeaf() && otherNode->isLeaf())
|
if (ourNode->isLeaf() && otherNode->isLeaf())
|
||||||
{
|
{
|
||||||
// two leaves
|
// two leaves
|
||||||
auto ours = static_cast<SHAMapTreeNode*>(ourNode);
|
auto ours = static_cast<SHAMapLeafNode*>(ourNode);
|
||||||
auto other = static_cast<SHAMapTreeNode*>(otherNode);
|
auto other = static_cast<SHAMapLeafNode*>(otherNode);
|
||||||
if (ours->peekItem()->key() == other->peekItem()->key())
|
if (ours->peekItem()->key() == other->peekItem()->key())
|
||||||
{
|
{
|
||||||
if (ours->peekItem()->peekData() !=
|
if (ours->peekItem()->peekData() !=
|
||||||
@@ -188,14 +188,14 @@ SHAMap::compare(SHAMap const& otherMap, Delta& differences, int maxCount) const
|
|||||||
else if (ourNode->isInner() && otherNode->isLeaf())
|
else if (ourNode->isInner() && otherNode->isLeaf())
|
||||||
{
|
{
|
||||||
auto ours = static_cast<SHAMapInnerNode*>(ourNode);
|
auto ours = static_cast<SHAMapInnerNode*>(ourNode);
|
||||||
auto other = static_cast<SHAMapTreeNode*>(otherNode);
|
auto other = static_cast<SHAMapLeafNode*>(otherNode);
|
||||||
if (!walkBranch(
|
if (!walkBranch(
|
||||||
ours, other->peekItem(), true, differences, maxCount))
|
ours, other->peekItem(), true, differences, maxCount))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (ourNode->isLeaf() && otherNode->isInner())
|
else if (ourNode->isLeaf() && otherNode->isInner())
|
||||||
{
|
{
|
||||||
auto ours = static_cast<SHAMapTreeNode*>(ourNode);
|
auto ours = static_cast<SHAMapLeafNode*>(ourNode);
|
||||||
auto other = static_cast<SHAMapInnerNode*>(otherNode);
|
auto other = static_cast<SHAMapInnerNode*>(otherNode);
|
||||||
if (!otherMap.walkBranch(
|
if (!otherMap.walkBranch(
|
||||||
other, ours->peekItem(), false, differences, maxCount))
|
other, ours->peekItem(), false, differences, maxCount))
|
||||||
@@ -211,7 +211,7 @@ SHAMap::compare(SHAMap const& otherMap, Delta& differences, int maxCount) const
|
|||||||
if (other->isEmptyBranch(i))
|
if (other->isEmptyBranch(i))
|
||||||
{
|
{
|
||||||
// We have a branch, the other tree does not
|
// We have a branch, the other tree does not
|
||||||
SHAMapAbstractNode* iNode = descendThrow(ours, i);
|
SHAMapTreeNode* iNode = descendThrow(ours, i);
|
||||||
if (!walkBranch(
|
if (!walkBranch(
|
||||||
iNode,
|
iNode,
|
||||||
std::shared_ptr<SHAMapItem const>(),
|
std::shared_ptr<SHAMapItem const>(),
|
||||||
@@ -223,8 +223,7 @@ SHAMap::compare(SHAMap const& otherMap, Delta& differences, int maxCount) const
|
|||||||
else if (ours->isEmptyBranch(i))
|
else if (ours->isEmptyBranch(i))
|
||||||
{
|
{
|
||||||
// The other tree has a branch, we do not
|
// The other tree has a branch, we do not
|
||||||
SHAMapAbstractNode* iNode =
|
SHAMapTreeNode* iNode = otherMap.descendThrow(other, i);
|
||||||
otherMap.descendThrow(other, i);
|
|
||||||
if (!otherMap.walkBranch(
|
if (!otherMap.walkBranch(
|
||||||
iNode,
|
iNode,
|
||||||
std::shared_ptr<SHAMapItem const>(),
|
std::shared_ptr<SHAMapItem const>(),
|
||||||
@@ -267,7 +266,7 @@ SHAMap::walkMap(std::vector<SHAMapMissingNode>& missingNodes, int maxMissing)
|
|||||||
{
|
{
|
||||||
if (!node->isEmptyBranch(i))
|
if (!node->isEmptyBranch(i))
|
||||||
{
|
{
|
||||||
std::shared_ptr<SHAMapAbstractNode> nextNode =
|
std::shared_ptr<SHAMapTreeNode> nextNode =
|
||||||
descendNoStore(node, i);
|
descendNoStore(node, i);
|
||||||
|
|
||||||
if (nextNode)
|
if (nextNode)
|
||||||
|
|||||||
313
src/ripple/shamap/impl/SHAMapInnerNode.cpp
Normal file
313
src/ripple/shamap/impl/SHAMapInnerNode.cpp
Normal file
@@ -0,0 +1,313 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#include <ripple/shamap/SHAMapInnerNode.h>
|
||||||
|
|
||||||
|
#include <ripple/basics/ByteUtilities.h>
|
||||||
|
#include <ripple/basics/Log.h>
|
||||||
|
#include <ripple/basics/Slice.h>
|
||||||
|
#include <ripple/basics/contract.h>
|
||||||
|
#include <ripple/basics/safe_cast.h>
|
||||||
|
#include <ripple/beast/core/LexicalCast.h>
|
||||||
|
#include <ripple/protocol/HashPrefix.h>
|
||||||
|
#include <ripple/protocol/digest.h>
|
||||||
|
#include <ripple/shamap/SHAMapTreeNode.h>
|
||||||
|
|
||||||
|
#include <openssl/sha.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
#include <atomic>
|
||||||
|
#include <iterator>
|
||||||
|
#include <mutex>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
std::mutex SHAMapInnerNode::childLock;
|
||||||
|
|
||||||
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
|
SHAMapInnerNode::clone(std::uint32_t cowid) const
|
||||||
|
{
|
||||||
|
auto p = std::make_shared<SHAMapInnerNode>(cowid);
|
||||||
|
p->hash_ = hash_;
|
||||||
|
p->mIsBranch = mIsBranch;
|
||||||
|
p->mFullBelowGen = mFullBelowGen;
|
||||||
|
p->mHashes = mHashes;
|
||||||
|
std::lock_guard lock(childLock);
|
||||||
|
for (int i = 0; i < 16; ++i)
|
||||||
|
p->mChildren[i] = mChildren[i];
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
|
SHAMapInnerNode::makeFullInner(
|
||||||
|
Slice data,
|
||||||
|
SHAMapHash const& hash,
|
||||||
|
bool hashValid)
|
||||||
|
{
|
||||||
|
if (data.size() != 512)
|
||||||
|
Throw<std::runtime_error>("Invalid FI node");
|
||||||
|
|
||||||
|
auto ret = std::make_shared<SHAMapInnerNode>(0);
|
||||||
|
|
||||||
|
Serializer s(data.data(), data.size());
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; ++i)
|
||||||
|
{
|
||||||
|
s.getBitString(ret->mHashes[i].as_uint256(), i * 32);
|
||||||
|
|
||||||
|
if (ret->mHashes[i].isNonZero())
|
||||||
|
ret->mIsBranch |= (1 << i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hashValid)
|
||||||
|
ret->hash_ = hash;
|
||||||
|
else
|
||||||
|
ret->updateHash();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
|
SHAMapInnerNode::makeCompressedInner(Slice data)
|
||||||
|
{
|
||||||
|
Serializer s(data.data(), data.size());
|
||||||
|
|
||||||
|
int len = s.getLength();
|
||||||
|
|
||||||
|
auto ret = std::make_shared<SHAMapInnerNode>(0);
|
||||||
|
|
||||||
|
for (int i = 0; i < (len / 33); ++i)
|
||||||
|
{
|
||||||
|
int pos;
|
||||||
|
|
||||||
|
if (!s.get8(pos, 32 + (i * 33)))
|
||||||
|
Throw<std::runtime_error>("short CI node");
|
||||||
|
|
||||||
|
if ((pos < 0) || (pos >= 16))
|
||||||
|
Throw<std::runtime_error>("invalid CI node");
|
||||||
|
|
||||||
|
s.getBitString(ret->mHashes[pos].as_uint256(), i * 33);
|
||||||
|
|
||||||
|
if (ret->mHashes[pos].isNonZero())
|
||||||
|
ret->mIsBranch |= (1 << pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret->updateHash();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SHAMapInnerNode::updateHash()
|
||||||
|
{
|
||||||
|
uint256 nh;
|
||||||
|
if (mIsBranch != 0)
|
||||||
|
{
|
||||||
|
sha512_half_hasher h;
|
||||||
|
using beast::hash_append;
|
||||||
|
hash_append(h, HashPrefix::innerNode);
|
||||||
|
for (auto const& hh : mHashes)
|
||||||
|
hash_append(h, hh);
|
||||||
|
nh = static_cast<typename sha512_half_hasher::result_type>(h);
|
||||||
|
}
|
||||||
|
hash_ = SHAMapHash{nh};
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SHAMapInnerNode::updateHashDeep()
|
||||||
|
{
|
||||||
|
for (auto pos = 0; pos < 16; ++pos)
|
||||||
|
{
|
||||||
|
if (mChildren[pos] != nullptr)
|
||||||
|
mHashes[pos] = mChildren[pos]->getHash();
|
||||||
|
}
|
||||||
|
updateHash();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SHAMapInnerNode::serializeForWire(Serializer& s) const
|
||||||
|
{
|
||||||
|
assert(!isEmpty());
|
||||||
|
|
||||||
|
// If the node is sparse, then only send non-empty branches:
|
||||||
|
if (getBranchCount() < 12)
|
||||||
|
{
|
||||||
|
// compressed node
|
||||||
|
for (int i = 0; i < mHashes.size(); ++i)
|
||||||
|
{
|
||||||
|
if (!isEmptyBranch(i))
|
||||||
|
{
|
||||||
|
s.addBitString(mHashes[i].as_uint256());
|
||||||
|
s.add8(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s.add8(wireTypeCompressedInner);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (auto const& hh : mHashes)
|
||||||
|
s.addBitString(hh.as_uint256());
|
||||||
|
|
||||||
|
s.add8(wireTypeInner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SHAMapInnerNode::serializeWithPrefix(Serializer& s) const
|
||||||
|
{
|
||||||
|
assert(!isEmpty());
|
||||||
|
|
||||||
|
s.add32(HashPrefix::innerNode);
|
||||||
|
for (auto const& hh : mHashes)
|
||||||
|
s.addBitString(hh.as_uint256());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
SHAMapInnerNode::isEmpty() const
|
||||||
|
{
|
||||||
|
return mIsBranch == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
SHAMapInnerNode::getBranchCount() const
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; ++i)
|
||||||
|
if (!isEmptyBranch(i))
|
||||||
|
++count;
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
SHAMapInnerNode::getString(const SHAMapNodeID& id) const
|
||||||
|
{
|
||||||
|
std::string ret = SHAMapTreeNode::getString(id);
|
||||||
|
for (int i = 0; i < mHashes.size(); ++i)
|
||||||
|
{
|
||||||
|
if (!isEmptyBranch(i))
|
||||||
|
{
|
||||||
|
ret += "\n";
|
||||||
|
ret += std::to_string(i);
|
||||||
|
ret += " = ";
|
||||||
|
ret += to_string(mHashes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are modifying an inner node
|
||||||
|
void
|
||||||
|
SHAMapInnerNode::setChild(int m, std::shared_ptr<SHAMapTreeNode> const& child)
|
||||||
|
{
|
||||||
|
assert((m >= 0) && (m < 16));
|
||||||
|
assert(cowid_ != 0);
|
||||||
|
assert(child.get() != this);
|
||||||
|
mHashes[m].zero();
|
||||||
|
hash_.zero();
|
||||||
|
if (child)
|
||||||
|
mIsBranch |= (1 << m);
|
||||||
|
else
|
||||||
|
mIsBranch &= ~(1 << m);
|
||||||
|
mChildren[m] = child;
|
||||||
|
}
|
||||||
|
|
||||||
|
// finished modifying, now make shareable
|
||||||
|
void
|
||||||
|
SHAMapInnerNode::shareChild(int m, std::shared_ptr<SHAMapTreeNode> const& child)
|
||||||
|
{
|
||||||
|
assert((m >= 0) && (m < 16));
|
||||||
|
assert(cowid_ != 0);
|
||||||
|
assert(child);
|
||||||
|
assert(child.get() != this);
|
||||||
|
|
||||||
|
mChildren[m] = child;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAMapTreeNode*
|
||||||
|
SHAMapInnerNode::getChildPointer(int branch)
|
||||||
|
{
|
||||||
|
assert(branch >= 0 && branch < 16);
|
||||||
|
|
||||||
|
std::lock_guard lock(childLock);
|
||||||
|
return mChildren[branch].get();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
|
SHAMapInnerNode::getChild(int branch)
|
||||||
|
{
|
||||||
|
assert(branch >= 0 && branch < 16);
|
||||||
|
|
||||||
|
std::lock_guard lock(childLock);
|
||||||
|
return mChildren[branch];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
|
SHAMapInnerNode::canonicalizeChild(
|
||||||
|
int branch,
|
||||||
|
std::shared_ptr<SHAMapTreeNode> node)
|
||||||
|
{
|
||||||
|
assert(branch >= 0 && branch < 16);
|
||||||
|
assert(node);
|
||||||
|
assert(node->getHash() == mHashes[branch]);
|
||||||
|
|
||||||
|
std::lock_guard lock(childLock);
|
||||||
|
if (mChildren[branch])
|
||||||
|
{
|
||||||
|
// There is already a node hooked up, return it
|
||||||
|
node = mChildren[branch];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Hook this node up
|
||||||
|
mChildren[branch] = node;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SHAMapInnerNode::invariants(bool is_root) const
|
||||||
|
{
|
||||||
|
unsigned count = 0;
|
||||||
|
for (int i = 0; i < 16; ++i)
|
||||||
|
{
|
||||||
|
if (mHashes[i].isNonZero())
|
||||||
|
{
|
||||||
|
assert((mIsBranch & (1 << i)) != 0);
|
||||||
|
if (mChildren[i] != nullptr)
|
||||||
|
mChildren[i]->invariants();
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert((mIsBranch & (1 << i)) == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!is_root)
|
||||||
|
{
|
||||||
|
assert(hash_.isNonZero());
|
||||||
|
assert(count >= 1);
|
||||||
|
}
|
||||||
|
assert((count == 0) ? hash_.isZero() : hash_.isNonZero());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ripple
|
||||||
94
src/ripple/shamap/impl/SHAMapLeafNode.cpp
Normal file
94
src/ripple/shamap/impl/SHAMapLeafNode.cpp
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#include <ripple/basics/contract.h>
|
||||||
|
#include <ripple/beast/core/LexicalCast.h>
|
||||||
|
#include <ripple/shamap/SHAMapLeafNode.h>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
SHAMapLeafNode::SHAMapLeafNode(
|
||||||
|
std::shared_ptr<SHAMapItem const> item,
|
||||||
|
std::uint32_t cowid)
|
||||||
|
: SHAMapTreeNode(cowid), item_(std::move(item))
|
||||||
|
{
|
||||||
|
assert(item_->peekData().size() >= 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAMapLeafNode::SHAMapLeafNode(
|
||||||
|
std::shared_ptr<SHAMapItem const> item,
|
||||||
|
std::uint32_t cowid,
|
||||||
|
SHAMapHash const& hash)
|
||||||
|
: SHAMapTreeNode(cowid, hash), item_(std::move(item))
|
||||||
|
{
|
||||||
|
assert(item_->peekData().size() >= 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SHAMapItem const> const&
|
||||||
|
SHAMapLeafNode::peekItem() const
|
||||||
|
{
|
||||||
|
return item_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
SHAMapLeafNode::setItem(std::shared_ptr<SHAMapItem const> i)
|
||||||
|
{
|
||||||
|
assert(cowid_ != 0);
|
||||||
|
item_ = std::move(i);
|
||||||
|
|
||||||
|
auto const oldHash = hash_;
|
||||||
|
|
||||||
|
updateHash();
|
||||||
|
|
||||||
|
return (oldHash != hash_);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
SHAMapLeafNode::getString(const SHAMapNodeID& id) const
|
||||||
|
{
|
||||||
|
std::string ret = SHAMapTreeNode::getString(id);
|
||||||
|
|
||||||
|
auto const type = getType();
|
||||||
|
|
||||||
|
if (type == SHAMapNodeType::tnTRANSACTION_NM)
|
||||||
|
ret += ",txn\n";
|
||||||
|
else if (type == SHAMapNodeType::tnTRANSACTION_MD)
|
||||||
|
ret += ",txn+md\n";
|
||||||
|
else if (type == SHAMapNodeType::tnACCOUNT_STATE)
|
||||||
|
ret += ",as\n";
|
||||||
|
else
|
||||||
|
ret += ",leaf\n";
|
||||||
|
|
||||||
|
ret += " Tag=";
|
||||||
|
ret += to_string(item_->key());
|
||||||
|
ret += "\n Hash=";
|
||||||
|
ret += to_string(hash_);
|
||||||
|
ret += "/";
|
||||||
|
ret += std::to_string(item_->size());
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SHAMapLeafNode::invariants(bool) const
|
||||||
|
{
|
||||||
|
assert(hash_.isNonZero());
|
||||||
|
assert(item_ != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ripple
|
||||||
@@ -28,16 +28,15 @@ SHAMap::visitLeaves(
|
|||||||
std::function<void(std::shared_ptr<SHAMapItem const> const& item)> const&
|
std::function<void(std::shared_ptr<SHAMapItem const> const& item)> const&
|
||||||
leafFunction) const
|
leafFunction) const
|
||||||
{
|
{
|
||||||
visitNodes([&leafFunction](SHAMapAbstractNode& node) {
|
visitNodes([&leafFunction](SHAMapTreeNode& node) {
|
||||||
if (!node.isInner())
|
if (!node.isInner())
|
||||||
leafFunction(static_cast<SHAMapTreeNode&>(node).peekItem());
|
leafFunction(static_cast<SHAMapLeafNode&>(node).peekItem());
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SHAMap::visitNodes(
|
SHAMap::visitNodes(std::function<bool(SHAMapTreeNode&)> const& function) const
|
||||||
std::function<bool(SHAMapAbstractNode&)> const& function) const
|
|
||||||
{
|
{
|
||||||
if (!root_)
|
if (!root_)
|
||||||
return;
|
return;
|
||||||
@@ -60,7 +59,7 @@ SHAMap::visitNodes(
|
|||||||
uint256 childHash;
|
uint256 childHash;
|
||||||
if (!node->isEmptyBranch(pos))
|
if (!node->isEmptyBranch(pos))
|
||||||
{
|
{
|
||||||
std::shared_ptr<SHAMapAbstractNode> child =
|
std::shared_ptr<SHAMapTreeNode> child =
|
||||||
descendNoStore(node, pos);
|
descendNoStore(node, pos);
|
||||||
if (!function(*child))
|
if (!function(*child))
|
||||||
return;
|
return;
|
||||||
@@ -101,24 +100,24 @@ SHAMap::visitNodes(
|
|||||||
void
|
void
|
||||||
SHAMap::visitDifferences(
|
SHAMap::visitDifferences(
|
||||||
SHAMap const* have,
|
SHAMap const* have,
|
||||||
std::function<bool(SHAMapAbstractNode&)> function) const
|
std::function<bool(SHAMapTreeNode const&)> function) const
|
||||||
{
|
{
|
||||||
// Visit every node in this SHAMap that is not present
|
// Visit every node in this SHAMap that is not present
|
||||||
// in the specified SHAMap
|
// in the specified SHAMap
|
||||||
if (!root_)
|
if (!root_)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (root_->getNodeHash().isZero())
|
if (root_->getHash().isZero())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (have && (root_->getNodeHash() == have->root_->getNodeHash()))
|
if (have && (root_->getHash() == have->root_->getHash()))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (root_->isLeaf())
|
if (root_->isLeaf())
|
||||||
{
|
{
|
||||||
auto leaf = std::static_pointer_cast<SHAMapTreeNode>(root_);
|
auto leaf = std::static_pointer_cast<SHAMapLeafNode>(root_);
|
||||||
if (!have ||
|
if (!have ||
|
||||||
!have->hasLeafNode(leaf->peekItem()->key(), leaf->getNodeHash()))
|
!have->hasLeafNode(leaf->peekItem()->key(), leaf->getHash()))
|
||||||
function(*root_);
|
function(*root_);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -155,7 +154,7 @@ SHAMap::visitDifferences(
|
|||||||
else if (
|
else if (
|
||||||
!have ||
|
!have ||
|
||||||
!have->hasLeafNode(
|
!have->hasLeafNode(
|
||||||
static_cast<SHAMapTreeNode*>(next)->peekItem()->key(),
|
static_cast<SHAMapLeafNode*>(next)->peekItem()->key(),
|
||||||
childHash))
|
childHash))
|
||||||
{
|
{
|
||||||
if (!function(*next))
|
if (!function(*next))
|
||||||
@@ -242,7 +241,7 @@ SHAMap::gmn_ProcessNodes(MissingNodes& mn, MissingNodes::StackEntry& se)
|
|||||||
if (backed_)
|
if (backed_)
|
||||||
{
|
{
|
||||||
f_.getFullBelowCache(ledgerSeq_)
|
f_.getFullBelowCache(ledgerSeq_)
|
||||||
->insert(node->getNodeHash().as_uint256());
|
->insert(node->getHash().as_uint256());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,7 +314,7 @@ SHAMap::gmn_ProcessDeferredReads(MissingNodes& mn)
|
|||||||
std::vector<std::pair<SHAMapNodeID, uint256>>
|
std::vector<std::pair<SHAMapNodeID, uint256>>
|
||||||
SHAMap::getMissingNodes(int max, SHAMapSyncFilter* filter)
|
SHAMap::getMissingNodes(int max, SHAMapSyncFilter* filter)
|
||||||
{
|
{
|
||||||
assert(root_->getNodeHash().isNonZero());
|
assert(root_->getHash().isNonZero());
|
||||||
assert(max > 0);
|
assert(max > 0);
|
||||||
|
|
||||||
MissingNodes mn(
|
MissingNodes mn(
|
||||||
@@ -423,23 +422,9 @@ SHAMap::getMissingNodes(int max, SHAMapSyncFilter* filter)
|
|||||||
return std::move(mn.missingNodes_);
|
return std::move(mn.missingNodes_);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint256>
|
|
||||||
SHAMap::getNeededHashes(int max, SHAMapSyncFilter* filter)
|
|
||||||
{
|
|
||||||
auto ret = getMissingNodes(max, filter);
|
|
||||||
|
|
||||||
std::vector<uint256> hashes;
|
|
||||||
hashes.reserve(ret.size());
|
|
||||||
|
|
||||||
for (auto const& n : ret)
|
|
||||||
hashes.push_back(n.second);
|
|
||||||
|
|
||||||
return hashes;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SHAMap::getNodeFat(
|
SHAMap::getNodeFat(
|
||||||
SHAMapNodeID wanted,
|
SHAMapNodeID const& wanted,
|
||||||
std::vector<SHAMapNodeID>& nodeIDs,
|
std::vector<SHAMapNodeID>& nodeIDs,
|
||||||
std::vector<Blob>& rawNodes,
|
std::vector<Blob>& rawNodes,
|
||||||
bool fatLeaves,
|
bool fatLeaves,
|
||||||
@@ -476,7 +461,7 @@ SHAMap::getNodeFat(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::stack<std::tuple<SHAMapAbstractNode*, SHAMapNodeID, int>> stack;
|
std::stack<std::tuple<SHAMapTreeNode*, SHAMapNodeID, int>> stack;
|
||||||
stack.emplace(node, nodeID, depth);
|
stack.emplace(node, nodeID, depth);
|
||||||
|
|
||||||
while (!stack.empty())
|
while (!stack.empty())
|
||||||
@@ -547,16 +532,16 @@ SHAMap::addRootNode(
|
|||||||
SHAMapSyncFilter* filter)
|
SHAMapSyncFilter* filter)
|
||||||
{
|
{
|
||||||
// we already have a root_ node
|
// we already have a root_ node
|
||||||
if (root_->getNodeHash().isNonZero())
|
if (root_->getHash().isNonZero())
|
||||||
{
|
{
|
||||||
JLOG(journal_.trace()) << "got root node, already have one";
|
JLOG(journal_.trace()) << "got root node, already have one";
|
||||||
assert(root_->getNodeHash() == hash);
|
assert(root_->getHash() == hash);
|
||||||
return SHAMapAddNode::duplicate();
|
return SHAMapAddNode::duplicate();
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(seq_ >= 1);
|
assert(cowid_ >= 1);
|
||||||
auto node = SHAMapAbstractNode::makeFromWire(rootNode);
|
auto node = SHAMapTreeNode::makeFromWire(rootNode);
|
||||||
if (!node || node->getNodeHash() != hash)
|
if (!node || node->getHash() != hash)
|
||||||
return SHAMapAddNode::invalid();
|
return SHAMapAddNode::invalid();
|
||||||
|
|
||||||
if (backed_)
|
if (backed_)
|
||||||
@@ -573,7 +558,7 @@ SHAMap::addRootNode(
|
|||||||
root_->serializeWithPrefix(s);
|
root_->serializeWithPrefix(s);
|
||||||
filter->gotNode(
|
filter->gotNode(
|
||||||
false,
|
false,
|
||||||
root_->getNodeHash(),
|
root_->getHash(),
|
||||||
ledgerSeq_,
|
ledgerSeq_,
|
||||||
std::move(s.modData()),
|
std::move(s.modData()),
|
||||||
root_->getType());
|
root_->getType());
|
||||||
@@ -597,7 +582,7 @@ SHAMap::addKnownNode(
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto const generation = f_.getFullBelowCache(ledgerSeq_)->getGeneration();
|
auto const generation = f_.getFullBelowCache(ledgerSeq_)->getGeneration();
|
||||||
auto newNode = SHAMapAbstractNode::makeFromWire(rawNode);
|
auto newNode = SHAMapTreeNode::makeFromWire(rawNode);
|
||||||
SHAMapNodeID iNodeID;
|
SHAMapNodeID iNodeID;
|
||||||
auto iNode = root_.get();
|
auto iNode = root_.get();
|
||||||
|
|
||||||
@@ -626,13 +611,17 @@ SHAMap::addKnownNode(
|
|||||||
|
|
||||||
if (iNode == nullptr)
|
if (iNode == nullptr)
|
||||||
{
|
{
|
||||||
if (!newNode || childHash != newNode->getNodeHash())
|
if (!newNode || childHash != newNode->getHash())
|
||||||
{
|
{
|
||||||
JLOG(journal_.warn()) << "Corrupt node received";
|
JLOG(journal_.warn()) << "Corrupt node received";
|
||||||
return SHAMapAddNode::invalid();
|
return SHAMapAddNode::invalid();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!newNode->isInBounds(iNodeID))
|
// Inner nodes must be at a level strictly less than 64
|
||||||
|
// but leaf nodes (while notionally at level 64) can be
|
||||||
|
// at any depth up to and including 64:
|
||||||
|
if ((iNodeID.getDepth() > leafDepth) ||
|
||||||
|
(newNode->isInner() && iNodeID.getDepth() == leafDepth))
|
||||||
{
|
{
|
||||||
// Map is provably invalid
|
// Map is provably invalid
|
||||||
state_ = SHAMapState::Invalid;
|
state_ = SHAMapState::Invalid;
|
||||||
@@ -678,7 +667,7 @@ bool
|
|||||||
SHAMap::deepCompare(SHAMap& other) const
|
SHAMap::deepCompare(SHAMap& other) const
|
||||||
{
|
{
|
||||||
// Intended for debug/test only
|
// Intended for debug/test only
|
||||||
std::stack<std::pair<SHAMapAbstractNode*, SHAMapAbstractNode*>> stack;
|
std::stack<std::pair<SHAMapTreeNode*, SHAMapTreeNode*>> stack;
|
||||||
|
|
||||||
stack.push({root_.get(), other.root_.get()});
|
stack.push({root_.get(), other.root_.get()});
|
||||||
|
|
||||||
@@ -692,7 +681,7 @@ SHAMap::deepCompare(SHAMap& other) const
|
|||||||
JLOG(journal_.info()) << "unable to fetch node";
|
JLOG(journal_.info()) << "unable to fetch node";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (otherNode->getNodeHash() != node->getNodeHash())
|
else if (otherNode->getHash() != node->getHash())
|
||||||
{
|
{
|
||||||
JLOG(journal_.warn()) << "node hash mismatch";
|
JLOG(journal_.warn()) << "node hash mismatch";
|
||||||
return false;
|
return false;
|
||||||
@@ -702,9 +691,9 @@ SHAMap::deepCompare(SHAMap& other) const
|
|||||||
{
|
{
|
||||||
if (!otherNode->isLeaf())
|
if (!otherNode->isLeaf())
|
||||||
return false;
|
return false;
|
||||||
auto& nodePeek = static_cast<SHAMapTreeNode*>(node)->peekItem();
|
auto& nodePeek = static_cast<SHAMapLeafNode*>(node)->peekItem();
|
||||||
auto& otherNodePeek =
|
auto& otherNodePeek =
|
||||||
static_cast<SHAMapTreeNode*>(otherNode)->peekItem();
|
static_cast<SHAMapLeafNode*>(otherNode)->peekItem();
|
||||||
if (nodePeek->key() != otherNodePeek->key())
|
if (nodePeek->key() != otherNodePeek->key())
|
||||||
return false;
|
return false;
|
||||||
if (nodePeek->peekData() != otherNodePeek->peekData())
|
if (nodePeek->peekData() != otherNodePeek->peekData())
|
||||||
@@ -765,7 +754,7 @@ SHAMap::hasInnerNode(
|
|||||||
nodeID = nodeID.getChildNodeID(branch);
|
nodeID = nodeID.getChildNodeID(branch);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (node->isInner()) && (node->getNodeHash() == targetNodeHash);
|
return (node->isInner()) && (node->getHash() == targetNodeHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Does this map have this leaf node?
|
/** Does this map have this leaf node?
|
||||||
@@ -777,7 +766,7 @@ SHAMap::hasLeafNode(uint256 const& tag, SHAMapHash const& targetNodeHash) const
|
|||||||
SHAMapNodeID nodeID;
|
SHAMapNodeID nodeID;
|
||||||
|
|
||||||
if (!node->isInner()) // only one leaf node in the tree
|
if (!node->isInner()) // only one leaf node in the tree
|
||||||
return node->getNodeHash() == targetNodeHash;
|
return node->getHash() == targetNodeHash;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@@ -798,35 +787,4 @@ SHAMap::hasLeafNode(uint256 const& tag, SHAMapHash const& targetNodeHash) const
|
|||||||
// already
|
// already
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
@param have A pointer to the map that the recipient already has (if any).
|
|
||||||
@param includeLeaves True if leaf nodes should be included.
|
|
||||||
@param max The maximum number of nodes to return.
|
|
||||||
@param func The functor to call for each node added to the FetchPack.
|
|
||||||
|
|
||||||
Note: a caller should set includeLeaves to false for transaction trees.
|
|
||||||
There's no point in including the leaves of transaction trees.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
SHAMap::getFetchPack(
|
|
||||||
SHAMap const* have,
|
|
||||||
bool includeLeaves,
|
|
||||||
int max,
|
|
||||||
std::function<void(SHAMapHash const&, const Blob&)> func) const
|
|
||||||
{
|
|
||||||
visitDifferences(
|
|
||||||
have, [includeLeaves, &max, &func](SHAMapAbstractNode& smn) -> bool {
|
|
||||||
if (includeLeaves || smn.isInner())
|
|
||||||
{
|
|
||||||
Serializer s;
|
|
||||||
smn.serializeWithPrefix(s);
|
|
||||||
func(smn.getNodeHash(), s.peekData());
|
|
||||||
|
|
||||||
if (--max <= 0)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ripple
|
} // namespace ripple
|
||||||
|
|||||||
@@ -24,69 +24,21 @@
|
|||||||
#include <ripple/beast/core/LexicalCast.h>
|
#include <ripple/beast/core/LexicalCast.h>
|
||||||
#include <ripple/protocol/HashPrefix.h>
|
#include <ripple/protocol/HashPrefix.h>
|
||||||
#include <ripple/protocol/digest.h>
|
#include <ripple/protocol/digest.h>
|
||||||
|
#include <ripple/shamap/SHAMapAccountStateLeafNode.h>
|
||||||
|
#include <ripple/shamap/SHAMapInnerNode.h>
|
||||||
|
#include <ripple/shamap/SHAMapLeafNode.h>
|
||||||
#include <ripple/shamap/SHAMapTreeNode.h>
|
#include <ripple/shamap/SHAMapTreeNode.h>
|
||||||
|
#include <ripple/shamap/SHAMapTxLeafNode.h>
|
||||||
|
#include <ripple/shamap/SHAMapTxPlusMetaLeafNode.h>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
#include <openssl/sha.h>
|
#include <openssl/sha.h>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
// These are wire-protocol identifiers used during serialization to encode the
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
// type of a node. They should not be arbitrarily be changed.
|
SHAMapTreeNode::makeTransaction(
|
||||||
static constexpr unsigned char const wireTypeTransaction = 0;
|
|
||||||
static constexpr unsigned char const wireTypeAccountState = 1;
|
|
||||||
static constexpr unsigned char const wireTypeInner = 2;
|
|
||||||
static constexpr unsigned char const wireTypeCompressedInner = 3;
|
|
||||||
static constexpr unsigned char const wireTypeTransactionWithMeta = 4;
|
|
||||||
|
|
||||||
std::mutex SHAMapInnerNode::childLock;
|
|
||||||
|
|
||||||
SHAMapAbstractNode::~SHAMapAbstractNode() = default;
|
|
||||||
|
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
|
||||||
SHAMapInnerNode::clone(std::uint32_t seq) const
|
|
||||||
{
|
|
||||||
auto p = std::make_shared<SHAMapInnerNode>(seq);
|
|
||||||
p->mHash = mHash;
|
|
||||||
p->mIsBranch = mIsBranch;
|
|
||||||
p->mFullBelowGen = mFullBelowGen;
|
|
||||||
p->mHashes = mHashes;
|
|
||||||
std::lock_guard lock(childLock);
|
|
||||||
for (int i = 0; i < 16; ++i)
|
|
||||||
p->mChildren[i] = mChildren[i];
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
|
||||||
SHAMapTreeNode::clone(std::uint32_t seq) const
|
|
||||||
{
|
|
||||||
return std::make_shared<SHAMapTreeNode>(mItem, mType, seq, mHash);
|
|
||||||
}
|
|
||||||
|
|
||||||
SHAMapTreeNode::SHAMapTreeNode(
|
|
||||||
std::shared_ptr<SHAMapItem const> item,
|
|
||||||
TNType type,
|
|
||||||
std::uint32_t seq)
|
|
||||||
: SHAMapAbstractNode(type, seq), mItem(std::move(item))
|
|
||||||
{
|
|
||||||
assert(mItem->peekData().size() >= 12);
|
|
||||||
updateHash();
|
|
||||||
}
|
|
||||||
|
|
||||||
SHAMapTreeNode::SHAMapTreeNode(
|
|
||||||
std::shared_ptr<SHAMapItem const> item,
|
|
||||||
TNType type,
|
|
||||||
std::uint32_t seq,
|
|
||||||
SHAMapHash const& hash)
|
|
||||||
: SHAMapAbstractNode(type, seq, hash), mItem(std::move(item))
|
|
||||||
{
|
|
||||||
assert(mItem->peekData().size() >= 12);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
|
||||||
SHAMapAbstractNode::makeTransaction(
|
|
||||||
Slice data,
|
Slice data,
|
||||||
std::uint32_t seq,
|
|
||||||
SHAMapHash const& hash,
|
SHAMapHash const& hash,
|
||||||
bool hashValid)
|
bool hashValid)
|
||||||
{
|
{
|
||||||
@@ -97,17 +49,14 @@ SHAMapAbstractNode::makeTransaction(
|
|||||||
sha512Half(HashPrefix::transactionID, data), s);
|
sha512Half(HashPrefix::transactionID, data), s);
|
||||||
|
|
||||||
if (hashValid)
|
if (hashValid)
|
||||||
return std::make_shared<SHAMapTreeNode>(
|
return std::make_shared<SHAMapTxLeafNode>(std::move(item), 0, hash);
|
||||||
std::move(item), tnTRANSACTION_NM, seq, hash);
|
|
||||||
|
|
||||||
return std::make_shared<SHAMapTreeNode>(
|
return std::make_shared<SHAMapTxLeafNode>(std::move(item), 0);
|
||||||
std::move(item), tnTRANSACTION_NM, seq);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
SHAMapAbstractNode::makeTransactionWithMeta(
|
SHAMapTreeNode::makeTransactionWithMeta(
|
||||||
Slice data,
|
Slice data,
|
||||||
std::uint32_t seq,
|
|
||||||
SHAMapHash const& hash,
|
SHAMapHash const& hash,
|
||||||
bool hashValid)
|
bool hashValid)
|
||||||
{
|
{
|
||||||
@@ -128,17 +77,15 @@ SHAMapAbstractNode::makeTransactionWithMeta(
|
|||||||
auto item = std::make_shared<SHAMapItem const>(tag, s.peekData());
|
auto item = std::make_shared<SHAMapItem const>(tag, s.peekData());
|
||||||
|
|
||||||
if (hashValid)
|
if (hashValid)
|
||||||
return std::make_shared<SHAMapTreeNode>(
|
return std::make_shared<SHAMapTxPlusMetaLeafNode>(
|
||||||
std::move(item), tnTRANSACTION_MD, seq, hash);
|
std::move(item), 0, hash);
|
||||||
|
|
||||||
return std::make_shared<SHAMapTreeNode>(
|
return std::make_shared<SHAMapTxPlusMetaLeafNode>(std::move(item), 0);
|
||||||
std::move(item), tnTRANSACTION_MD, seq);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
SHAMapAbstractNode::makeAccountState(
|
SHAMapTreeNode::makeAccountState(
|
||||||
Slice data,
|
Slice data,
|
||||||
std::uint32_t seq,
|
|
||||||
SHAMapHash const& hash,
|
SHAMapHash const& hash,
|
||||||
bool hashValid)
|
bool hashValid)
|
||||||
{
|
{
|
||||||
@@ -162,74 +109,14 @@ SHAMapAbstractNode::makeAccountState(
|
|||||||
auto item = std::make_shared<SHAMapItem const>(tag, s.peekData());
|
auto item = std::make_shared<SHAMapItem const>(tag, s.peekData());
|
||||||
|
|
||||||
if (hashValid)
|
if (hashValid)
|
||||||
return std::make_shared<SHAMapTreeNode>(
|
return std::make_shared<SHAMapAccountStateLeafNode>(
|
||||||
std::move(item), tnACCOUNT_STATE, seq, hash);
|
std::move(item), 0, hash);
|
||||||
|
|
||||||
return std::make_shared<SHAMapTreeNode>(
|
return std::make_shared<SHAMapAccountStateLeafNode>(std::move(item), 0);
|
||||||
std::move(item), tnACCOUNT_STATE, seq);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
SHAMapInnerNode::makeFullInner(
|
SHAMapTreeNode::makeFromWire(Slice rawNode)
|
||||||
Slice data,
|
|
||||||
std::uint32_t seq,
|
|
||||||
SHAMapHash const& hash,
|
|
||||||
bool hashValid)
|
|
||||||
{
|
|
||||||
if (data.size() != 512)
|
|
||||||
Throw<std::runtime_error>("Invalid FI node");
|
|
||||||
|
|
||||||
auto ret = std::make_shared<SHAMapInnerNode>(seq);
|
|
||||||
|
|
||||||
Serializer s(data.data(), data.size());
|
|
||||||
|
|
||||||
for (int i = 0; i < 16; ++i)
|
|
||||||
{
|
|
||||||
s.getBitString(ret->mHashes[i].as_uint256(), i * 32);
|
|
||||||
|
|
||||||
if (ret->mHashes[i].isNonZero())
|
|
||||||
ret->mIsBranch |= (1 << i);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hashValid)
|
|
||||||
ret->mHash = hash;
|
|
||||||
else
|
|
||||||
ret->updateHash();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
|
||||||
SHAMapInnerNode::makeCompressedInner(Slice data, std::uint32_t seq)
|
|
||||||
{
|
|
||||||
Serializer s(data.data(), data.size());
|
|
||||||
|
|
||||||
int len = s.getLength();
|
|
||||||
|
|
||||||
auto ret = std::make_shared<SHAMapInnerNode>(seq);
|
|
||||||
|
|
||||||
for (int i = 0; i < (len / 33); ++i)
|
|
||||||
{
|
|
||||||
int pos;
|
|
||||||
|
|
||||||
if (!s.get8(pos, 32 + (i * 33)))
|
|
||||||
Throw<std::runtime_error>("short CI node");
|
|
||||||
|
|
||||||
if ((pos < 0) || (pos >= 16))
|
|
||||||
Throw<std::runtime_error>("invalid CI node");
|
|
||||||
|
|
||||||
s.getBitString(ret->mHashes[pos].as_uint256(), i * 33);
|
|
||||||
|
|
||||||
if (ret->mHashes[pos].isNonZero())
|
|
||||||
ret->mIsBranch |= (1 << pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret->updateHash();
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
|
||||||
SHAMapAbstractNode::makeFromWire(Slice rawNode)
|
|
||||||
{
|
{
|
||||||
if (rawNode.empty())
|
if (rawNode.empty())
|
||||||
return {};
|
return {};
|
||||||
@@ -241,29 +128,27 @@ SHAMapAbstractNode::makeFromWire(Slice rawNode)
|
|||||||
bool const hashValid = false;
|
bool const hashValid = false;
|
||||||
SHAMapHash const hash;
|
SHAMapHash const hash;
|
||||||
|
|
||||||
std::uint32_t const seq = 0;
|
|
||||||
|
|
||||||
if (type == wireTypeTransaction)
|
if (type == wireTypeTransaction)
|
||||||
return makeTransaction(rawNode, seq, hash, hashValid);
|
return makeTransaction(rawNode, hash, hashValid);
|
||||||
|
|
||||||
if (type == wireTypeAccountState)
|
if (type == wireTypeAccountState)
|
||||||
return makeAccountState(rawNode, seq, hash, hashValid);
|
return makeAccountState(rawNode, hash, hashValid);
|
||||||
|
|
||||||
if (type == wireTypeInner)
|
if (type == wireTypeInner)
|
||||||
return SHAMapInnerNode::makeFullInner(rawNode, seq, hash, hashValid);
|
return SHAMapInnerNode::makeFullInner(rawNode, hash, hashValid);
|
||||||
|
|
||||||
if (type == wireTypeCompressedInner)
|
if (type == wireTypeCompressedInner)
|
||||||
return SHAMapInnerNode::makeCompressedInner(rawNode, seq);
|
return SHAMapInnerNode::makeCompressedInner(rawNode);
|
||||||
|
|
||||||
if (type == wireTypeTransactionWithMeta)
|
if (type == wireTypeTransactionWithMeta)
|
||||||
return makeTransactionWithMeta(rawNode, seq, hash, hashValid);
|
return makeTransactionWithMeta(rawNode, hash, hashValid);
|
||||||
|
|
||||||
Throw<std::runtime_error>(
|
Throw<std::runtime_error>(
|
||||||
"wire: Unknown type (" + std::to_string(type) + ")");
|
"wire: Unknown type (" + std::to_string(type) + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
std::shared_ptr<SHAMapTreeNode>
|
||||||
SHAMapAbstractNode::makeFromPrefix(Slice rawNode, SHAMapHash const& hash)
|
SHAMapTreeNode::makeFromPrefix(Slice rawNode, SHAMapHash const& hash)
|
||||||
{
|
{
|
||||||
if (rawNode.size() < 4)
|
if (rawNode.size() < 4)
|
||||||
Throw<std::runtime_error>("prefix: short node");
|
Throw<std::runtime_error>("prefix: short node");
|
||||||
@@ -279,19 +164,18 @@ SHAMapAbstractNode::makeFromPrefix(Slice rawNode, SHAMapHash const& hash)
|
|||||||
rawNode.remove_prefix(4);
|
rawNode.remove_prefix(4);
|
||||||
|
|
||||||
bool const hashValid = true;
|
bool const hashValid = true;
|
||||||
std::uint32_t const seq = 0;
|
|
||||||
|
|
||||||
if (type == HashPrefix::transactionID)
|
if (type == HashPrefix::transactionID)
|
||||||
return makeTransaction(rawNode, seq, hash, hashValid);
|
return makeTransaction(rawNode, hash, hashValid);
|
||||||
|
|
||||||
if (type == HashPrefix::leafNode)
|
if (type == HashPrefix::leafNode)
|
||||||
return makeAccountState(rawNode, seq, hash, hashValid);
|
return makeAccountState(rawNode, hash, hashValid);
|
||||||
|
|
||||||
if (type == HashPrefix::innerNode)
|
if (type == HashPrefix::innerNode)
|
||||||
return SHAMapInnerNode::makeFullInner(rawNode, seq, hash, hashValid);
|
return SHAMapInnerNode::makeFullInner(rawNode, hash, hashValid);
|
||||||
|
|
||||||
if (type == HashPrefix::txNode)
|
if (type == HashPrefix::txNode)
|
||||||
return makeTransactionWithMeta(rawNode, seq, hash, hashValid);
|
return makeTransactionWithMeta(rawNode, hash, hashValid);
|
||||||
|
|
||||||
Throw<std::runtime_error>(
|
Throw<std::runtime_error>(
|
||||||
"prefix: unknown type (" +
|
"prefix: unknown type (" +
|
||||||
@@ -299,349 +183,10 @@ SHAMapAbstractNode::makeFromPrefix(Slice rawNode, SHAMapHash const& hash)
|
|||||||
")");
|
")");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
SHAMapInnerNode::updateHash()
|
|
||||||
{
|
|
||||||
uint256 nh;
|
|
||||||
if (mIsBranch != 0)
|
|
||||||
{
|
|
||||||
sha512_half_hasher h;
|
|
||||||
using beast::hash_append;
|
|
||||||
hash_append(h, HashPrefix::innerNode);
|
|
||||||
for (auto const& hh : mHashes)
|
|
||||||
hash_append(h, hh);
|
|
||||||
nh = static_cast<typename sha512_half_hasher::result_type>(h);
|
|
||||||
}
|
|
||||||
if (nh == mHash.as_uint256())
|
|
||||||
return false;
|
|
||||||
mHash = SHAMapHash{nh};
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SHAMapInnerNode::updateHashDeep()
|
|
||||||
{
|
|
||||||
for (auto pos = 0; pos < 16; ++pos)
|
|
||||||
{
|
|
||||||
if (mChildren[pos] != nullptr)
|
|
||||||
mHashes[pos] = mChildren[pos]->getNodeHash();
|
|
||||||
}
|
|
||||||
updateHash();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
SHAMapTreeNode::updateHash()
|
|
||||||
{
|
|
||||||
uint256 nh;
|
|
||||||
if (mType == tnTRANSACTION_NM)
|
|
||||||
{
|
|
||||||
nh =
|
|
||||||
sha512Half(HashPrefix::transactionID, makeSlice(mItem->peekData()));
|
|
||||||
}
|
|
||||||
else if (mType == tnACCOUNT_STATE)
|
|
||||||
{
|
|
||||||
nh = sha512Half(
|
|
||||||
HashPrefix::leafNode, makeSlice(mItem->peekData()), mItem->key());
|
|
||||||
}
|
|
||||||
else if (mType == tnTRANSACTION_MD)
|
|
||||||
{
|
|
||||||
nh = sha512Half(
|
|
||||||
HashPrefix::txNode, makeSlice(mItem->peekData()), mItem->key());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
assert(false);
|
|
||||||
|
|
||||||
if (nh == mHash.as_uint256())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
mHash = SHAMapHash{nh};
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SHAMapInnerNode::serializeForWire(Serializer& s) const
|
|
||||||
{
|
|
||||||
assert(mType == tnINNER);
|
|
||||||
assert(!isEmpty());
|
|
||||||
|
|
||||||
// If the node is sparse, then only send non-empty branches:
|
|
||||||
if (getBranchCount() < 12)
|
|
||||||
{
|
|
||||||
// compressed node
|
|
||||||
for (int i = 0; i < mHashes.size(); ++i)
|
|
||||||
{
|
|
||||||
if (!isEmptyBranch(i))
|
|
||||||
{
|
|
||||||
s.addBitString(mHashes[i].as_uint256());
|
|
||||||
s.add8(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s.add8(wireTypeCompressedInner);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (auto const& hh : mHashes)
|
|
||||||
s.addBitString(hh.as_uint256());
|
|
||||||
|
|
||||||
s.add8(wireTypeInner);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SHAMapInnerNode::serializeWithPrefix(Serializer& s) const
|
|
||||||
{
|
|
||||||
assert(mType == tnINNER);
|
|
||||||
assert(!isEmpty());
|
|
||||||
|
|
||||||
s.add32(HashPrefix::innerNode);
|
|
||||||
for (auto const& hh : mHashes)
|
|
||||||
s.addBitString(hh.as_uint256());
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SHAMapTreeNode::serializeForWire(Serializer& s) const
|
|
||||||
{
|
|
||||||
if (mType == tnACCOUNT_STATE)
|
|
||||||
{
|
|
||||||
s.addRaw(mItem->peekData());
|
|
||||||
s.addBitString(mItem->key());
|
|
||||||
s.add8(wireTypeAccountState);
|
|
||||||
}
|
|
||||||
else if (mType == tnTRANSACTION_NM)
|
|
||||||
{
|
|
||||||
s.addRaw(mItem->peekData());
|
|
||||||
s.add8(wireTypeTransaction);
|
|
||||||
}
|
|
||||||
else if (mType == tnTRANSACTION_MD)
|
|
||||||
{
|
|
||||||
s.addRaw(mItem->peekData());
|
|
||||||
s.addBitString(mItem->key());
|
|
||||||
s.add8(wireTypeTransactionWithMeta);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SHAMapTreeNode::serializeWithPrefix(Serializer& s) const
|
|
||||||
{
|
|
||||||
if (mType == tnACCOUNT_STATE)
|
|
||||||
{
|
|
||||||
s.add32(HashPrefix::leafNode);
|
|
||||||
s.addRaw(mItem->peekData());
|
|
||||||
s.addBitString(mItem->key());
|
|
||||||
}
|
|
||||||
else if (mType == tnTRANSACTION_NM)
|
|
||||||
{
|
|
||||||
s.add32(HashPrefix::transactionID);
|
|
||||||
s.addRaw(mItem->peekData());
|
|
||||||
}
|
|
||||||
else if (mType == tnTRANSACTION_MD)
|
|
||||||
{
|
|
||||||
s.add32(HashPrefix::txNode);
|
|
||||||
s.addRaw(mItem->peekData());
|
|
||||||
s.addBitString(mItem->key());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
SHAMapTreeNode::setItem(std::shared_ptr<SHAMapItem const> i, TNType type)
|
|
||||||
{
|
|
||||||
mType = type;
|
|
||||||
mItem = std::move(i);
|
|
||||||
assert(isLeaf());
|
|
||||||
assert(mSeq != 0);
|
|
||||||
return updateHash();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
SHAMapInnerNode::isEmpty() const
|
|
||||||
{
|
|
||||||
return mIsBranch == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
SHAMapInnerNode::getBranchCount() const
|
|
||||||
{
|
|
||||||
assert(isInner());
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < 16; ++i)
|
|
||||||
if (!isEmptyBranch(i))
|
|
||||||
++count;
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
SHAMapAbstractNode::getString(const SHAMapNodeID& id) const
|
SHAMapTreeNode::getString(const SHAMapNodeID& id) const
|
||||||
{
|
{
|
||||||
return to_string(id);
|
return to_string(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string
|
|
||||||
SHAMapInnerNode::getString(const SHAMapNodeID& id) const
|
|
||||||
{
|
|
||||||
std::string ret = SHAMapAbstractNode::getString(id);
|
|
||||||
for (int i = 0; i < mHashes.size(); ++i)
|
|
||||||
{
|
|
||||||
if (!isEmptyBranch(i))
|
|
||||||
{
|
|
||||||
ret += "\n";
|
|
||||||
ret += std::to_string(i);
|
|
||||||
ret += " = ";
|
|
||||||
ret += to_string(mHashes[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string
|
|
||||||
SHAMapTreeNode::getString(const SHAMapNodeID& id) const
|
|
||||||
{
|
|
||||||
std::string ret = SHAMapAbstractNode::getString(id);
|
|
||||||
if (mType == tnTRANSACTION_NM)
|
|
||||||
ret += ",txn\n";
|
|
||||||
else if (mType == tnTRANSACTION_MD)
|
|
||||||
ret += ",txn+md\n";
|
|
||||||
else if (mType == tnACCOUNT_STATE)
|
|
||||||
ret += ",as\n";
|
|
||||||
else
|
|
||||||
ret += ",leaf\n";
|
|
||||||
|
|
||||||
ret += " Tag=";
|
|
||||||
ret += to_string(peekItem()->key());
|
|
||||||
ret += "\n Hash=";
|
|
||||||
ret += to_string(mHash);
|
|
||||||
ret += "/";
|
|
||||||
ret += std::to_string(mItem->size());
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We are modifying an inner node
|
|
||||||
void
|
|
||||||
SHAMapInnerNode::setChild(
|
|
||||||
int m,
|
|
||||||
std::shared_ptr<SHAMapAbstractNode> const& child)
|
|
||||||
{
|
|
||||||
assert((m >= 0) && (m < 16));
|
|
||||||
assert(mType == tnINNER);
|
|
||||||
assert(mSeq != 0);
|
|
||||||
assert(child.get() != this);
|
|
||||||
mHashes[m].zero();
|
|
||||||
mHash.zero();
|
|
||||||
if (child)
|
|
||||||
mIsBranch |= (1 << m);
|
|
||||||
else
|
|
||||||
mIsBranch &= ~(1 << m);
|
|
||||||
mChildren[m] = child;
|
|
||||||
}
|
|
||||||
|
|
||||||
// finished modifying, now make shareable
|
|
||||||
void
|
|
||||||
SHAMapInnerNode::shareChild(
|
|
||||||
int m,
|
|
||||||
std::shared_ptr<SHAMapAbstractNode> const& child)
|
|
||||||
{
|
|
||||||
assert((m >= 0) && (m < 16));
|
|
||||||
assert(mType == tnINNER);
|
|
||||||
assert(mSeq != 0);
|
|
||||||
assert(child);
|
|
||||||
assert(child.get() != this);
|
|
||||||
|
|
||||||
mChildren[m] = child;
|
|
||||||
}
|
|
||||||
|
|
||||||
SHAMapAbstractNode*
|
|
||||||
SHAMapInnerNode::getChildPointer(int branch)
|
|
||||||
{
|
|
||||||
assert(branch >= 0 && branch < 16);
|
|
||||||
assert(isInner());
|
|
||||||
|
|
||||||
std::lock_guard lock(childLock);
|
|
||||||
return mChildren[branch].get();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
|
||||||
SHAMapInnerNode::getChild(int branch)
|
|
||||||
{
|
|
||||||
assert(branch >= 0 && branch < 16);
|
|
||||||
assert(isInner());
|
|
||||||
|
|
||||||
std::lock_guard lock(childLock);
|
|
||||||
return mChildren[branch];
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<SHAMapAbstractNode>
|
|
||||||
SHAMapInnerNode::canonicalizeChild(
|
|
||||||
int branch,
|
|
||||||
std::shared_ptr<SHAMapAbstractNode> node)
|
|
||||||
{
|
|
||||||
assert(branch >= 0 && branch < 16);
|
|
||||||
assert(isInner());
|
|
||||||
assert(node);
|
|
||||||
assert(node->getNodeHash() == mHashes[branch]);
|
|
||||||
|
|
||||||
std::lock_guard lock(childLock);
|
|
||||||
if (mChildren[branch])
|
|
||||||
{
|
|
||||||
// There is already a node hooked up, return it
|
|
||||||
node = mChildren[branch];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Hook this node up
|
|
||||||
mChildren[branch] = node;
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint256 const&
|
|
||||||
SHAMapInnerNode::key() const
|
|
||||||
{
|
|
||||||
Throw<std::logic_error>("SHAMapInnerNode::key() should never be called");
|
|
||||||
static uint256 x;
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint256 const&
|
|
||||||
SHAMapTreeNode::key() const
|
|
||||||
{
|
|
||||||
return mItem->key();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SHAMapInnerNode::invariants(bool is_root) const
|
|
||||||
{
|
|
||||||
assert(mType == tnINNER);
|
|
||||||
unsigned count = 0;
|
|
||||||
for (int i = 0; i < 16; ++i)
|
|
||||||
{
|
|
||||||
if (mHashes[i].isNonZero())
|
|
||||||
{
|
|
||||||
assert((mIsBranch & (1 << i)) != 0);
|
|
||||||
if (mChildren[i] != nullptr)
|
|
||||||
mChildren[i]->invariants();
|
|
||||||
++count;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
assert((mIsBranch & (1 << i)) == 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!is_root)
|
|
||||||
{
|
|
||||||
assert(mHash.isNonZero());
|
|
||||||
assert(count >= 1);
|
|
||||||
}
|
|
||||||
assert((count == 0) ? mHash.isZero() : mHash.isNonZero());
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SHAMapTreeNode::invariants(bool) const
|
|
||||||
{
|
|
||||||
assert(mType >= tnTRANSACTION_NM);
|
|
||||||
assert(mHash.isNonZero());
|
|
||||||
assert(mItem != nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ripple
|
} // namespace ripple
|
||||||
|
|||||||
@@ -72,8 +72,8 @@ public:
|
|||||||
res->updateSkipList();
|
res->updateSkipList();
|
||||||
|
|
||||||
{
|
{
|
||||||
res->stateMap().flushDirty(hotACCOUNT_NODE, res->info().seq);
|
res->stateMap().flushDirty(hotACCOUNT_NODE);
|
||||||
res->txMap().flushDirty(hotTRANSACTION_NODE, res->info().seq);
|
res->txMap().flushDirty(hotTRANSACTION_NODE);
|
||||||
}
|
}
|
||||||
res->unshare();
|
res->unshare();
|
||||||
|
|
||||||
|
|||||||
@@ -283,15 +283,14 @@ class DatabaseShard_test : public TestBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Store the state map
|
// Store the state map
|
||||||
auto visitAcc = [&](SHAMapAbstractNode& node) {
|
auto visitAcc = [&](SHAMapTreeNode const& node) {
|
||||||
Serializer s;
|
Serializer s;
|
||||||
node.serializeWithPrefix(s);
|
node.serializeWithPrefix(s);
|
||||||
db.store(
|
db.store(
|
||||||
node.getType() == SHAMapAbstractNode::TNType::tnINNER
|
node.getType() == SHAMapNodeType::tnINNER ? hotUNKNOWN
|
||||||
? hotUNKNOWN
|
: hotACCOUNT_NODE,
|
||||||
: hotACCOUNT_NODE,
|
|
||||||
std::move(s.modData()),
|
std::move(s.modData()),
|
||||||
node.getNodeHash().as_uint256(),
|
node.getHash().as_uint256(),
|
||||||
ledger.info().seq);
|
ledger.info().seq);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
@@ -311,15 +310,14 @@ class DatabaseShard_test : public TestBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Store the transaction map
|
// Store the transaction map
|
||||||
auto visitTx = [&](SHAMapAbstractNode& node) {
|
auto visitTx = [&](SHAMapTreeNode& node) {
|
||||||
Serializer s;
|
Serializer s;
|
||||||
node.serializeWithPrefix(s);
|
node.serializeWithPrefix(s);
|
||||||
db.store(
|
db.store(
|
||||||
node.getType() == SHAMapAbstractNode::TNType::tnINNER
|
node.getType() == SHAMapNodeType::tnINNER ? hotUNKNOWN
|
||||||
? hotUNKNOWN
|
: hotTRANSACTION_NODE,
|
||||||
: hotTRANSACTION_NODE,
|
|
||||||
std::move(s.modData()),
|
std::move(s.modData()),
|
||||||
node.getNodeHash().as_uint256(),
|
node.getHash().as_uint256(),
|
||||||
ledger.info().seq);
|
ledger.info().seq);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
@@ -357,20 +355,19 @@ class DatabaseShard_test : public TestBase
|
|||||||
LedgerFill{*fetched, LedgerFill::full | LedgerFill::binary}));
|
LedgerFill{*fetched, LedgerFill::full | LedgerFill::binary}));
|
||||||
|
|
||||||
// walk shamap and validate each node
|
// walk shamap and validate each node
|
||||||
auto fcompAcc = [&](SHAMapAbstractNode& node) -> bool {
|
auto fcompAcc = [&](SHAMapTreeNode& node) -> bool {
|
||||||
Serializer s;
|
Serializer s;
|
||||||
node.serializeWithPrefix(s);
|
node.serializeWithPrefix(s);
|
||||||
auto nSrc{NodeObject::createObject(
|
auto nSrc{NodeObject::createObject(
|
||||||
node.getType() == SHAMapAbstractNode::TNType::tnINNER
|
node.getType() == SHAMapNodeType::tnINNER ? hotUNKNOWN
|
||||||
? hotUNKNOWN
|
: hotACCOUNT_NODE,
|
||||||
: hotACCOUNT_NODE,
|
|
||||||
std::move(s.modData()),
|
std::move(s.modData()),
|
||||||
node.getNodeHash().as_uint256())};
|
node.getHash().as_uint256())};
|
||||||
if (!BEAST_EXPECT(nSrc))
|
if (!BEAST_EXPECT(nSrc))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto nDst = db.fetchNodeObject(
|
auto nDst = db.fetchNodeObject(
|
||||||
node.getNodeHash().as_uint256(), ledger.info().seq);
|
node.getHash().as_uint256(), ledger.info().seq);
|
||||||
if (!BEAST_EXPECT(nDst))
|
if (!BEAST_EXPECT(nDst))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -381,20 +378,19 @@ class DatabaseShard_test : public TestBase
|
|||||||
if (ledger.stateMap().getHash().isNonZero())
|
if (ledger.stateMap().getHash().isNonZero())
|
||||||
ledger.stateMap().snapShot(false)->visitNodes(fcompAcc);
|
ledger.stateMap().snapShot(false)->visitNodes(fcompAcc);
|
||||||
|
|
||||||
auto fcompTx = [&](SHAMapAbstractNode& node) -> bool {
|
auto fcompTx = [&](SHAMapTreeNode& node) -> bool {
|
||||||
Serializer s;
|
Serializer s;
|
||||||
node.serializeWithPrefix(s);
|
node.serializeWithPrefix(s);
|
||||||
auto nSrc{NodeObject::createObject(
|
auto nSrc{NodeObject::createObject(
|
||||||
node.getType() == SHAMapAbstractNode::TNType::tnINNER
|
node.getType() == SHAMapNodeType::tnINNER ? hotUNKNOWN
|
||||||
? hotUNKNOWN
|
: hotTRANSACTION_NODE,
|
||||||
: hotTRANSACTION_NODE,
|
|
||||||
std::move(s.modData()),
|
std::move(s.modData()),
|
||||||
node.getNodeHash().as_uint256())};
|
node.getHash().as_uint256())};
|
||||||
if (!BEAST_EXPECT(nSrc))
|
if (!BEAST_EXPECT(nSrc))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto nDst = db.fetchNodeObject(
|
auto nDst = db.fetchNodeObject(
|
||||||
node.getNodeHash().as_uint256(), ledger.info().seq);
|
node.getHash().as_uint256(), ledger.info().seq);
|
||||||
if (!BEAST_EXPECT(nDst))
|
if (!BEAST_EXPECT(nDst))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ public:
|
|||||||
SHAMapHash const& nodeHash,
|
SHAMapHash const& nodeHash,
|
||||||
std::uint32_t ledgerSeq,
|
std::uint32_t ledgerSeq,
|
||||||
Blob&& nodeData,
|
Blob&& nodeData,
|
||||||
SHAMapTreeNode::TNType type) const override
|
SHAMapNodeType type) const override
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +100,8 @@ public:
|
|||||||
while (n--)
|
while (n--)
|
||||||
{
|
{
|
||||||
std::shared_ptr<SHAMapItem> item(make_random_item(r));
|
std::shared_ptr<SHAMapItem> item(make_random_item(r));
|
||||||
auto const result(t.addItem(std::move(*item), false, false));
|
auto const result(
|
||||||
|
t.addItem(SHAMapNodeType::tnACCOUNT_STATE, std::move(*item)));
|
||||||
assert(result);
|
assert(result);
|
||||||
(void)result;
|
(void)result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ public:
|
|||||||
std::shared_ptr<SHAMapItem> item = makeRandomAS();
|
std::shared_ptr<SHAMapItem> item = makeRandomAS();
|
||||||
items.push_back(item->key());
|
items.push_back(item->key());
|
||||||
|
|
||||||
if (!map.addItem(std::move(*item), false, false))
|
if (!map.addItem(SHAMapNodeType::tnACCOUNT_STATE, std::move(*item)))
|
||||||
{
|
{
|
||||||
log << "Unable to add item to map\n";
|
log << "Unable to add item to map\n";
|
||||||
return false;
|
return false;
|
||||||
@@ -98,7 +98,8 @@ public:
|
|||||||
int items = 10000;
|
int items = 10000;
|
||||||
for (int i = 0; i < items; ++i)
|
for (int i = 0; i < items; ++i)
|
||||||
{
|
{
|
||||||
source.addItem(std::move(*makeRandomAS()), false, false);
|
source.addItem(
|
||||||
|
SHAMapNodeType::tnACCOUNT_STATE, std::move(*makeRandomAS()));
|
||||||
if (i % 100 == 0)
|
if (i % 100 == 0)
|
||||||
source.invariants();
|
source.invariants();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,12 +64,12 @@ static_assert(std::is_copy_assignable<SHAMapHash>{}, "");
|
|||||||
static_assert(std::is_move_constructible<SHAMapHash>{}, "");
|
static_assert(std::is_move_constructible<SHAMapHash>{}, "");
|
||||||
static_assert(std::is_move_assignable<SHAMapHash>{}, "");
|
static_assert(std::is_move_assignable<SHAMapHash>{}, "");
|
||||||
|
|
||||||
static_assert(!std::is_nothrow_destructible<SHAMapAbstractNode>{}, "");
|
static_assert(std::is_nothrow_destructible<SHAMapTreeNode>{}, "");
|
||||||
static_assert(!std::is_default_constructible<SHAMapAbstractNode>{}, "");
|
static_assert(!std::is_default_constructible<SHAMapTreeNode>{}, "");
|
||||||
static_assert(!std::is_copy_constructible<SHAMapAbstractNode>{}, "");
|
static_assert(!std::is_copy_constructible<SHAMapTreeNode>{}, "");
|
||||||
static_assert(!std::is_copy_assignable<SHAMapAbstractNode>{}, "");
|
static_assert(!std::is_copy_assignable<SHAMapTreeNode>{}, "");
|
||||||
static_assert(!std::is_move_constructible<SHAMapAbstractNode>{}, "");
|
static_assert(!std::is_move_constructible<SHAMapTreeNode>{}, "");
|
||||||
static_assert(!std::is_move_assignable<SHAMapAbstractNode>{}, "");
|
static_assert(!std::is_move_assignable<SHAMapTreeNode>{}, "");
|
||||||
|
|
||||||
static_assert(std::is_nothrow_destructible<SHAMapInnerNode>{}, "");
|
static_assert(std::is_nothrow_destructible<SHAMapInnerNode>{}, "");
|
||||||
static_assert(!std::is_default_constructible<SHAMapInnerNode>{}, "");
|
static_assert(!std::is_default_constructible<SHAMapInnerNode>{}, "");
|
||||||
@@ -78,12 +78,12 @@ static_assert(!std::is_copy_assignable<SHAMapInnerNode>{}, "");
|
|||||||
static_assert(!std::is_move_constructible<SHAMapInnerNode>{}, "");
|
static_assert(!std::is_move_constructible<SHAMapInnerNode>{}, "");
|
||||||
static_assert(!std::is_move_assignable<SHAMapInnerNode>{}, "");
|
static_assert(!std::is_move_assignable<SHAMapInnerNode>{}, "");
|
||||||
|
|
||||||
static_assert(std::is_nothrow_destructible<SHAMapTreeNode>{}, "");
|
static_assert(std::is_nothrow_destructible<SHAMapLeafNode>{}, "");
|
||||||
static_assert(!std::is_default_constructible<SHAMapTreeNode>{}, "");
|
static_assert(!std::is_default_constructible<SHAMapLeafNode>{}, "");
|
||||||
static_assert(!std::is_copy_constructible<SHAMapTreeNode>{}, "");
|
static_assert(!std::is_copy_constructible<SHAMapLeafNode>{}, "");
|
||||||
static_assert(!std::is_copy_assignable<SHAMapTreeNode>{}, "");
|
static_assert(!std::is_copy_assignable<SHAMapLeafNode>{}, "");
|
||||||
static_assert(!std::is_move_constructible<SHAMapTreeNode>{}, "");
|
static_assert(!std::is_move_constructible<SHAMapLeafNode>{}, "");
|
||||||
static_assert(!std::is_move_assignable<SHAMapTreeNode>{}, "");
|
static_assert(!std::is_move_assignable<SHAMapLeafNode>{}, "");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
@@ -161,9 +161,13 @@ public:
|
|||||||
|
|
||||||
SHAMapItem i1(h1, IntToVUC(1)), i2(h2, IntToVUC(2)),
|
SHAMapItem i1(h1, IntToVUC(1)), i2(h2, IntToVUC(2)),
|
||||||
i3(h3, IntToVUC(3)), i4(h4, IntToVUC(4)), i5(h5, IntToVUC(5));
|
i3(h3, IntToVUC(3)), i4(h4, IntToVUC(4)), i5(h5, IntToVUC(5));
|
||||||
unexpected(!sMap.addItem(SHAMapItem{i2}, true, false), "no add");
|
unexpected(
|
||||||
|
!sMap.addItem(SHAMapNodeType::tnTRANSACTION_NM, SHAMapItem{i2}),
|
||||||
|
"no add");
|
||||||
sMap.invariants();
|
sMap.invariants();
|
||||||
unexpected(!sMap.addItem(SHAMapItem{i1}, true, false), "no add");
|
unexpected(
|
||||||
|
!sMap.addItem(SHAMapNodeType::tnTRANSACTION_NM, SHAMapItem{i1}),
|
||||||
|
"no add");
|
||||||
sMap.invariants();
|
sMap.invariants();
|
||||||
|
|
||||||
auto i = sMap.begin();
|
auto i = sMap.begin();
|
||||||
@@ -173,11 +177,11 @@ public:
|
|||||||
unexpected(i == e || (*i != i2), "bad traverse");
|
unexpected(i == e || (*i != i2), "bad traverse");
|
||||||
++i;
|
++i;
|
||||||
unexpected(i != e, "bad traverse");
|
unexpected(i != e, "bad traverse");
|
||||||
sMap.addItem(SHAMapItem{i4}, true, false);
|
sMap.addItem(SHAMapNodeType::tnTRANSACTION_NM, SHAMapItem{i4});
|
||||||
sMap.invariants();
|
sMap.invariants();
|
||||||
sMap.delItem(i2.key());
|
sMap.delItem(i2.key());
|
||||||
sMap.invariants();
|
sMap.invariants();
|
||||||
sMap.addItem(SHAMapItem{i3}, true, false);
|
sMap.addItem(SHAMapNodeType::tnTRANSACTION_NM, SHAMapItem{i3});
|
||||||
sMap.invariants();
|
sMap.invariants();
|
||||||
i = sMap.begin();
|
i = sMap.begin();
|
||||||
e = sMap.end();
|
e = sMap.end();
|
||||||
@@ -282,7 +286,8 @@ public:
|
|||||||
for (int k = 0; k < keys.size(); ++k)
|
for (int k = 0; k < keys.size(); ++k)
|
||||||
{
|
{
|
||||||
SHAMapItem item(keys[k], IntToVUC(k));
|
SHAMapItem item(keys[k], IntToVUC(k));
|
||||||
BEAST_EXPECT(map.addItem(std::move(item), true, false));
|
BEAST_EXPECT(map.addItem(
|
||||||
|
SHAMapNodeType::tnTRANSACTION_NM, std::move(item)));
|
||||||
BEAST_EXPECT(map.getHash().as_uint256() == hashes[k]);
|
BEAST_EXPECT(map.getHash().as_uint256() == hashes[k]);
|
||||||
map.invariants();
|
map.invariants();
|
||||||
}
|
}
|
||||||
@@ -333,7 +338,9 @@ public:
|
|||||||
map.setUnbacked();
|
map.setUnbacked();
|
||||||
for (auto const& k : keys)
|
for (auto const& k : keys)
|
||||||
{
|
{
|
||||||
map.addItem(SHAMapItem{k, IntToVUC(0)}, true, false);
|
map.addItem(
|
||||||
|
SHAMapNodeType::tnTRANSACTION_NM,
|
||||||
|
SHAMapItem{k, IntToVUC(0)});
|
||||||
map.invariants();
|
map.invariants();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user