CCF
Loading...
Searching...
No Matches
historical_queries.h
Go to the documentation of this file.
1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the Apache 2.0 License.
3#pragma once
4
6#include "ccf/pal/locking.h"
8#include "ds/ccf_assert.h"
9#include "kv/store.h"
10#include "node/encryptor.h"
11#include "node/history.h"
12#include "node/ledger_secrets.h"
16
17#include <list>
18#include <map>
19#include <memory>
20#include <set>
21
22#ifdef ENABLE_HISTORICAL_VERBOSE_LOGGING
23# define HISTORICAL_LOG(...) LOG_INFO_FMT(__VA_ARGS__)
24#else
25# define HISTORICAL_LOG(...)
26#endif
27
28namespace ccf::historical
29{
30 enum class RequestNamespace : uint8_t
31 {
33 System,
34 };
35
36 using CompoundHandle = std::pair<RequestNamespace, RequestHandle>;
37};
38
39FMT_BEGIN_NAMESPACE
40template <>
42{
43 template <typename ParseContext>
44 constexpr auto parse(ParseContext& ctx)
45 {
46 return ctx.begin();
47 }
48
49 template <typename FormatContext>
50 auto format(
51 const ccf::historical::CompoundHandle& p, FormatContext& ctx) const
52 {
53 return format_to(
54 ctx.out(),
55 "[{}|{}]",
56 std::get<0>(p) == ccf::historical::RequestNamespace::Application ? "APP" :
57 "SYS",
58 std::get<1>(p));
59 }
60};
61FMT_END_NAMESPACE
62
63namespace ccf::historical
64{
65 static constexpr auto slow_fetch_threshold = std::chrono::milliseconds(1000);
66 static constexpr size_t soft_to_raw_ratio{5};
67
68 static std::optional<ccf::PrimarySignature> get_signature(
69 const ccf::kv::StorePtr& sig_store)
70 {
71 auto tx = sig_store->create_read_only_tx();
72 auto* signatures = tx.ro<ccf::Signatures>(ccf::Tables::SIGNATURES);
73 return signatures->get();
74 }
75
76 static std::optional<ccf::CoseSignature> get_cose_signature(
77 const ccf::kv::StorePtr& sig_store)
78 {
79 auto tx = sig_store->create_read_only_tx();
80 auto* signatures = tx.ro<ccf::CoseSignatures>(ccf::Tables::COSE_SIGNATURES);
81 return signatures->get();
82 }
83
84 static std::optional<std::vector<uint8_t>> get_tree(
85 const ccf::kv::StorePtr& sig_store)
86 {
87 auto tx = sig_store->create_read_only_tx();
88 auto* tree =
89 tx.ro<ccf::SerialisedMerkleTree>(ccf::Tables::SERIALISED_MERKLE_TREE);
90 return tree->get();
91 }
92
94 {
95 protected:
97 std::shared_ptr<ccf::LedgerSecrets> source_ledger_secrets;
99
100 std::shared_ptr<ccf::LedgerSecrets> historical_ledger_secrets;
101 std::shared_ptr<ccf::NodeEncryptor> historical_encryptor;
102
103 // whether to keep all the writes so that we can build a diff later
105
106 enum class StoreStage : uint8_t
107 {
108 Fetching,
109 Trusted,
110 };
111
112 using LedgerEntry = std::vector<uint8_t>;
113
115 {
116 if (earliest_secret_.secret == nullptr)
117 {
118 // Haven't worked out earliest known secret yet - work it out now
119 if (historical_ledger_secrets->is_empty())
120 {
122 !source_ledger_secrets->is_empty(),
123 "Source ledger secrets are empty");
125 }
126 else
127 {
130 historical_ledger_secrets->get_latest(tx).first <
131 source_ledger_secrets->get_first().first,
132 "Historical ledger secrets are not older than main ledger secrets");
133
135 }
136 }
137 }
138
140 {
141 std::chrono::milliseconds time_until_fetch = {};
146 bool is_signature = false;
150
152 {
153 if (store != nullptr)
154 {
155 auto e = store->get_encryptor();
156 return e->get_commit_nonce(
158 }
159
160 throw std::logic_error("Store pointer not set");
161 }
162
163 std::optional<std::string> get_commit_evidence()
164 {
166 {
167 return fmt::format(
168 "ce:{}.{}:{}",
171 ds::to_hex(get_commit_nonce()));
172 }
173
174 return std::nullopt;
175 }
176 };
177 using StoreDetailsPtr = std::shared_ptr<StoreDetails>;
178 using RequestedStores = std::map<ccf::SeqNo, StoreDetailsPtr>;
179
180 using WeakStoreDetailsPtr = std::weak_ptr<StoreDetails>;
181 using AllRequestedStores = std::map<ccf::SeqNo, WeakStoreDetailsPtr>;
182
184 {
187
188 VersionedSecret() = default;
189 // NB: Can't use VersionedLedgerSecret directly because the first element
190 // is const, so the whole thing is non-copyable
192 valid_from(vls.first),
193 secret(vls.second)
194 {}
195 };
196
199
200 struct Request
201 {
203
205 std::chrono::milliseconds time_to_expiry{};
206
207 bool include_receipts = false;
208
209 // Entries from outside the requested range (such as the next signature)
210 // may be needed to produce receipts. They are stored here, distinct from
211 // user-requested stores.
213
214 // Only set when recovering ledger secrets
215 std::optional<ccf::SeqNo> awaiting_ledger_secrets = std::nullopt;
216
217 Request(AllRequestedStores& all_stores_) : all_stores(all_stores_) {}
218
220 {
221 auto it = all_stores.find(seqno);
222 if (it != all_stores.end())
223 {
224 return it->second.lock();
225 }
226
227 return nullptr;
228 }
229
230 [[nodiscard]] ccf::SeqNo first_requested_seqno() const
231 {
232 if (!my_stores.empty())
233 {
234 return my_stores.begin()->first;
235 }
236
237 return {};
238 }
239
240 std::pair<std::vector<SeqNo>, std::vector<SeqNo>> adjust_ranges(
241 const SeqNoCollection& new_seqnos,
242 bool should_include_receipts,
243 SeqNo earliest_ledger_secret_seqno)
244 {
245 std::vector<SeqNo> removed{};
246 std::vector<SeqNo> added{};
247
248 // If a seqno is earlier than the earliest known ledger secret, we will
249 // store that it was requested with a nullptr in `my_stores`, but not
250 // add it to `all_stores` to begin fetching until a sufficiently early
251 // secret has been retrieved. To avoid awkwardly sharding requests (and
252 // delaying the secret-fetch with a large request for a later range), we
253 // extend that to say that if _any_ seqno is too early, then _all_
254 // subsequent seqnos will be pending. This bool tracks that behaviour.
255 bool any_too_early = false;
256
257 {
258 auto prev_it = my_stores.begin();
259 auto new_it = new_seqnos.begin();
260 while (new_it != new_seqnos.end())
261 {
262 if (prev_it != my_stores.end() && *new_it == prev_it->first)
263 {
264 // Asking for a seqno which was also requested previously - do
265 // nothing and advance to compare next entries
266 ++new_it;
267 ++prev_it;
268 }
269 else if (prev_it != my_stores.end() && *new_it > prev_it->first)
270 {
271 // No longer looking for a seqno which was previously requested.
272 // Remove it from my_stores
273 removed.push_back(prev_it->first);
274 prev_it = my_stores.erase(prev_it);
275 }
276 else
277 {
278 // *new_it < prev_it->first
279 // Asking for a seqno which was not previously being fetched =>
280 // check if another request was fetching it, else create new
281 // details to track it
282 if (*new_it < earliest_ledger_secret_seqno || any_too_early)
283 {
284 // If this is too early for known secrets, just record that it
285 // was requested but don't add it to all_stores yet
286 added.push_back(*new_it);
287 prev_it = my_stores.insert_or_assign(prev_it, *new_it, nullptr);
288 any_too_early = true;
289 }
290 else
291 {
292 auto all_it = all_stores.find(*new_it);
293 auto details =
294 all_it == all_stores.end() ? nullptr : all_it->second.lock();
295 if (details == nullptr)
296 {
297 HISTORICAL_LOG("{} is newly requested", *new_it);
298 details = std::make_shared<StoreDetails>();
299 all_stores.insert_or_assign(all_it, *new_it, details);
300 }
301 added.push_back(*new_it);
302 prev_it = my_stores.insert_or_assign(prev_it, *new_it, details);
303 }
304 }
305 }
306
307 if (prev_it != my_stores.end())
308 {
309 // If we have a suffix of seqnos previously requested, now
310 // unrequested, purge them
311 for (auto it = prev_it; it != my_stores.end(); ++it)
312 {
313 removed.push_back(it->first);
314 }
315 my_stores.erase(prev_it, my_stores.end());
316 }
317 }
318
319 const bool any_diff = !removed.empty() || !added.empty();
320
321 if (!any_diff && (should_include_receipts == include_receipts))
322 {
323 HISTORICAL_LOG("Identical to previous request");
324 return {removed, added};
325 }
326
327 include_receipts = should_include_receipts;
328
330 "Clearing {} supporting signatures", supporting_signatures.size());
331 supporting_signatures.clear();
332 if (should_include_receipts)
333 {
334 // If requesting signatures, populate receipts for each entry that we
335 // already have. Normally this would be done when each entry was
336 // received, but in the case that we have the entries already and only
337 // request signatures now, we delay that work to now.
338
339 for (auto seqno : new_seqnos)
340 {
342 }
343 }
344 return {removed, added};
345 }
346
348 {
350 "Looking at {}, and populating receipts from it", new_seqno);
351 auto new_details = get_store_details(new_seqno);
352 if (new_details != nullptr && new_details->store != nullptr)
353 {
354 if (new_details->is_signature)
355 {
356 HISTORICAL_LOG("{} is a signature", new_seqno);
357
358 fill_receipts_from_signature(new_details);
359 }
360 else
361 {
362 // This isn't a signature. To find the signature for this, we look
363 // through every subsequent transaction, until we find either a gap
364 // (a seqno that hasn't been fetched yet), or a signature. If it is
365 // a signature, and we've found a contiguous range of seqnos to it,
366 // then it must be a signature over this seqno. Else we find a gap
367 // first, and fetch it in case it is the signature. It's possible
368 // that we already have the later signature, and wastefully fill in
369 // the gaps, but this reduces the cases we have to consider so makes
370 // the code much simpler.
371
372 HISTORICAL_LOG("{} is not a signature", new_seqno);
373 supporting_signatures.erase(new_seqno);
374
375 auto next_seqno = new_seqno + 1;
376 while (true)
377 {
378 auto all_it = all_stores.find(next_seqno);
379 auto details =
380 all_it == all_stores.end() ? nullptr : all_it->second.lock();
381 if (details == nullptr)
382 {
384 "Looking for new supporting signature at {}", next_seqno);
385 details = std::make_shared<StoreDetails>();
386 all_stores.insert_or_assign(all_it, next_seqno, details);
387 }
388
389 if (details->store == nullptr)
390 {
391 // Whether we just started fetching or someone else was already
392 // looking for this, it's the first gap we've found so _may_ be
393 // our signature
395 "Assigning {} as potential signature for {}",
396 next_seqno,
397 new_seqno);
398 supporting_signatures[next_seqno] = details;
399 return;
400 }
401
402 if (details->is_signature)
403 {
404 const auto filled_this =
405 fill_receipts_from_signature(details, new_seqno);
406
407 if (
408 !filled_this && my_stores.find(new_seqno) != my_stores.end())
409 {
410 throw std::logic_error(fmt::format(
411 "Unexpected: Found a signature at {}, and contiguous range "
412 "of transactions from {}, yet signature does not cover "
413 "this seqno!",
414 next_seqno,
415 new_seqno));
416 }
417
418 return;
419 }
420
421 // This is a normal transaction, and its already fetched.
422 // Nothing to do, consider the next.
423 ++next_seqno;
424 }
425 }
426 }
427 }
428
429 private:
430 bool fill_receipts_from_signature(
431 const std::shared_ptr<StoreDetails>& sig_details,
432 std::optional<ccf::SeqNo> should_fill = std::nullopt)
433 {
434 // Iterate through earlier indices. If this signature covers them
435 // then create a receipt for them
436 const auto sig = get_signature(sig_details->store);
437 if (!sig.has_value())
438 {
439 return false;
440 }
441 const auto cose_sig = get_cose_signature(sig_details->store);
442 const auto serialised_tree = get_tree(sig_details->store);
443 if (!serialised_tree.has_value())
444 {
445 return false;
446 }
447 ccf::MerkleTreeHistory tree(serialised_tree.value());
448
449 // This is either pointing at the sig itself, or the closest larger
450 // seqno we're holding
451 auto sig_lower_bound_it =
452 my_stores.lower_bound(sig_details->transaction_id.seqno);
453
454 if (sig_lower_bound_it != my_stores.begin()) // Skip empty map edge case
455 {
456 // Construct reverse iterator to search backwards from here
457 auto search_rit = std::reverse_iterator(sig_lower_bound_it);
458 while (search_rit != my_stores.rend())
459 {
460 auto seqno = search_rit->first;
461 if (tree.in_range(seqno))
462 {
463 auto details = search_rit->second;
464 if (details != nullptr && details->store != nullptr)
465 {
466 auto proof = tree.get_proof(seqno);
467 details->transaction_id = {sig->view, seqno};
468 details->receipt = std::make_shared<TxReceiptImpl>(
469 sig->sig,
470 cose_sig,
471 proof.get_root(),
472 proof.get_path(),
473 sig->node,
474 sig->cert,
475 details->entry_digest,
476 details->get_commit_evidence(),
477 details->claims_digest);
479 "Assigned a receipt for {} after given signature at {}",
480 seqno,
481 sig_details->transaction_id.to_str());
482
483 if (should_fill.has_value() && seqno == *should_fill)
484 {
485 should_fill.reset();
486 }
487 }
488
489 ++search_rit;
490 }
491 else
492 {
493 // Found a seqno which this signature doesn't cover. It can't
494 // cover anything else, so break here
495 break;
496 }
497 }
498 }
499
500 return !should_fill.has_value();
501 }
502 };
503
504 // Guard all access to internal state with this lock
506
507 // Track all things currently requested by external callers
508 std::map<CompoundHandle, Request> requests;
509
510 // A map containing (weak pointers to) _all_ of the stores for active
511 // requests, allowing distinct requests for the same seqnos to share the
512 // same underlying state (and benefit from faster lookup)
514
515 ExpiryDuration default_expiry_duration = std::chrono::seconds(1800);
516
517 // These two combine into an effective O(log(N)) lookup/add/remove by
518 // handle.
519 std::list<CompoundHandle> lru_requests;
520 std::map<CompoundHandle, std::list<CompoundHandle>::iterator> lru_lookup;
521
522 // To maintain the estimated size consumed by all requests. Gets updated
523 // when ledger entries are fetched, and when requests are dropped.
524 std::unordered_map<SeqNo, std::set<CompoundHandle>> store_to_requests;
525 std::unordered_map<ccf::SeqNo, size_t> raw_store_sizes;
526
527 CacheSize soft_store_cache_limit{std::numeric_limits<size_t>::max()};
529 soft_store_cache_limit / soft_to_raw_ratio;
531
533 {
534 auto it = store_to_requests.find(seq);
535
536 if (it == store_to_requests.end())
537 {
538 store_to_requests.insert({seq, {handle}});
539 auto size = raw_store_sizes.find(seq);
540 if (size != raw_store_sizes.end())
541 {
542 estimated_store_cache_size += size->second;
543 }
544 }
545 else
546 {
547 it->second.insert(handle);
548 }
549 }
550
552 {
553 for (const auto& [seq, _] : requests.at(handle).my_stores)
554 {
555 add_request_ref(seq, handle);
556 }
557 }
558
560 {
561 auto it = store_to_requests.find(seq);
562 assert(it != store_to_requests.end());
563
564 it->second.erase(handle);
565 if (it->second.empty())
566 {
567 store_to_requests.erase(it);
568 auto size = raw_store_sizes.find(seq);
569 if (size != raw_store_sizes.end())
570 {
571 estimated_store_cache_size -= size->second;
572 raw_store_sizes.erase(size);
573 }
574 }
575 }
576
578 {
579 for (const auto& [seq, _] : requests.at(handle).my_stores)
580 {
581 remove_request_ref(seq, handle);
582 }
583 }
584
586 {
587 auto it = lru_lookup.find(handle);
588 if (it != lru_lookup.end())
589 {
590 lru_requests.erase(it->second);
591 it->second = lru_requests.insert(lru_requests.begin(), handle);
592 }
593 else
594 {
595 lru_lookup[handle] = lru_requests.insert(lru_requests.begin(), handle);
596 add_request_refs(handle);
597 }
598 }
599
600 void lru_shrink_to_fit(size_t threshold)
601 {
602 while (estimated_store_cache_size > threshold)
603 {
604 if (lru_requests.empty())
605 {
607 "LRU shrink to {} requested but cache is already empty", threshold);
608 return;
609 }
610
611 const auto handle = lru_requests.back();
613 "Cache size shrinking (reached {} / {}). Dropping {}",
615 threshold,
616 handle);
617
618 remove_request_refs(handle);
619 lru_lookup.erase(handle);
620
621 requests.erase(handle);
622 lru_requests.pop_back();
623 }
624 }
625
627 {
628 auto it = lru_lookup.find(handle);
629 if (it != lru_lookup.end())
630 {
631 remove_request_refs(handle);
632 lru_requests.erase(it->second);
633 lru_lookup.erase(it);
634 }
635 }
636
637 void update_store_raw_size(SeqNo seq, size_t new_size)
638 {
639 auto& stored_size = raw_store_sizes[seq];
640 assert(!stored_size || stored_size == new_size);
641
642 estimated_store_cache_size -= stored_size;
643 estimated_store_cache_size += new_size;
644 stored_size = new_size;
645 }
646
651
653 {
654 LOG_TRACE_FMT("fetch_entries_range({}, {})", from, to);
655
657 ::consensus::ledger_get_range,
658 to_host,
659 static_cast<::consensus::Index>(from),
660 static_cast<::consensus::Index>(to),
662 }
663
664 std::optional<ccf::SeqNo> fetch_supporting_secret_if_needed(
666 {
667 auto [earliest_ledger_secret_seqno, earliest_ledger_secret] =
670 earliest_ledger_secret != nullptr,
671 "Can't fetch without knowing earliest");
672
673 const auto too_early = seqno < earliest_ledger_secret_seqno;
674
675 auto previous_secret_stored_version =
676 earliest_ledger_secret->previous_secret_stored_version;
677 const auto is_next_secret =
678 previous_secret_stored_version.value_or(0) == seqno;
679
680 if (too_early || is_next_secret)
681 {
682 // Still need more secrets, fetch the next
683 if (!previous_secret_stored_version.has_value())
684 {
685 throw std::logic_error(fmt::format(
686 "Earliest known ledger secret at {} has no earlier secret stored "
687 "version ({})",
688 earliest_ledger_secret_seqno,
689 seqno));
690 }
691
692 const auto seqno_to_fetch = previous_secret_stored_version.value();
694 "Requesting historical entry at {} but first known ledger "
695 "secret is applicable from {}",
696 seqno,
697 earliest_ledger_secret_seqno);
698
699 auto it = all_stores.find(seqno_to_fetch);
700 auto details = it == all_stores.end() ? nullptr : it->second.lock();
701 if (details == nullptr)
702 {
703 LOG_TRACE_FMT("Requesting older secret at {} now", seqno_to_fetch);
704 details = std::make_shared<StoreDetails>();
705 all_stores.insert_or_assign(it, seqno_to_fetch, details);
706 fetch_entry_at(seqno_to_fetch);
707 }
708
709 next_secret_fetch_handle = details;
710
711 if (too_early)
712 {
713 return seqno_to_fetch;
714 }
715 }
716
717 return std::nullopt;
718 }
719
721 const StoreDetailsPtr& details,
722 const ccf::kv::StorePtr& store,
723 const ccf::crypto::Sha256Hash& entry_digest,
725 bool is_signature,
726 ccf::ClaimsDigest&& claims_digest,
727 bool has_commit_evidence)
728 {
729 // Deserialisation includes a GCM integrity check, so all entries
730 // have been verified by the time we get here.
731 details->current_stage = StoreStage::Trusted;
732 details->has_commit_evidence = has_commit_evidence;
733
734 details->entry_digest = entry_digest;
735 if (!claims_digest.empty())
736 {
737 details->claims_digest = std::move(claims_digest);
738 }
739
741 details->store == nullptr,
742 "Cache already has store for seqno {}",
743 seqno);
744 details->store = store;
745
746 details->is_signature = is_signature;
747 if (is_signature)
748 {
749 // Construct a signature receipt.
750 // We do this whether it was requested or not, because we have all
751 // the state to do so already, and it's simpler than constructing
752 // the receipt _later_ for an already-fetched signature
753 // transaction.
754 const auto sig = get_signature(details->store);
755 const auto cose_sig = get_cose_signature(details->store);
756 if (sig.has_value())
757 {
758 details->transaction_id = {sig->view, sig->seqno};
759 details->receipt = std::make_shared<TxReceiptImpl>(
760 sig->sig, cose_sig, sig->root.h, nullptr, sig->node, sig->cert);
761 }
762 }
763
764 auto request_it = requests.begin();
765 while (request_it != requests.end())
766 {
767 auto& [handle, request] = *request_it;
768
769 // If this request was still waiting for a ledger secret, and this is
770 // that secret
771 if (
772 request.awaiting_ledger_secrets.has_value() &&
773 request.awaiting_ledger_secrets.value() == seqno)
774 {
776 "{} is a ledger secret seqno this request was waiting for", seqno);
777
778 request.awaiting_ledger_secrets =
779 fetch_supporting_secret_if_needed(request.first_requested_seqno());
780 if (!request.awaiting_ledger_secrets.has_value())
781 {
782 // Newly have all required secrets - begin fetching the actual
783 // entries. Note this is adding them to `all_stores`, from where
784 // they'll be requested on the next tick.
785 auto my_stores_it = request.my_stores.begin();
786 while (my_stores_it != request.my_stores.end())
787 {
788 auto [store_seqno, _] = *my_stores_it;
789 auto it = all_stores.find(store_seqno);
790 auto store_details =
791 it == all_stores.end() ? nullptr : it->second.lock();
792
793 if (store_details == nullptr)
794 {
795 store_details = std::make_shared<StoreDetails>();
796 all_stores.insert_or_assign(it, store_seqno, store_details);
797 }
798
799 my_stores_it->second = store_details;
800 ++my_stores_it;
801 }
802 }
803
804 // In either case, done with this request, try the next
805 ++request_it;
806 continue;
807 }
808
809 if (request.include_receipts)
810 {
811 const bool seqno_in_this_request =
812 (request.my_stores.find(seqno) != request.my_stores.end() ||
813 request.supporting_signatures.find(seqno) !=
814 request.supporting_signatures.end());
815 if (seqno_in_this_request)
816 {
817 request.populate_receipts(seqno);
818 }
819 }
820
821 ++request_it;
822 }
823 }
824
826 const ccf::kv::StorePtr& store, LedgerSecretPtr encrypting_secret)
827 {
828 // Read encrypted secrets from store
829 auto tx = store->create_read_only_tx();
830 auto* encrypted_past_ledger_secret_handle =
832 ccf::Tables::ENCRYPTED_PAST_LEDGER_SECRET);
833 if (encrypted_past_ledger_secret_handle == nullptr)
834 {
835 return false;
836 }
837
838 auto encrypted_past_ledger_secret =
839 encrypted_past_ledger_secret_handle->get();
840 if (!encrypted_past_ledger_secret.has_value())
841 {
842 return false;
843 }
844
845 // Construct description and decrypted secret
846 auto previous_ledger_secret =
847 encrypted_past_ledger_secret->previous_ledger_secret;
848 if (!previous_ledger_secret.has_value())
849 {
850 // The only write to this table that should not contain a previous
851 // secret is the initial service open
853 encrypted_past_ledger_secret->next_version.has_value() &&
854 encrypted_past_ledger_secret->next_version.value() == 1,
855 "Write to ledger secrets table at {} should contain a next_version "
856 "of 1",
857 store->current_version());
858 return true;
859 }
860
861 auto recovered_ledger_secret = std::make_shared<LedgerSecret>(
863 encrypting_secret, previous_ledger_secret->encrypted_data),
864 previous_ledger_secret->previous_secret_stored_version);
865
866 // Add recovered secret to historical secrets
867 historical_ledger_secrets->set_secret(
868 previous_ledger_secret->version, std::move(recovered_ledger_secret));
869
870 // Update earliest_secret
872 previous_ledger_secret->version < earliest_secret_.valid_from, "");
874
875 return true;
876 }
877
879 ccf::SeqNo start_seqno, ccf::SeqNo end_seqno)
880 {
881 if (end_seqno < start_seqno)
882 {
883 throw std::logic_error(fmt::format(
884 "Invalid range for historical query: end {} is before start {}",
885 end_seqno,
886 start_seqno));
887 }
888
889 SeqNoCollection c(start_seqno, end_seqno - start_seqno);
890 return c;
891 }
892
893 std::vector<StatePtr> get_states_internal(
894 const CompoundHandle& handle,
895 const SeqNoCollection& seqnos,
896 ExpiryDuration seconds_until_expiry,
897 bool include_receipts)
898 {
899 if (seqnos.empty())
900 {
901 throw std::logic_error(
902 "Invalid range for historical query: Cannot request empty range");
903 }
904
905 std::lock_guard<ccf::pal::Mutex> guard(requests_lock);
906
907 const auto ms_until_expiry =
908 std::chrono::duration_cast<std::chrono::milliseconds>(
909 seconds_until_expiry);
910
911 auto it = requests.find(handle);
912 if (it == requests.end())
913 {
914 // This is a new handle - insert a newly created Request for it
915 it = requests.emplace_hint(it, handle, Request(all_stores));
916 HISTORICAL_LOG("First time I've seen handle {}", handle);
917 }
918
919 lru_promote(handle);
920
921 Request& request = it->second;
922
924
925 // Update this Request to represent the currently requested ranges
927 "Adjusting handle {} to cover {} seqnos starting at {} "
928 "(include_receipts={})",
929 handle,
930 seqnos.size(),
931 *seqnos.begin(),
932 include_receipts);
933 auto [removed, added] = request.adjust_ranges(
934 seqnos, include_receipts, earliest_secret_.valid_from);
935
936 for (auto seq : removed)
937 {
938 remove_request_ref(seq, handle);
939 }
940 for (auto seq : added)
941 {
942 add_request_ref(seq, handle);
943 }
944
945 // If the earliest target entry cannot be deserialised with the earliest
946 // known ledger secret, record the target seqno and begin fetching the
947 // previous historical ledger secret.
950
951 // Reset the expiry timer as this has just been requested
952 request.time_to_expiry = ms_until_expiry;
953
954 std::vector<StatePtr> trusted_states;
955
956 for (auto seqno : seqnos)
957 {
958 auto target_details = request.get_store_details(seqno);
959 if (
960 target_details != nullptr &&
961 target_details->current_stage == StoreStage::Trusted &&
962 (!request.include_receipts || target_details->receipt != nullptr))
963 {
964 // Have this store, associated txid and receipt and trust it - add
965 // it to return list
966 StatePtr state = std::make_shared<State>(
967 target_details->store,
968 target_details->receipt,
969 target_details->transaction_id);
970 trusted_states.push_back(state);
971 }
972 else
973 {
974 // Still fetching this store or don't trust it yet, so range is
975 // incomplete - return empty vector
976 return {};
977 }
978 }
979
980 return trusted_states;
981 }
982
983 // Used when we received an invalid entry, to drop any requests which were
984 // asking for it
986 {
987 auto request_it = requests.begin();
988 while (request_it != requests.end())
989 {
990 if (request_it->second.get_store_details(seqno) != nullptr)
991 {
992 lru_evict(request_it->first);
993 request_it = requests.erase(request_it);
994 }
995 else
996 {
997 ++request_it;
998 }
999 }
1000 }
1001
1002 std::vector<ccf::kv::ReadOnlyStorePtr> states_to_stores(
1003 const std::vector<StatePtr>& states)
1004 {
1005 std::vector<ccf::kv::ReadOnlyStorePtr> stores;
1006 stores.reserve(states.size());
1007 for (const auto& state : states)
1008 {
1009 stores.push_back(state->store);
1010 }
1011 return stores;
1012 }
1013
1014 public:
1016 ccf::kv::Store& store,
1017 const std::shared_ptr<ccf::LedgerSecrets>& secrets,
1018 ringbuffer::WriterPtr host_writer) :
1019 source_store(store),
1020 source_ledger_secrets(secrets),
1021 to_host(std::move(host_writer)),
1025 {}
1026
1028 const CompoundHandle& handle,
1030 ExpiryDuration seconds_until_expiry)
1031 {
1032 auto range = get_store_range(handle, seqno, seqno, seconds_until_expiry);
1033 if (range.empty())
1034 {
1035 return nullptr;
1036 }
1037
1038 return range[0];
1039 }
1040
1046
1048 const CompoundHandle& handle,
1050 ExpiryDuration seconds_until_expiry)
1051 {
1052 auto range = get_state_range(handle, seqno, seqno, seconds_until_expiry);
1053 if (range.empty())
1054 {
1055 return nullptr;
1056 }
1057
1058 return range[0];
1059 }
1060
1065
1066 std::vector<ccf::kv::ReadOnlyStorePtr> get_store_range(
1067 const CompoundHandle& handle,
1068 ccf::SeqNo start_seqno,
1069 ccf::SeqNo end_seqno,
1070 ExpiryDuration seconds_until_expiry)
1071 {
1073 handle,
1074 collection_from_single_range(start_seqno, end_seqno),
1075 seconds_until_expiry,
1076 false));
1077 }
1078
1079 std::vector<ccf::kv::ReadOnlyStorePtr> get_store_range(
1080 const CompoundHandle& handle,
1081 ccf::SeqNo start_seqno,
1082 ccf::SeqNo end_seqno)
1083 {
1084 return get_store_range(
1085 handle, start_seqno, end_seqno, default_expiry_duration);
1086 }
1087
1088 std::vector<StatePtr> get_state_range(
1089 const CompoundHandle& handle,
1090 ccf::SeqNo start_seqno,
1091 ccf::SeqNo end_seqno,
1092 ExpiryDuration seconds_until_expiry)
1093 {
1094 return get_states_internal(
1095 handle,
1096 collection_from_single_range(start_seqno, end_seqno),
1097 seconds_until_expiry,
1098 true);
1099 }
1100
1101 std::vector<StatePtr> get_state_range(
1102 const CompoundHandle& handle,
1103 ccf::SeqNo start_seqno,
1104 ccf::SeqNo end_seqno)
1105 {
1106 return get_state_range(
1107 handle, start_seqno, end_seqno, default_expiry_duration);
1108 }
1109
1110 std::vector<ccf::kv::ReadOnlyStorePtr> get_stores_for(
1111 const CompoundHandle& handle,
1112 const SeqNoCollection& seqnos,
1113 ExpiryDuration seconds_until_expiry)
1114 {
1115 return states_to_stores(
1116 get_states_internal(handle, seqnos, seconds_until_expiry, false));
1117 }
1118
1119 std::vector<ccf::kv::ReadOnlyStorePtr> get_stores_for(
1120 const CompoundHandle& handle, const SeqNoCollection& seqnos)
1121 {
1122 return get_stores_for(handle, seqnos, default_expiry_duration);
1123 }
1124
1125 std::vector<StatePtr> get_states_for(
1126 const CompoundHandle& handle,
1127 const SeqNoCollection& seqnos,
1128 ExpiryDuration seconds_until_expiry)
1129 {
1130 if (seqnos.empty())
1131 {
1132 throw std::runtime_error("Cannot request empty range");
1133 }
1134 return get_states_internal(handle, seqnos, seconds_until_expiry, true);
1135 }
1136
1137 std::vector<StatePtr> get_states_for(
1138 const CompoundHandle& handle, const SeqNoCollection& seqnos)
1139 {
1140 return get_states_for(handle, seqnos, default_expiry_duration);
1141 }
1142
1144 {
1145 default_expiry_duration = duration;
1146 }
1147
1149 {
1150 soft_store_cache_limit = cache_limit;
1152 }
1153
1155 {
1157 }
1158
1160 {
1161 std::lock_guard<ccf::pal::Mutex> guard(requests_lock);
1162 lru_evict(handle);
1163 const auto erased_count = requests.erase(handle);
1164 return erased_count > 0;
1165 }
1166
1167 bool handle_ledger_entry(ccf::SeqNo seqno, const std::vector<uint8_t>& data)
1168 {
1169 return handle_ledger_entry(seqno, data.data(), data.size());
1170 }
1171
1172 bool handle_ledger_entry(ccf::SeqNo seqno, const uint8_t* data, size_t size)
1173 {
1174 std::lock_guard<ccf::pal::Mutex> guard(requests_lock);
1175 const auto it = all_stores.find(seqno);
1176 auto details = it == all_stores.end() ? nullptr : it->second.lock();
1177 if (details == nullptr || details->current_stage != StoreStage::Fetching)
1178 {
1179 // Unexpected entry, we already have it or weren't asking for it -
1180 // ignore this resubmission
1181 return false;
1182 }
1183
1185 ccf::ClaimsDigest claims_digest;
1186 bool has_commit_evidence = false;
1187 auto store = deserialise_ledger_entry(
1188 seqno,
1189 data,
1190 size,
1191 deserialise_result,
1192 claims_digest,
1193 has_commit_evidence);
1194
1195 if (deserialise_result == ccf::kv::ApplyResult::FAIL)
1196 {
1197 return false;
1198 }
1199
1200 {
1201 // Confirm this entry is from a precursor of the current state, and not
1202 // a fork
1203 const auto tx_id = store->current_txid();
1204 if (tx_id.seqno != seqno)
1205 {
1207 "Corrupt ledger entry received - claims to be {} but is actually "
1208 "{}.{}",
1209 seqno,
1210 tx_id.view,
1211 tx_id.seqno);
1212 return false;
1213 }
1214
1216 if (consensus == nullptr)
1217 {
1218 LOG_FAIL_FMT("No consensus on source store");
1219 return false;
1220 }
1221
1222 const auto actual_view = consensus->get_view(seqno);
1223 if (actual_view != tx_id.view)
1224 {
1226 "Ledger entry comes from fork - contains {}.{} but this service "
1227 "expected {}.{}",
1228 tx_id.view,
1229 tx_id.seqno,
1230 actual_view,
1231 seqno);
1232 return false;
1233 }
1234 }
1235
1236 const auto is_signature =
1237 deserialise_result == ccf::kv::ApplyResult::PASS_SIGNATURE;
1238
1240
1241 auto [valid_from, secret] = earliest_secret_;
1242
1243 if (secret != nullptr)
1244 {
1245 const auto& prev_version = secret->previous_secret_stored_version;
1246 if (prev_version.has_value() && *prev_version == seqno)
1247 {
1249 "Handling past ledger secret. Current earliest is valid from {}, "
1250 "now "
1251 "processing secret stored at {}",
1252 valid_from,
1253 seqno);
1255 next_secret_fetch_handle = nullptr;
1256 }
1257 }
1258
1260 "Processing historical store at {} ({})",
1261 seqno,
1262 (size_t)deserialise_result);
1263 const auto entry_digest = ccf::crypto::Sha256Hash({data, size});
1265 details,
1266 store,
1267 entry_digest,
1268 seqno,
1269 is_signature,
1270 std::move(claims_digest),
1271 has_commit_evidence);
1272
1274 return true;
1275 }
1276
1278 ccf::SeqNo from_seqno, ccf::SeqNo to_seqno, const LedgerEntry& data)
1279 {
1280 return handle_ledger_entries(
1281 from_seqno, to_seqno, data.data(), data.size());
1282 }
1283
1285 ccf::SeqNo from_seqno,
1286 ccf::SeqNo to_seqno,
1287 const uint8_t* data,
1288 size_t size)
1289 {
1290 LOG_TRACE_FMT("handle_ledger_entries({}, {})", from_seqno, to_seqno);
1291
1292 auto seqno = from_seqno;
1293 bool all_accepted = true;
1294 while (size > 0)
1295 {
1296 const auto header =
1297 serialized::peek<ccf::kv::SerialisedEntryHeader>(data, size);
1298 const auto whole_size =
1299 header.size + ccf::kv::serialised_entry_header_size;
1300 all_accepted &= handle_ledger_entry(seqno, data, whole_size);
1301 data += whole_size;
1302 size -= whole_size;
1303 ++seqno;
1304 }
1305
1306 if (seqno != to_seqno + 1)
1307 {
1309 "Claimed ledger entries: [{}, {}), actual [{}, {}]",
1310 from_seqno,
1311 to_seqno,
1312 from_seqno,
1313 seqno);
1314 }
1315
1316 return all_accepted;
1317 }
1318
1323
1325 {
1326 std::lock_guard<ccf::pal::Mutex> guard(requests_lock);
1327
1328 LOG_TRACE_FMT("handle_no_entry_range({}, {})", from_seqno, to_seqno);
1329
1330 for (auto seqno = from_seqno; seqno <= to_seqno; ++seqno)
1331 {
1332 // The host failed or refused to give this entry. Currently just
1333 // forget about it and drop any requests which were looking for it -
1334 // don't have a mechanism for remembering this failure and reporting it
1335 // to users.
1336 const auto fetches_it = all_stores.find(seqno);
1337 if (fetches_it != all_stores.end())
1338 {
1340
1341 all_stores.erase(fetches_it);
1342 }
1343 }
1344 }
1345
1348 const uint8_t* data,
1349 size_t size,
1350 ccf::kv::ApplyResult& result,
1351 ccf::ClaimsDigest& claims_digest,
1352 bool& has_commit_evidence)
1353 {
1354 // Create a new store and try to deserialise this entry into it
1355 ccf::kv::StorePtr store = std::make_shared<ccf::kv::Store>(
1356 false /* Do not start from very first seqno */,
1357 true /* Make use of historical secrets */);
1358
1359 // If this is older than the node's currently known ledger secrets, use
1360 // the historical encryptor (which should have older secrets)
1361 if (seqno < source_ledger_secrets->get_first().first)
1362 {
1363 store->set_encryptor(historical_encryptor);
1364 }
1365 else
1366 {
1367 store->set_encryptor(source_store.get_encryptor());
1368 }
1369
1370 try
1371 {
1372 // Encrypted ledger secrets are deserialised in public-only mode. Their
1373 // Merkle tree integrity is not verified: even if the recovered ledger
1374 // secret was bogus, the deserialisation of subsequent ledger entries
1375 // would fail.
1376 bool public_only = false;
1377 for (const auto& [_, request] : requests)
1378 {
1379 const auto& als = request.awaiting_ledger_secrets;
1380 if (als.has_value() && als.value() == seqno)
1381 {
1382 public_only = true;
1383 break;
1384 }
1385 }
1386
1387 auto exec = store->deserialize({data, data + size}, public_only);
1388 if (exec == nullptr)
1389 {
1391 return nullptr;
1392 }
1393
1394 result = exec->apply(track_deletes_on_missing_keys_v);
1395 claims_digest = std::move(exec->consume_claims_digest());
1396
1397 auto commit_evidence_digest =
1398 std::move(exec->consume_commit_evidence_digest());
1399 has_commit_evidence = commit_evidence_digest.has_value();
1400 }
1401 catch (const std::exception& e)
1402 {
1404 "Exception while attempting to deserialise entry {}: {}",
1405 seqno,
1406 e.what());
1408 }
1409
1410 return store;
1411 }
1412
1414 {
1415 std::lock_guard<ccf::pal::Mutex> guard(requests_lock);
1417 }
1418
1419 void tick(const std::chrono::milliseconds& elapsed_ms)
1420 {
1421 std::lock_guard<ccf::pal::Mutex> guard(requests_lock);
1422
1423 {
1424 auto it = requests.begin();
1425 while (it != requests.end())
1426 {
1427 auto& request = it->second;
1428 if (elapsed_ms >= request.time_to_expiry)
1429 {
1431 "Dropping expired historical query with handle {}", it->first);
1432 lru_evict(it->first);
1433 it = requests.erase(it);
1434 }
1435 else
1436 {
1437 request.time_to_expiry -= elapsed_ms;
1438 ++it;
1439 }
1440 }
1441 }
1442
1444
1445 {
1446 auto it = all_stores.begin();
1447 std::optional<std::pair<ccf::SeqNo, ccf::SeqNo>> range_to_request =
1448 std::nullopt;
1449 while (it != all_stores.end())
1450 {
1451 auto details = it->second.lock();
1452 if (details == nullptr)
1453 {
1454 it = all_stores.erase(it);
1455 }
1456 else
1457 {
1458 if (details->current_stage == StoreStage::Fetching)
1459 {
1460 details->time_until_fetch -= elapsed_ms;
1461 if (details->time_until_fetch.count() <= 0)
1462 {
1463 details->time_until_fetch = slow_fetch_threshold;
1464
1465 const auto seqno = it->first;
1466 if (auto range_val = range_to_request; range_val.has_value())
1467 {
1468 auto range = range_val.value();
1469 if (range.second + 1 == seqno)
1470 {
1471 range.second = seqno;
1472 range_to_request = range;
1473 }
1474 else
1475 {
1476 // Submit fetch for previously tracked range
1477 fetch_entries_range(range.first, range.second);
1478 // Track new range
1479 range_to_request = std::make_pair(seqno, seqno);
1480 }
1481 }
1482 else
1483 {
1484 // Track new range
1485 range_to_request = std::make_pair(seqno, seqno);
1486 }
1487 }
1488 }
1489
1490 ++it;
1491 }
1492 }
1493
1494 if (auto range_val = range_to_request; range_val.has_value())
1495 {
1496 // Submit fetch for final tracked range
1497 auto range = range_val.value();
1498 fetch_entries_range(range.first, range.second);
1499 }
1500 }
1501 }
1502 };
1503
1505 {
1506 protected:
1511
1512 public:
1513 template <typename... Ts>
1514 StateCache(Ts&&... ts) : StateCacheImpl(std::forward<Ts>(ts)...)
1515 {}
1516
1518 RequestHandle handle,
1520 ExpiryDuration seconds_until_expiry) override
1521 {
1523 make_compound_handle(handle), seqno, seconds_until_expiry);
1524 }
1525
1531
1533 RequestHandle handle,
1535 ExpiryDuration seconds_until_expiry) override
1536 {
1538 make_compound_handle(handle), seqno, seconds_until_expiry);
1539 }
1540
1545
1546 std::vector<ccf::kv::ReadOnlyStorePtr> get_store_range(
1547 RequestHandle handle,
1548 ccf::SeqNo start_seqno,
1549 ccf::SeqNo end_seqno,
1550 ExpiryDuration seconds_until_expiry) override
1551 {
1553 make_compound_handle(handle),
1554 start_seqno,
1555 end_seqno,
1556 seconds_until_expiry);
1557 }
1558
1559 std::vector<ccf::kv::ReadOnlyStorePtr> get_store_range(
1560 RequestHandle handle,
1561 ccf::SeqNo start_seqno,
1562 ccf::SeqNo end_seqno) override
1563 {
1565 make_compound_handle(handle), start_seqno, end_seqno);
1566 }
1567
1568 std::vector<StatePtr> get_state_range(
1569 RequestHandle handle,
1570 ccf::SeqNo start_seqno,
1571 ccf::SeqNo end_seqno,
1572 ExpiryDuration seconds_until_expiry) override
1573 {
1575 make_compound_handle(handle),
1576 start_seqno,
1577 end_seqno,
1578 seconds_until_expiry);
1579 }
1580
1581 std::vector<StatePtr> get_state_range(
1582 RequestHandle handle,
1583 ccf::SeqNo start_seqno,
1584 ccf::SeqNo end_seqno) override
1585 {
1587 make_compound_handle(handle), start_seqno, end_seqno);
1588 }
1589
1590 std::vector<ccf::kv::ReadOnlyStorePtr> get_stores_for(
1591 RequestHandle handle,
1592 const SeqNoCollection& seqnos,
1593 ExpiryDuration seconds_until_expiry) override
1594 {
1596 make_compound_handle(handle), seqnos, seconds_until_expiry);
1597 }
1598
1599 std::vector<ccf::kv::ReadOnlyStorePtr> get_stores_for(
1600 RequestHandle handle, const SeqNoCollection& seqnos) override
1601 {
1603 make_compound_handle(handle), seqnos);
1604 }
1605
1606 std::vector<StatePtr> get_states_for(
1607 RequestHandle handle,
1608 const SeqNoCollection& seqnos,
1609 ExpiryDuration seconds_until_expiry) override
1610 {
1612 make_compound_handle(handle), seqnos, seconds_until_expiry);
1613 }
1614
1615 std::vector<StatePtr> get_states_for(
1616 RequestHandle handle, const SeqNoCollection& seqnos) override
1617 {
1619 make_compound_handle(handle), seqnos);
1620 }
1621
1626
1627 void set_soft_cache_limit(CacheSize cache_limit) override
1628 {
1630 }
1631
1632 void track_deletes_on_missing_keys(bool track) override
1633 {
1635 }
1636
1637 bool drop_cached_states(RequestHandle handle) override
1638 {
1640 }
1641 };
1642}
#define CCF_ASSERT_FMT(expr,...)
Definition ccf_assert.h:10
#define CCF_ASSERT(expr, msg)
Definition ccf_assert.h:14
Definition claims_digest.h:10
Definition ledger_secrets.h:25
Definition history.h:415
Definition sha256_hash.h:16
Definition contiguous_set.h:18
ConstIterator end() const
Definition contiguous_set.h:490
bool empty() const
Definition contiguous_set.h:317
ConstIterator begin() const
Definition contiguous_set.h:485
size_t size() const
Definition contiguous_set.h:309
Definition historical_queries_interface.h:67
Definition historical_queries.h:94
std::map< CompoundHandle, std::list< CompoundHandle >::iterator > lru_lookup
Definition historical_queries.h:520
void update_store_raw_size(SeqNo seq, size_t new_size)
Definition historical_queries.h:637
void process_deserialised_store(const StoreDetailsPtr &details, const ccf::kv::StorePtr &store, const ccf::crypto::Sha256Hash &entry_digest, ccf::SeqNo seqno, bool is_signature, ccf::ClaimsDigest &&claims_digest, bool has_commit_evidence)
Definition historical_queries.h:720
std::vector< StatePtr > get_states_for(const CompoundHandle &handle, const SeqNoCollection &seqnos)
Definition historical_queries.h:1137
std::map< CompoundHandle, Request > requests
Definition historical_queries.h:508
std::list< CompoundHandle > lru_requests
Definition historical_queries.h:519
std::vector< ccf::kv::ReadOnlyStorePtr > states_to_stores(const std::vector< StatePtr > &states)
Definition historical_queries.h:1002
ExpiryDuration default_expiry_duration
Definition historical_queries.h:515
bool track_deletes_on_missing_keys_v
Definition historical_queries.h:104
ccf::kv::Store & source_store
Definition historical_queries.h:96
std::map< ccf::SeqNo, WeakStoreDetailsPtr > AllRequestedStores
Definition historical_queries.h:181
ringbuffer::WriterPtr to_host
Definition historical_queries.h:98
void add_request_refs(CompoundHandle handle)
Definition historical_queries.h:551
std::vector< StatePtr > get_state_range(const CompoundHandle &handle, ccf::SeqNo start_seqno, ccf::SeqNo end_seqno, ExpiryDuration seconds_until_expiry)
Definition historical_queries.h:1088
std::unordered_map< SeqNo, std::set< CompoundHandle > > store_to_requests
Definition historical_queries.h:524
std::vector< StatePtr > get_state_range(const CompoundHandle &handle, ccf::SeqNo start_seqno, ccf::SeqNo end_seqno)
Definition historical_queries.h:1101
StoreStage
Definition historical_queries.h:107
AllRequestedStores all_stores
Definition historical_queries.h:513
void set_soft_cache_limit(CacheSize cache_limit)
Definition historical_queries.h:1148
void remove_request_ref(SeqNo seq, CompoundHandle handle)
Definition historical_queries.h:559
CacheSize estimated_store_cache_size
Definition historical_queries.h:530
StatePtr get_state_at(const CompoundHandle &handle, ccf::SeqNo seqno, ExpiryDuration seconds_until_expiry)
Definition historical_queries.h:1047
StateCacheImpl(ccf::kv::Store &store, const std::shared_ptr< ccf::LedgerSecrets > &secrets, ringbuffer::WriterPtr host_writer)
Definition historical_queries.h:1015
bool drop_cached_states(const CompoundHandle &handle)
Definition historical_queries.h:1159
void handle_no_entry(ccf::SeqNo seqno)
Definition historical_queries.h:1319
void remove_request_refs(CompoundHandle handle)
Definition historical_queries.h:577
void track_deletes_on_missing_keys(bool track)
Definition historical_queries.h:1154
std::vector< StatePtr > get_states_for(const CompoundHandle &handle, const SeqNoCollection &seqnos, ExpiryDuration seconds_until_expiry)
Definition historical_queries.h:1125
std::vector< ccf::kv::ReadOnlyStorePtr > get_stores_for(const CompoundHandle &handle, const SeqNoCollection &seqnos, ExpiryDuration seconds_until_expiry)
Definition historical_queries.h:1110
std::map< ccf::SeqNo, StoreDetailsPtr > RequestedStores
Definition historical_queries.h:178
void handle_no_entry_range(ccf::SeqNo from_seqno, ccf::SeqNo to_seqno)
Definition historical_queries.h:1324
bool handle_encrypted_past_ledger_secret(const ccf::kv::StorePtr &store, LedgerSecretPtr encrypting_secret)
Definition historical_queries.h:825
ccf::kv::ReadOnlyStorePtr get_store_at(const CompoundHandle &handle, ccf::SeqNo seqno)
Definition historical_queries.h:1041
StatePtr get_state_at(const CompoundHandle &handle, ccf::SeqNo seqno)
Definition historical_queries.h:1061
std::shared_ptr< ccf::NodeEncryptor > historical_encryptor
Definition historical_queries.h:101
CacheSize soft_store_cache_limit
Definition historical_queries.h:527
void add_request_ref(SeqNo seq, CompoundHandle handle)
Definition historical_queries.h:532
void fetch_entries_range(ccf::SeqNo from, ccf::SeqNo to)
Definition historical_queries.h:652
std::vector< uint8_t > LedgerEntry
Definition historical_queries.h:112
bool handle_ledger_entry(ccf::SeqNo seqno, const uint8_t *data, size_t size)
Definition historical_queries.h:1172
void fetch_entry_at(ccf::SeqNo seqno)
Definition historical_queries.h:647
ccf::kv::ReadOnlyStorePtr get_store_at(const CompoundHandle &handle, ccf::SeqNo seqno, ExpiryDuration seconds_until_expiry)
Definition historical_queries.h:1027
StoreDetailsPtr next_secret_fetch_handle
Definition historical_queries.h:198
void update_earliest_known_ledger_secret()
Definition historical_queries.h:114
ccf::pal::Mutex requests_lock
Definition historical_queries.h:505
std::shared_ptr< StoreDetails > StoreDetailsPtr
Definition historical_queries.h:177
bool handle_ledger_entry(ccf::SeqNo seqno, const std::vector< uint8_t > &data)
Definition historical_queries.h:1167
void tick(const std::chrono::milliseconds &elapsed_ms)
Definition historical_queries.h:1419
VersionedSecret earliest_secret_
Definition historical_queries.h:197
std::optional< ccf::SeqNo > fetch_supporting_secret_if_needed(ccf::SeqNo seqno)
Definition historical_queries.h:664
std::unordered_map< ccf::SeqNo, size_t > raw_store_sizes
Definition historical_queries.h:525
std::shared_ptr< ccf::LedgerSecrets > source_ledger_secrets
Definition historical_queries.h:97
ccf::kv::StorePtr deserialise_ledger_entry(ccf::SeqNo seqno, const uint8_t *data, size_t size, ccf::kv::ApplyResult &result, ccf::ClaimsDigest &claims_digest, bool &has_commit_evidence)
Definition historical_queries.h:1346
std::shared_ptr< ccf::LedgerSecrets > historical_ledger_secrets
Definition historical_queries.h:100
std::vector< ccf::kv::ReadOnlyStorePtr > get_stores_for(const CompoundHandle &handle, const SeqNoCollection &seqnos)
Definition historical_queries.h:1119
std::vector< StatePtr > get_states_internal(const CompoundHandle &handle, const SeqNoCollection &seqnos, ExpiryDuration seconds_until_expiry, bool include_receipts)
Definition historical_queries.h:893
void delete_all_interested_requests(ccf::SeqNo seqno)
Definition historical_queries.h:985
void lru_shrink_to_fit(size_t threshold)
Definition historical_queries.h:600
bool handle_ledger_entries(ccf::SeqNo from_seqno, ccf::SeqNo to_seqno, const uint8_t *data, size_t size)
Definition historical_queries.h:1284
size_t get_estimated_store_cache_size()
Definition historical_queries.h:1413
CacheSize soft_store_cache_limit_raw
Definition historical_queries.h:528
void set_default_expiry_duration(ExpiryDuration duration)
Definition historical_queries.h:1143
bool handle_ledger_entries(ccf::SeqNo from_seqno, ccf::SeqNo to_seqno, const LedgerEntry &data)
Definition historical_queries.h:1277
std::vector< ccf::kv::ReadOnlyStorePtr > get_store_range(const CompoundHandle &handle, ccf::SeqNo start_seqno, ccf::SeqNo end_seqno)
Definition historical_queries.h:1079
std::weak_ptr< StoreDetails > WeakStoreDetailsPtr
Definition historical_queries.h:180
SeqNoCollection collection_from_single_range(ccf::SeqNo start_seqno, ccf::SeqNo end_seqno)
Definition historical_queries.h:878
std::vector< ccf::kv::ReadOnlyStorePtr > get_store_range(const CompoundHandle &handle, ccf::SeqNo start_seqno, ccf::SeqNo end_seqno, ExpiryDuration seconds_until_expiry)
Definition historical_queries.h:1066
void lru_promote(CompoundHandle handle)
Definition historical_queries.h:585
void lru_evict(CompoundHandle handle)
Definition historical_queries.h:626
Definition historical_queries.h:1505
StatePtr get_state_at(RequestHandle handle, ccf::SeqNo seqno, ExpiryDuration seconds_until_expiry) override
Definition historical_queries.h:1532
std::vector< StatePtr > get_state_range(RequestHandle handle, ccf::SeqNo start_seqno, ccf::SeqNo end_seqno, ExpiryDuration seconds_until_expiry) override
Definition historical_queries.h:1568
std::vector< StatePtr > get_states_for(RequestHandle handle, const SeqNoCollection &seqnos, ExpiryDuration seconds_until_expiry) override
Definition historical_queries.h:1606
CompoundHandle make_compound_handle(RequestHandle rh)
Definition historical_queries.h:1507
std::vector< ccf::kv::ReadOnlyStorePtr > get_store_range(RequestHandle handle, ccf::SeqNo start_seqno, ccf::SeqNo end_seqno) override
Definition historical_queries.h:1559
ccf::kv::ReadOnlyStorePtr get_store_at(RequestHandle handle, ccf::SeqNo seqno) override
Definition historical_queries.h:1526
std::vector< ccf::kv::ReadOnlyStorePtr > get_stores_for(RequestHandle handle, const SeqNoCollection &seqnos) override
Definition historical_queries.h:1599
std::vector< ccf::kv::ReadOnlyStorePtr > get_stores_for(RequestHandle handle, const SeqNoCollection &seqnos, ExpiryDuration seconds_until_expiry) override
Definition historical_queries.h:1590
StatePtr get_state_at(RequestHandle handle, ccf::SeqNo seqno) override
Definition historical_queries.h:1541
void set_soft_cache_limit(CacheSize cache_limit) override
Definition historical_queries.h:1627
std::vector< StatePtr > get_state_range(RequestHandle handle, ccf::SeqNo start_seqno, ccf::SeqNo end_seqno) override
Definition historical_queries.h:1581
ccf::kv::ReadOnlyStorePtr get_store_at(RequestHandle handle, ccf::SeqNo seqno, ExpiryDuration seconds_until_expiry) override
Definition historical_queries.h:1517
void set_default_expiry_duration(ExpiryDuration duration) override
Definition historical_queries.h:1622
bool drop_cached_states(RequestHandle handle) override
Definition historical_queries.h:1637
std::vector< StatePtr > get_states_for(RequestHandle handle, const SeqNoCollection &seqnos) override
Definition historical_queries.h:1615
void track_deletes_on_missing_keys(bool track) override
Definition historical_queries.h:1632
std::vector< ccf::kv::ReadOnlyStorePtr > get_store_range(RequestHandle handle, ccf::SeqNo start_seqno, ccf::SeqNo end_seqno, ExpiryDuration seconds_until_expiry) override
Definition historical_queries.h:1546
StateCache(Ts &&... ts)
Definition historical_queries.h:1514
Definition store.h:89
ReadOnlyTx create_read_only_tx() override
Definition store.h:1267
EncryptorPtr get_encryptor() override
Definition store.h:220
std::shared_ptr< Consensus > get_consensus() override
Definition store.h:182
Definition encryptor.h:15
Definition value.h:32
#define HISTORICAL_LOG(...)
Definition historical_queries.h:25
#define LOG_TRACE_FMT
Definition internal_logger.h:13
#define LOG_DEBUG_FMT
Definition internal_logger.h:14
#define LOG_FAIL_FMT
Definition internal_logger.h:16
std::vector< uint8_t > HashBytes
Definition hash_bytes.h:10
Definition historical_queries_adapter.h:18
std::chrono::seconds ExpiryDuration
Definition historical_queries_interface.h:50
std::shared_ptr< State > StatePtr
Definition historical_queries_interface.h:41
RequestNamespace
Definition historical_queries.h:31
std::pair< RequestNamespace, RequestHandle > CompoundHandle
Definition historical_queries.h:36
size_t RequestHandle
Definition historical_queries_interface.h:48
size_t CacheSize
Definition historical_queries_interface.h:52
std::shared_ptr< ReadOnlyStore > ReadOnlyStorePtr
Definition read_only_store.h:23
std::shared_ptr< ccf::kv::Store > StorePtr
Definition store.h:1332
ApplyResult
Definition kv_types.h:302
@ PASS_SIGNATURE
Definition kv_types.h:304
@ FAIL
Definition kv_types.h:311
std::mutex Mutex
Definition locking.h:12
Definition app_interface.h:14
LedgerSecretsMap::value_type VersionedLedgerSecret
Definition ledger_secrets.h:22
std::shared_ptr< TxReceiptImpl > TxReceiptImplPtr
Definition receipt.h:133
std::shared_ptr< LedgerSecret > LedgerSecretPtr
Definition ledger_secret.h:79
seqno
Definition signatures.h:54
uint64_t SeqNo
Definition tx_id.h:36
std::vector< uint8_t > decrypt_previous_ledger_secret_raw(const LedgerSecretPtr &ledger_secret, const std::vector< uint8_t > &encrypted_previous_secret_raw)
Definition ledger_secret.h:87
Definition consensus_types.h:23
uint64_t Index
Definition ledger_enclave_types.h:11
@ HistoricalQuery
Definition ledger_enclave_types.h:16
std::shared_ptr< AbstractWriter > WriterPtr
Definition ring_buffer_types.h:154
STL namespace.
#define RINGBUFFER_WRITE_MESSAGE(MSG,...)
Definition ring_buffer_types.h:259
Definition tx_id.h:44
SeqNo seqno
Definition tx_id.h:46
View view
Definition tx_id.h:45
Definition historical_queries.h:201
bool include_receipts
Definition historical_queries.h:207
StoreDetailsPtr get_store_details(ccf::SeqNo seqno) const
Definition historical_queries.h:219
Request(AllRequestedStores &all_stores_)
Definition historical_queries.h:217
void populate_receipts(ccf::SeqNo new_seqno)
Definition historical_queries.h:347
std::pair< std::vector< SeqNo >, std::vector< SeqNo > > adjust_ranges(const SeqNoCollection &new_seqnos, bool should_include_receipts, SeqNo earliest_ledger_secret_seqno)
Definition historical_queries.h:240
std::optional< ccf::SeqNo > awaiting_ledger_secrets
Definition historical_queries.h:215
AllRequestedStores & all_stores
Definition historical_queries.h:202
std::chrono::milliseconds time_to_expiry
Definition historical_queries.h:205
RequestedStores supporting_signatures
Definition historical_queries.h:212
ccf::SeqNo first_requested_seqno() const
Definition historical_queries.h:230
RequestedStores my_stores
Definition historical_queries.h:204
Definition historical_queries.h:140
std::chrono::milliseconds time_until_fetch
Definition historical_queries.h:141
std::optional< std::string > get_commit_evidence()
Definition historical_queries.h:163
bool has_commit_evidence
Definition historical_queries.h:149
ccf::kv::StorePtr store
Definition historical_queries.h:145
ccf::ClaimsDigest claims_digest
Definition historical_queries.h:144
ccf::crypto::Sha256Hash entry_digest
Definition historical_queries.h:143
ccf::TxID transaction_id
Definition historical_queries.h:148
ccf::crypto::HashBytes get_commit_nonce()
Definition historical_queries.h:151
TxReceiptImplPtr receipt
Definition historical_queries.h:147
StoreStage current_stage
Definition historical_queries.h:142
bool is_signature
Definition historical_queries.h:146
Definition historical_queries.h:184
ccf::LedgerSecretPtr secret
Definition historical_queries.h:186
ccf::SeqNo valid_from
Definition historical_queries.h:185
VersionedSecret(const ccf::VersionedLedgerSecret &vls)
Definition historical_queries.h:191
constexpr auto parse(ParseContext &ctx)
Definition historical_queries.h:44
auto format(const ccf::historical::CompoundHandle &p, FormatContext &ctx) const
Definition historical_queries.h:50