std::shared_ptr<Ledger> buildLedgerImpl( std::shared_ptr<Ledger const> const& parent, NetClock::time_point closeTime, const bool closeTimeCorrect, NetClock::duration closeResolution, Application& app, beast::Journal j, ApplyTxs&& applyTxs) { auto buildLCL = std::make_shared<Ledger>(*parent, closeTime); if (buildLCL->rules().enabled(featureSHAMapV2) && !buildLCL->stateMap().is_v2()) { buildLCL->make_v2(); } // Set up to write SHAMap changes to our database, // perform updates, extract changes { OpenView accum(&*buildLCL); assert(!accum.open()); applyTxs(accum, buildLCL); accum.apply(*buildLCL); } buildLCL->updateSkipList(); { // Write the final version of all modified SHAMap // nodes to the node store to preserve the new LCL int const asf = buildLCL->stateMap().flushDirty( hotACCOUNT_NODE, buildLCL->info().seq); int const tmf = buildLCL->txMap().flushDirty( hotTRANSACTION_NODE, buildLCL->info().seq); JLOG(j.debug()) << "Flushed " << asf << " accounts and " << tmf << " transaction nodes"; } buildLCL->unshare(); // Accept ledger buildLCL->setAccepted( closeTime, closeResolution, closeTimeCorrect, app.config()); return buildLCL; }
void testSkipList() { beast::Journal const j; std::vector<std::shared_ptr<Ledger>> history; { jtx::Env env(*this); Config config; auto prev = std::make_shared<Ledger>(create_genesis, config, env.app().family()); history.push_back(prev); for (auto i = 0; i < 1023; ++i) { auto next = std::make_shared<Ledger>( *prev, env.app().timeKeeper().closeTime()); next->updateSkipList(); history.push_back(next); prev = next; } } { auto l = *(std::next(std::begin(history))); expect((*std::begin(history))->info().seq < l->info().seq); expect(hashOfSeq(*l, l->info().seq + 1, j) == boost::none); expect(hashOfSeq(*l, l->info().seq, j) == l->info().hash); expect(hashOfSeq(*l, l->info().seq - 1, j) == l->info().parentHash); expect(hashOfSeq(*history.back(), l->info().seq, j) == boost::none); } // ledger skip lists store up to the previous 256 hashes for (auto i = history.crbegin(); i != history.crend(); i += 256) { for (auto n = i; n != std::next(i, (*i)->info().seq - 256 > 1 ? 257 : 256); ++n) { expect(hashOfSeq(**i, (*n)->info().seq, j) == (*n)->info().hash); } // edge case accessing beyond 256 expect(hashOfSeq(**i, (*i)->info().seq - 258, j) == boost::none); } // every 256th hash beyond the first 256 is stored for (auto i = history.crbegin(); i != std::next(history.crend(), -512); i += 256) { for (auto n = std::next(i, 512); n != history.crend(); n += 256) { expect(hashOfSeq(**i, (*n)->info().seq, j) == (*n)->info().hash); } } }