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