/** We got some data for a ledger we are no longer acquiring Since we paid the price to receive it, we might as well stash it in case we need it. Nodes are received in wire format and must be stashed/hashed in prefix format */ void gotStaleData (std::shared_ptr<protocol::TMLedgerData> packet_ptr) override { const uint256 uZero; Serializer s; try { for (int i = 0; i < packet_ptr->nodes ().size (); ++i) { auto const& node = packet_ptr->nodes (i); if (!node.has_nodeid () || !node.has_nodedata ()) return; auto id_string = node.nodeid(); auto newNode = SHAMapAbstractNode::make( makeSlice(node.nodedata()), 0, snfWIRE, SHAMapHash{uZero}, false, app_.journal ("SHAMapNodeID"), SHAMapNodeID(id_string.data(), id_string.size())); if (!newNode) return; s.erase(); newNode->addRaw(s, snfPREFIX); auto blob = std::make_shared<Blob> (s.begin(), s.end()); app_.getLedgerMaster().addFetchPack( newNode->getNodeHash().as_uint256(), blob); } } catch (std::exception const&) { } }
// This can be optimized to avoid the << if needed SHAMapNodeID SHAMapNodeID::getChildNodeID (int m) const { assert ((m >= 0) && (m < 16)); assert (mDepth < 64); uint256 child (mNodeID); child.begin ()[mDepth / 2] |= (mDepth & 1) ? m : (m << 4); return SHAMapNodeID (mDepth + 1, child); }
void run () { unsigned int seed; // VFALCO DEPRECATED Should use C++11 RAND_pseudo_bytes (reinterpret_cast<unsigned char*> (&seed), sizeof (seed)); srand (seed); beast::Journal const j; // debug journal TestFamily f(j); SHAMap source (SHAMapType::FREE, f, j); SHAMap destination (SHAMapType::FREE, f, j); int items = 10000; for (int i = 0; i < items; ++i) source.addItem (*makeRandomAS (), false, false); unexpected (!confuseMap (source, 500), "ConfuseMap"); source.setImmutable (); std::vector<SHAMapNodeID> nodeIDs, gotNodeIDs; std::vector< Blob > gotNodes; std::vector<uint256> hashes; std::vector<SHAMapNodeID>::iterator nodeIDIterator; std::vector< Blob >::iterator rawNodeIterator; int passes = 0; int nodes = 0; destination.setSynching (); unexpected (!source.getNodeFat (SHAMapNodeID (), nodeIDs, gotNodes, (rand () % 2) == 0, rand () % 3), "GetNodeFat"); unexpected (gotNodes.size () < 1, "NodeSize"); unexpected (!destination.addRootNode (*gotNodes.begin (), snfWIRE, nullptr).isGood(), "AddRootNode"); nodeIDs.clear (); gotNodes.clear (); #ifdef SMS_DEBUG int bytes = 0; #endif do { f.clock().advance(std::chrono::seconds(1)); ++passes; hashes.clear (); // get the list of nodes we know we need destination.getMissingNodes (nodeIDs, hashes, 2048, nullptr); if (nodeIDs.empty ()) break; // get as many nodes as possible based on this information for (nodeIDIterator = nodeIDs.begin (); nodeIDIterator != nodeIDs.end (); ++nodeIDIterator) { if (!source.getNodeFat (*nodeIDIterator, gotNodeIDs, gotNodes, (rand () % 2) == 0, rand () % 3)) { fail ("GetNodeFat"); } else { pass (); } } assert (gotNodeIDs.size () == gotNodes.size ()); nodeIDs.clear (); hashes.clear (); if (gotNodeIDs.empty ()) { fail ("Got Node ID"); } else { pass (); } for (nodeIDIterator = gotNodeIDs.begin (), rawNodeIterator = gotNodes.begin (); nodeIDIterator != gotNodeIDs.end (); ++nodeIDIterator, ++rawNodeIterator) { ++nodes; #ifdef SMS_DEBUG bytes += rawNodeIterator->size (); #endif if (!destination.addKnownNode (*nodeIDIterator, *rawNodeIterator, nullptr).isGood ()) { fail ("AddKnownNode"); } else { pass (); } } gotNodeIDs.clear (); gotNodes.clear (); } while (true); destination.clearSynching (); #ifdef SMS_DEBUG log << "SYNCHING COMPLETE " << items << " items, " << nodes << " nodes, " << bytes / 1024 << " KB"; #endif if (!source.deepCompare (destination)) { fail ("Deep Compare"); } else { pass (); } #ifdef SMS_DEBUG log << "SHAMapSync test passed: " << items << " items, " << passes << " passes, " << nodes << " nodes"; #endif }