CCF
Loading...
Searching...
No Matches
history.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
8#include "ccf/pal/locking.h"
12#include "cose/cose_rs_ffi.h"
13#include "crypto/cose.h"
15#include "crypto/openssl/hash.h"
16#include "crypto/public_key.h"
17#include "ds/internal_logger.h"
18#include "endian.h"
19#include "kv/kv_types.h"
20#include "kv/store.h"
21#include "node/cose_common.h"
22#include "node/no_get_ledger_sign_mode.cpp" // NOLINT(bugprone-suspicious-include)
25#include "tasks/basic_task.h"
26#include "tasks/task_system.h"
27
28#include <array>
29#include <deque>
30#include <string.h>
31
32#define HAVE_OPENSSL
33// merklecpp traces are off by default, even when CCF tracing is enabled
34// #include "merklecpp_trace.h"
35#include <merklecpp/merklecpp.h>
36
37namespace ccf
38{
39 enum HashOp : uint8_t
40 {
45 };
46
47#ifdef OVERRIDE_MAX_HISTORY_LEN
48 constexpr int MAX_HISTORY_LEN = OVERRIDE_MAX_HISTORY_LEN;
49#else
50 constexpr int MAX_HISTORY_LEN = 0;
51#endif
52
53 static std::ostream& operator<<(std::ostream& os, HashOp flag)
54 {
55 switch (flag)
56 {
57 case APPEND:
58 os << "append";
59 break;
60
61 case VERIFY:
62 os << "verify";
63 break;
64
65 case ROLLBACK:
66 os << "rollback";
67 break;
68
69 case COMPACT:
70 os << "compact";
71 break;
72 }
73
74 return os;
75 }
76
77 static inline void log_hash(const ccf::crypto::Sha256Hash& h, HashOp flag)
78 {
79 LOG_TRACE_FMT("History [{}] {}", flag, h);
80 }
81
83 {
84 ccf::TxID txid;
85 ccf::kv::Store& store;
86 NodeId id;
87
88 public:
90 ccf::TxID txid_, ccf::kv::Store& store_, NodeId id_) :
91 txid(txid_),
92 store(store_),
93 id(std::move(id_))
94 {}
95
97 {
98 auto sig = store.create_reserved_tx(txid);
99 auto* signatures =
100 sig.template wo<ccf::Signatures>(ccf::Tables::SIGNATURES);
101 auto* cose_signatures =
102 sig.template wo<ccf::CoseSignatures>(ccf::Tables::COSE_SIGNATURES);
103
104 auto* serialised_tree = sig.template wo<ccf::SerialisedMerkleTree>(
105 ccf::Tables::SERIALISED_MERKLE_TREE);
106 PrimarySignature sig_value(id, txid.seqno);
107 signatures->put(sig_value);
108 cose_signatures->put(ccf::CoseSignature{});
109 serialised_tree->put({});
110 return sig.commit_reserved();
111 }
112 };
113
115 {
116 ccf::kv::Store& store;
117 NodeId id;
118
119 protected:
123
124 public:
126 ccf::kv::Store& store_, NodeId id_, ccf::crypto::ECKeyPair& /*unused*/) :
127 store(store_),
128 id(std::move(id_))
129 {}
130
131 void append(const std::vector<uint8_t>& /*data*/) override
132 {
133 version++;
134 }
135
137 const ccf::crypto::Sha256Hash& /*digest*/,
138 std::optional<ccf::kv::Term> /*term_of_next_version_*/ =
139 std::nullopt) override
140 {
141 version++;
142 }
143
145 {
146 return true;
147 }
148
149 void set_term(ccf::kv::Term t) override
150 {
153 }
154
155 void rollback(const ccf::TxID& tx_id, ccf::kv::Term commit_term_) override
156 {
157 version = tx_id.seqno;
159 term_of_next_version = commit_term_;
160 }
161
162 void compact(ccf::kv::Version /*v*/) override {}
163
165 const std::vector<uint8_t>& /*hash_at_snapshot*/) override
166 {
167 return true;
168 }
169
170 std::vector<uint8_t> get_raw_leaf(uint64_t /*index*/) override
171 {
172 return {};
173 }
174
175 void emit_signature() override
176 {
177 auto txid = store.next_txid();
178 LOG_DEBUG_FMT("Issuing signature at {}.{}", txid.view, txid.seqno);
179 store.commit(
180 txid, std::make_unique<NullTxHistoryPendingTx>(txid, store, id), true);
181 }
182
183 void try_emit_signature() override {}
184
185 void start_signature_emit_timer() override {}
186
188 std::shared_ptr<ccf::crypto::ECKeyPair_OpenSSL> service_kp_,
189 const ccf::COSESignaturesConfig& /*cose_signatures*/) override
190 {
191 std::ignore = service_kp_;
192 }
193
195 {
196 throw std::logic_error("Unimplemented");
197 }
198
200 {
201 return ccf::crypto::Sha256Hash(std::to_string(version));
202 }
203
204 std::tuple<ccf::TxID, ccf::crypto::Sha256Hash, ccf::kv::Term>
206 {
207 return {
209 ccf::crypto::Sha256Hash(std::to_string(version)),
211 }
212
213 std::vector<uint8_t> get_proof(ccf::kv::Version /*v*/) override
214 {
215 return {};
216 }
217
218 bool verify_proof(const std::vector<uint8_t>& /*proof*/) override
219 {
220 return true;
221 }
222
223 std::vector<uint8_t> serialise_tree(size_t /*to*/) override
224 {
225 return {};
226 }
227
228 void set_endorsed_certificate(const ccf::crypto::Pem& cert) override {}
229 };
230
231 // Use optimised CCF openssl_sha256 function to avoid performance regression
232 // on OpenSSL 3.x
233 static constexpr size_t sha256_byte_size = 32;
234 static inline void sha256_history(
235 const merkle::HashT<sha256_byte_size>& l,
236 const merkle::HashT<sha256_byte_size>& r,
237 merkle::HashT<sha256_byte_size>& out)
238
239 {
240 uint8_t block[sha256_byte_size * 2];
241 memcpy(&block[0], l.bytes, sha256_byte_size);
242 memcpy(&block[sha256_byte_size], r.bytes, sha256_byte_size);
243
244 ccf::crypto::openssl_sha256(block, out.bytes);
245 }
246
247 using HistoryTree = merkle::TreeT<sha256_byte_size, ccf::sha256_history>;
248
249 class Proof
250 {
251 private:
252 HistoryTree::Hash root;
253 std::shared_ptr<HistoryTree::Path> path = nullptr;
254
255 public:
256 Proof() = default;
257
258 Proof(const std::vector<uint8_t>& v)
259 {
260 size_t position = 0;
261 root.deserialise(v, position);
262 path = std::make_shared<HistoryTree::Path>(v, position);
263 }
264
265 [[nodiscard]] const HistoryTree::Hash& get_root() const
266 {
267 return root;
268 }
269
270 std::shared_ptr<HistoryTree::Path> get_path()
271 {
272 return path;
273 }
274
275 Proof(HistoryTree* tree, uint64_t index) :
276 root(tree->root()),
277 path(tree->path(index))
278 {}
279
280 Proof(const Proof&) = delete;
281
282 bool verify(HistoryTree* tree) const
283 {
284 if (path->max_index() > tree->max_index())
285 {
286 return false;
287 }
288
289 if (tree->max_index() == path->max_index())
290 {
291 return tree->root() == root && path->verify(root);
292 }
293
294 auto past_root = tree->past_root(path->max_index());
295 return path->verify(*past_root);
296 }
297
298 [[nodiscard]] std::vector<uint8_t> to_v() const
299 {
300 std::vector<uint8_t> v;
301 root.serialise(v);
302 path->serialise(v);
303 return v;
304 }
305 };
306
307 template <class T>
309 {
310 ccf::TxID txid;
311 ccf::kv::Store& store;
312 ccf::kv::TxHistory& history;
313 NodeId id;
314 ccf::crypto::ECKeyPair& node_kp;
316 ccf::crypto::Pem& endorsed_cert;
317 const ccf::COSESignaturesConfig& cose_signatures_config;
318 const ccf::LedgerSignMode ledger_sign_mode;
319 std::unordered_map<std::string, CoseKey>& cose_key_cache;
320
321 public:
323 ccf::TxID txid_,
324 ccf::kv::Store& store_,
325 ccf::kv::TxHistory& history_,
326 NodeId id_,
327 ccf::crypto::ECKeyPair& node_kp_,
329 ccf::crypto::Pem& endorsed_cert_,
330 const ccf::COSESignaturesConfig& cose_signatures_config_,
331 ccf::LedgerSignMode ledger_sign_mode_,
332 std::unordered_map<std::string, CoseKey>& cose_key_cache_) :
333 txid(txid_),
334 store(store_),
335 history(history_),
336 id(std::move(id_)),
337 node_kp(node_kp_),
338 service_kp(service_kp_),
339 endorsed_cert(endorsed_cert_),
340 cose_signatures_config(cose_signatures_config_),
341 ledger_sign_mode(ledger_sign_mode_),
342 cose_key_cache(cose_key_cache_)
343 {}
344
346 {
347 auto sig = store.create_reserved_tx(txid);
349
350 std::vector<uint8_t> root_hash{
351 root.h.data(), root.h.data() + root.h.size()};
352
353 if (ledger_sign_mode == ccf::LedgerSignMode::Dual)
354 {
355 auto* signatures =
356 sig.template wo<ccf::Signatures>(ccf::Tables::SIGNATURES);
357 auto primary_sig =
358 node_kp.sign_hash(root_hash.data(), root_hash.size());
359
360 PrimarySignature sig_value(
361 id,
362 txid.seqno,
363 txid.view,
364 root,
365 {}, // Nonce is currently empty
366 primary_sig,
367 endorsed_cert);
368
369 signatures->put(sig_value);
370 }
371
372 auto* cose_signatures =
373 sig.template wo<ccf::CoseSignatures>(ccf::Tables::COSE_SIGNATURES);
374
375 auto kid = ccf::crypto::kid_from_key(service_kp.public_key_der());
376 const auto tx_id = txid.to_str();
377
378 const auto time_since_epoch =
379 std::chrono::duration_cast<std::chrono::seconds>(
380 std::chrono::system_clock::now().time_since_epoch())
381 .count();
382
383 auto it = cose_key_cache.find(kid);
384 if (it == cose_key_cache.end())
385 {
386 auto key_der = service_kp.private_key_der();
387 CoseBuffer key_err;
388 auto cose_key =
389 CoseKey::from_private(key_der.data(), key_der.size(), key_err);
390 if (!cose_key.is_set())
391 {
392 throw std::runtime_error(fmt::format(
393 "cose_key_from_der_private failed: {}",
394 key_err.is_set() ? key_err.to_string() : "unknown error"));
395 }
396 auto [inserted, _] = cose_key_cache.emplace(kid, std::move(cose_key));
397 it = inserted;
398 }
399
400 CoseBuffer cose_buf;
401 CoseBuffer cose_err;
402 auto rc = cose_sign_ledger(
403 it->second,
404 reinterpret_cast<const uint8_t*>(kid.data()),
405 kid.size(),
406 time_since_epoch,
407 reinterpret_cast<const uint8_t*>(cose_signatures_config.issuer.data()),
408 cose_signatures_config.issuer.size(),
409 reinterpret_cast<const uint8_t*>(cose_signatures_config.subject.data()),
410 cose_signatures_config.subject.size(),
411 reinterpret_cast<const uint8_t*>(tx_id.data()),
412 tx_id.size(),
413 root_hash.data(),
414 root_hash.size(),
415 cose_buf,
416 cose_err);
417 if (rc != 0 || !cose_buf.is_set())
418 {
419 throw std::runtime_error(fmt::format(
420 "cose_sign_ledger failed: {}",
421 cose_err.is_set() ? cose_err.to_string() : "unknown error"));
422 }
423 std::vector<uint8_t> cose_sign(cose_buf.to_vector());
424
425 cose_signatures->put(cose_sign);
426
427 auto* serialised_tree = sig.template wo<ccf::SerialisedMerkleTree>(
428 ccf::Tables::SERIALISED_MERKLE_TREE);
429 serialised_tree->put(history.serialise_tree(txid.seqno - 1));
430
431 return sig.commit_reserved();
432 }
433 };
434
436 {
437 std::unique_ptr<HistoryTree> tree;
438
439 public:
441
442 MerkleTreeHistory(const std::vector<uint8_t>& serialised) :
443 tree(std::make_unique<HistoryTree>(serialised))
444 {}
445
447 tree(std::make_unique<HistoryTree>(merkle::Hash(first_hash.h)))
448 {}
449
451
452 void deserialise(const std::vector<uint8_t>& serialised)
453 {
454 tree = std::make_unique<HistoryTree>(serialised);
455 }
456
458 {
459 tree->insert(merkle::Hash(hash.h));
460 }
461
462 [[nodiscard]] ccf::crypto::Sha256Hash get_root() const
463 {
464 const merkle::Hash& root = tree->root();
466 std::copy(root.bytes, root.bytes + root.size(), result.h.begin());
467 return result;
468 }
469
471 {
472 if (this != &rhs)
473 {
475 tree = std::make_unique<HistoryTree>(merkle::Hash(root.h));
476 }
477 return *this;
478 }
479
480 void flush(uint64_t index)
481 {
482 LOG_TRACE_FMT("mt_flush_to index={}", index);
483 tree->flush_to(index);
484 }
485
486 void retract(uint64_t index)
487 {
488 LOG_TRACE_FMT("mt_retract_to index={}", index);
489 tree->retract_to(index);
490 }
491
492 Proof get_proof(uint64_t index)
493 {
494 if (index < begin_index())
495 {
496 throw std::logic_error(fmt::format(
497 "Cannot produce proof for {}: index is older than first index {}, "
498 "and has been flushed from memory",
499 index,
500 begin_index()));
501 }
502 if (index > end_index())
503 {
504 throw std::logic_error(fmt::format(
505 "Cannot produce proof for {}: index is later than last index {}",
506 index,
507 end_index()));
508 }
509 return {tree.get(), index};
510 }
511
512 bool verify(const Proof& r)
513 {
514 return r.verify(tree.get());
515 }
516
517 std::vector<uint8_t> serialise()
518 {
519 LOG_TRACE_FMT("mt_serialize_size {}", tree->serialised_size());
520 std::vector<uint8_t> output;
521 tree->serialise(output);
522 return output;
523 }
524
525 std::vector<uint8_t> serialise(size_t from, size_t to)
526 {
528 "mt_serialize_size ({},{}) {}",
529 from,
530 to,
531 tree->serialised_size(from, to));
532 std::vector<uint8_t> output;
533 tree->serialise(from, to, output);
534 return output;
535 }
536
537 uint64_t begin_index()
538 {
539 return tree->min_index();
540 }
541
542 uint64_t end_index()
543 {
544 return tree->max_index();
545 }
546
547 bool in_range(uint64_t index)
548 {
549 return index >= begin_index() && index <= end_index();
550 }
551
553 {
554 const merkle::Hash& leaf = tree->leaf(index);
556 std::copy(leaf.bytes, leaf.bytes + leaf.size(), result.h.begin());
557 return result;
558 }
559 };
560
561 template <class T>
563 {
564 ccf::kv::Store& store;
565 NodeId id;
566 T replicated_state_tree;
567
568 ccf::crypto::ECKeyPair& node_kp;
570 ccf::crypto::Pem cose_cert_cached;
571
572 ccf::tasks::Task emit_signature_periodic_task;
573 size_t sig_tx_interval;
574 size_t sig_ms_interval;
575
576 ccf::pal::Mutex state_lock;
577 ccf::kv::Term term_of_last_version = 0;
578 ccf::kv::Term term_of_next_version{};
579
580 std::optional<ccf::crypto::Pem> endorsed_cert = std::nullopt;
581
582 struct ServiceSigningIdentity
583 {
584 const std::shared_ptr<ccf::crypto::ECKeyPair_OpenSSL> service_kp;
585 const ccf::COSESignaturesConfig cose_signatures_config;
586 const ccf::LedgerSignMode ledger_sign_mode = ccf::LedgerSignMode::Dual;
587 };
588
589 std::optional<ServiceSigningIdentity> signing_identity = std::nullopt;
590
591 std::unordered_map<std::string, CoseKey> cose_key_cache;
592
593 public:
595 ccf::kv::Store& store_,
596 NodeId id_,
597 ccf::crypto::ECKeyPair& node_kp_,
598 size_t sig_tx_interval_ = 0,
599 size_t sig_ms_interval_ = 0,
600 bool signature_timer = false) :
601 store(store_),
602 id(std::move(id_)),
603 node_kp(node_kp_),
604 sig_tx_interval(sig_tx_interval_),
605 sig_ms_interval(sig_ms_interval_)
606 {
607 if (signature_timer)
608 {
610 }
611 }
612
614 std::shared_ptr<ccf::crypto::ECKeyPair_OpenSSL> service_kp_,
615 const ccf::COSESignaturesConfig& cose_signatures_config_) override
616 {
617 if (signing_identity.has_value())
618 {
619 throw std::logic_error(
620 "Called set_service_signing_identity() multiple times");
621 }
622
623 const auto ledger_sign_mode_ = ccf::get_ledger_sign_mode();
624
625 signing_identity.emplace(ServiceSigningIdentity{
626 service_kp_, cose_signatures_config_, ledger_sign_mode_});
627
629 "Setting service signing identity to iss: {} sub: {}. Ledger "
630 "signature mode: {}",
631 cose_signatures_config_.issuer,
632 cose_signatures_config_.subject,
633 nlohmann::json(ledger_sign_mode_).dump());
634 }
635
637 {
638 if (!signing_identity.has_value())
639 {
640 throw std::logic_error(
641 "Called get_cose_signatures_config() before "
642 "set_service_signing_identity()");
643 }
644
645 return signing_identity->cose_signatures_config;
646 }
647
649 {
650 const auto delay = std::chrono::milliseconds(sig_ms_interval);
651
652 emit_signature_periodic_task = ccf::tasks::make_basic_task([this]() {
653 std::unique_lock<ccf::pal::Mutex> mguard(
654 this->signature_lock, std::defer_lock);
655
656 bool should_emit_signature = false;
657
658 if (mguard.try_lock())
659 {
660 auto consensus = this->store.get_consensus();
661 if (consensus != nullptr)
662 {
663 auto sig_disp = consensus->get_signature_disposition();
664 switch (sig_disp)
665 {
667 {
668 break;
669 }
671 {
672 // To snapshot we need to complete the chunk and to do that we
673 // need to set the force_chunk_after flag on the last snapshot
674 // in it.
675 // At this point the previous signature is already replicating
676 // and is immutable.
677 // So if we need to snapshot, we need to emit a new signature to
678 // ensure we can set the force_chunk_after flag, even if there
679 // are no other transactions between this and the last snapshot
680 if (
681 this->store.committable_gap() > 0 ||
682 this->store.should_schedule_snapshot())
683 {
684 should_emit_signature = true;
685 }
686 break;
687 }
689 {
690 should_emit_signature = true;
691 break;
692 }
693 }
694 }
695 }
696
697 if (should_emit_signature)
698 {
699 this->emit_signature();
700 }
701 });
702
703 ccf::tasks::add_periodic_task(emit_signature_periodic_task, delay, delay);
704 }
705
707 {
708 if (emit_signature_periodic_task != nullptr)
709 {
710 emit_signature_periodic_task->cancel_task();
711 }
712 }
713
714 void set_node_id(const NodeId& id_)
715 {
716 id = id_;
717 }
718
720 const std::vector<uint8_t>& hash_at_snapshot) override
721 {
722 // The history can be initialised after a snapshot has been applied by
723 // deserialising the tree in the signatures table and then applying the
724 // hash of the transaction at which the snapshot was taken
725 auto tx = store.create_read_only_tx();
726 auto* tree_h = tx.template ro<ccf::SerialisedMerkleTree>(
727 ccf::Tables::SERIALISED_MERKLE_TREE);
728 auto tree = tree_h->get();
729 if (!tree.has_value())
730 {
731 LOG_FAIL_FMT("No tree found in serialised tree map");
732 return false;
733 }
734
735 // Delay taking this lock until _after_ the read above, to avoid lock
736 // inversions
737 std::lock_guard<ccf::pal::Mutex> guard(state_lock);
738
740 !replicated_state_tree.in_range(1),
741 "Tree is not empty before initialising from snapshot");
742
743 replicated_state_tree.deserialise(tree.value());
744
746 std::copy_n(
747 hash_at_snapshot.begin(),
749 hash.h.begin());
750 replicated_state_tree.append(hash);
751 return true;
752 }
753
755 {
756 std::lock_guard<ccf::pal::Mutex> guard(state_lock);
757 return replicated_state_tree.get_root();
758 }
759
760 std::tuple<ccf::TxID, ccf::crypto::Sha256Hash, ccf::kv::Term>
762 {
763 std::lock_guard<ccf::pal::Mutex> guard(state_lock);
764 return {
765 {term_of_last_version,
766 static_cast<ccf::kv::Version>(replicated_state_tree.end_index())},
767 replicated_state_tree.get_root(),
768 term_of_next_version};
769 }
770
772 {
773 auto tx = store.create_read_only_tx();
774
775 auto root = get_replicated_state_root();
776 log_hash(root, VERIFY);
777
778 auto* signatures =
779 tx.template ro<ccf::Signatures>(ccf::Tables::SIGNATURES);
780 auto sig = signatures->get();
781 if (sig.has_value())
782 {
783 // Only verify the node signature if it was actually written in this
784 // version. In COSE-only mode, the signatures table is not written,
785 // so an old value may be present from a previous dual-signed
786 // transaction. Verifying that stale signature against the current
787 // root would fail.
788 const auto sig_version = signatures->get_version_of_previous_write();
789 if (sig_version.has_value() && sig_version.value() == version)
790 {
791 if (!verify_node_signature(tx, sig->node, sig->sig, root))
792 {
793 return false;
794 }
795 }
796 }
797
798 auto* cose_signatures =
799 tx.template ro<ccf::CoseSignatures>(ccf::Tables::COSE_SIGNATURES);
800 auto cose_sig = cose_signatures->get();
801
802 if (!cose_sig.has_value())
803 {
804 // It's possible we are reading some old non-COSE ledger entry.
805 // In that case, it's enough to only verify regular sig.
806 if (sig.has_value())
807 {
808 return true;
809 }
810
811 LOG_FAIL_FMT("No signatures found in COSE signatures map");
812 return false;
813 }
814
815 // Since COSE signatures have not always been emitted, it is possible in a
816 // mixed-service to see an _old_ COSE signature (by reading from the KV)
817 // that does not refer to the _current root_. When this occurs
818 // version_of_previous_write will not match the version at which we're
819 // verifying.
820 const auto cose_sig_version =
821 cose_signatures->get_version_of_previous_write();
822 if (cose_sig_version.has_value() && cose_sig_version.value() != version)
823 {
825 "Non-monotonic presence of COSE signatures - had one at {} but none "
826 "at {}",
827 cose_sig_version.value(),
828 version);
829 return true;
830 }
831
832 auto* service = tx.template ro<ccf::Service>(Tables::SERVICE);
833 auto service_info = service->get();
834
835 if (!service_info.has_value())
836 {
837 LOG_FAIL_FMT("No service key found to verify the signature");
838 return false;
839 }
840
841 std::vector<uint8_t> root_hash{
842 root.h.data(), root.h.data() + root.h.size()};
843 if (!cose_verifier_cached(service_info->cert)
844 ->verify_detached(cose_sig.value(), root_hash))
845 {
846 return false;
847 }
848
850 {
851 try
852 {
853 auto receipt = ccf::cose::decode_ccf_receipt(
854 cose_sig.value(), /* recompute_root */ false);
855 if (receipt.phdr.cwt.iat.has_value())
856 {
858 "Verified COSE signature for TxID {}, issued at {}",
859 receipt.phdr.ccf.txid,
860 ccf::ds::to_x509_time_string(
861 std::chrono::system_clock::from_time_t(
862 receipt.phdr.cwt.iat.value())));
863 }
864 }
865 catch (const std::exception& e)
866 {
868 "Failed to decode COSE protected header for debug logging: {}",
869 e.what());
870 }
871 }
872
873 return true;
874 }
875
876 std::vector<uint8_t> serialise_tree(size_t to) override
877 {
878 std::lock_guard<ccf::pal::Mutex> guard(state_lock);
879 if (to <= replicated_state_tree.end_index())
880 {
881 return replicated_state_tree.serialise(
882 replicated_state_tree.begin_index(), to);
883 }
884
885 return {};
886 }
887
888 void set_term(ccf::kv::Term t) override
889 {
890 // This should only be called once, when the store first knows about its
891 // term
892 std::lock_guard<ccf::pal::Mutex> guard(state_lock);
893 term_of_last_version = t;
894 term_of_next_version = t;
895 }
896
898 const ccf::TxID& tx_id, ccf::kv::Term term_of_next_version_) override
899 {
900 std::lock_guard<ccf::pal::Mutex> guard(state_lock);
901 LOG_TRACE_FMT("Rollback to {}.{}", tx_id.view, tx_id.seqno);
902 term_of_last_version = tx_id.view;
903 term_of_next_version = term_of_next_version_;
904 replicated_state_tree.retract(tx_id.seqno);
905 log_hash(replicated_state_tree.get_root(), ROLLBACK);
906 }
907
908 void compact(ccf::kv::Version v) override
909 {
910 std::lock_guard<ccf::pal::Mutex> guard(state_lock);
911 // Receipts can only be retrieved to the flushed index. Keep a range of
912 // history so that a range of receipts are available.
913 if (v > MAX_HISTORY_LEN)
914 {
915 replicated_state_tree.flush(v - MAX_HISTORY_LEN);
916 }
917 log_hash(replicated_state_tree.get_root(), COMPACT);
918 }
919
921
922 void try_emit_signature() override
923 {
924 std::unique_lock<ccf::pal::Mutex> mguard(signature_lock, std::defer_lock);
925 if (store.committable_gap() < sig_tx_interval || !mguard.try_lock())
926 {
927 return;
928 }
929
930 if (store.committable_gap() >= sig_tx_interval)
931 {
932 mguard.unlock();
934 }
935 }
936
937 void emit_signature() override
938 {
939 // Signatures are only emitted when there is a consensus
940 auto consensus = store.get_consensus();
941 if (!consensus)
942 {
943 return;
944 }
945
946 if (!endorsed_cert.has_value())
947 {
948 throw std::logic_error(
949 fmt::format("No endorsed certificate set to emit signature"));
950 }
951
952 auto txid = store.next_txid();
953
954 LOG_DEBUG_FMT("Signed at {} in view: {}", txid.seqno, txid.view);
955
956 if (!signing_identity.has_value())
957 {
958 throw std::logic_error(
959 fmt::format("No service key has been set yet to sign"));
960 }
961
962 store.commit(
963 txid,
964 std::make_unique<MerkleTreeHistoryPendingTx<T>>(
965 txid,
966 store,
967 *this,
968 id,
969 node_kp,
970 *signing_identity->service_kp,
971 endorsed_cert.value(),
972 signing_identity->cose_signatures_config,
973 signing_identity->ledger_sign_mode,
974 cose_key_cache),
975 true);
976 }
977
978 std::vector<uint8_t> get_proof(ccf::kv::Version index) override
979 {
980 std::lock_guard<ccf::pal::Mutex> guard(state_lock);
981 return replicated_state_tree.get_proof(index).to_v();
982 }
983
984 bool verify_proof(const std::vector<uint8_t>& v) override
985 {
986 Proof proof(v);
987 std::lock_guard<ccf::pal::Mutex> guard(state_lock);
988 return replicated_state_tree.verify(proof);
989 }
990
991 std::vector<uint8_t> get_raw_leaf(uint64_t index) override
992 {
993 std::lock_guard<ccf::pal::Mutex> guard(state_lock);
994 auto leaf = replicated_state_tree.get_leaf(index);
995 return {leaf.h.begin(), leaf.h.end()};
996 }
997
998 void append(const std::vector<uint8_t>& data) override
999 {
1000 ccf::crypto::Sha256Hash rh(data);
1001 log_hash(rh, APPEND);
1002 std::lock_guard<ccf::pal::Mutex> guard(state_lock);
1003 replicated_state_tree.append(rh);
1004 }
1005
1007 const ccf::crypto::Sha256Hash& digest,
1008 std::optional<ccf::kv::Term> expected_term_of_next_version =
1009 std::nullopt) override
1010 {
1011 log_hash(digest, APPEND);
1012 std::lock_guard<ccf::pal::Mutex> guard(state_lock);
1013 if (expected_term_of_next_version.has_value())
1014 {
1015 if (expected_term_of_next_version.value() != term_of_next_version)
1016 {
1017 return;
1018 }
1019 }
1020 replicated_state_tree.append(digest);
1021 }
1022
1024 {
1025 endorsed_cert = cert;
1026 }
1027
1028 private:
1029 ccf::crypto::COSEVerifierUniquePtr& cose_verifier_cached(
1030 const ccf::crypto::Pem& cert)
1031 {
1032 if (cert != cose_cert_cached)
1033 {
1034 cose_cert_cached = cert;
1035 cose_verifier =
1037 }
1038 return cose_verifier;
1039 }
1040 };
1041
1043}
#define CCF_ASSERT_FMT(expr,...)
Definition ccf_assert.h:10
Definition history.h:563
void set_service_signing_identity(std::shared_ptr< ccf::crypto::ECKeyPair_OpenSSL > service_kp_, const ccf::COSESignaturesConfig &cose_signatures_config_) override
Definition history.h:613
~HashedTxHistory() override
Definition history.h:706
std::tuple< ccf::TxID, ccf::crypto::Sha256Hash, ccf::kv::Term > get_replicated_state_txid_and_root() override
Definition history.h:761
void set_term(ccf::kv::Term t) override
Definition history.h:888
bool verify_proof(const std::vector< uint8_t > &v) override
Definition history.h:984
void set_endorsed_certificate(const ccf::crypto::Pem &cert) override
Definition history.h:1023
HashedTxHistory(ccf::kv::Store &store_, NodeId id_, ccf::crypto::ECKeyPair &node_kp_, size_t sig_tx_interval_=0, size_t sig_ms_interval_=0, bool signature_timer=false)
Definition history.h:594
void compact(ccf::kv::Version v) override
Definition history.h:908
std::vector< uint8_t > get_proof(ccf::kv::Version index) override
Definition history.h:978
ccf::pal::Mutex signature_lock
Definition history.h:920
const ccf::COSESignaturesConfig & get_cose_signatures_config() override
Definition history.h:636
void rollback(const ccf::TxID &tx_id, ccf::kv::Term term_of_next_version_) override
Definition history.h:897
std::vector< uint8_t > serialise_tree(size_t to) override
Definition history.h:876
bool verify_root_signatures(ccf::kv::Version version) override
Definition history.h:771
void append(const std::vector< uint8_t > &data) override
Definition history.h:998
void start_signature_emit_timer() override
Definition history.h:648
void set_node_id(const NodeId &id_)
Definition history.h:714
void try_emit_signature() override
Definition history.h:922
void emit_signature() override
Definition history.h:937
ccf::crypto::Sha256Hash get_replicated_state_root() override
Definition history.h:754
std::vector< uint8_t > get_raw_leaf(uint64_t index) override
Definition history.h:991
void append_entry(const ccf::crypto::Sha256Hash &digest, std::optional< ccf::kv::Term > expected_term_of_next_version=std::nullopt) override
Definition history.h:1006
bool init_from_snapshot(const std::vector< uint8_t > &hash_at_snapshot) override
Definition history.h:719
Definition history.h:309
ccf::kv::PendingTxInfo call() override
Definition history.h:345
MerkleTreeHistoryPendingTx(ccf::TxID txid_, ccf::kv::Store &store_, ccf::kv::TxHistory &history_, NodeId id_, ccf::crypto::ECKeyPair &node_kp_, ccf::crypto::ECKeyPair_OpenSSL &service_kp_, ccf::crypto::Pem &endorsed_cert_, const ccf::COSESignaturesConfig &cose_signatures_config_, ccf::LedgerSignMode ledger_sign_mode_, std::unordered_map< std::string, CoseKey > &cose_key_cache_)
Definition history.h:322
Definition history.h:436
void deserialise(const std::vector< uint8_t > &serialised)
Definition history.h:452
void flush(uint64_t index)
Definition history.h:480
ccf::crypto::Sha256Hash get_root() const
Definition history.h:462
std::vector< uint8_t > serialise(size_t from, size_t to)
Definition history.h:525
ccf::crypto::Sha256Hash get_leaf(uint64_t index)
Definition history.h:552
MerkleTreeHistory(const std::vector< uint8_t > &serialised)
Definition history.h:442
~MerkleTreeHistory()=default
MerkleTreeHistory & operator=(const MerkleTreeHistory &rhs)
Definition history.h:470
MerkleTreeHistory(ccf::crypto::Sha256Hash first_hash={})
Definition history.h:446
bool verify(const Proof &r)
Definition history.h:512
MerkleTreeHistory(MerkleTreeHistory const &)=delete
Proof get_proof(uint64_t index)
Definition history.h:492
std::vector< uint8_t > serialise()
Definition history.h:517
uint64_t end_index()
Definition history.h:542
void append(const ccf::crypto::Sha256Hash &hash)
Definition history.h:457
uint64_t begin_index()
Definition history.h:537
void retract(uint64_t index)
Definition history.h:486
bool in_range(uint64_t index)
Definition history.h:547
Definition history.h:83
ccf::kv::PendingTxInfo call() override
Definition history.h:96
NullTxHistoryPendingTx(ccf::TxID txid_, ccf::kv::Store &store_, NodeId id_)
Definition history.h:89
Definition history.h:115
void set_endorsed_certificate(const ccf::crypto::Pem &cert) override
Definition history.h:228
void try_emit_signature() override
Definition history.h:183
void compact(ccf::kv::Version) override
Definition history.h:162
ccf::crypto::Sha256Hash get_replicated_state_root() override
Definition history.h:199
ccf::kv::Term term_of_last_version
Definition history.h:121
void start_signature_emit_timer() override
Definition history.h:185
bool verify_root_signatures(ccf::kv::Version) override
Definition history.h:144
bool init_from_snapshot(const std::vector< uint8_t > &) override
Definition history.h:164
std::vector< uint8_t > serialise_tree(size_t) override
Definition history.h:223
void emit_signature() override
Definition history.h:175
ccf::kv::Term term_of_next_version
Definition history.h:122
bool verify_proof(const std::vector< uint8_t > &) override
Definition history.h:218
void append(const std::vector< uint8_t > &) override
Definition history.h:131
std::vector< uint8_t > get_proof(ccf::kv::Version) override
Definition history.h:213
NullTxHistory(ccf::kv::Store &store_, NodeId id_, ccf::crypto::ECKeyPair &)
Definition history.h:125
void set_term(ccf::kv::Term t) override
Definition history.h:149
std::tuple< ccf::TxID, ccf::crypto::Sha256Hash, ccf::kv::Term > get_replicated_state_txid_and_root() override
Definition history.h:205
void append_entry(const ccf::crypto::Sha256Hash &, std::optional< ccf::kv::Term >=std::nullopt) override
Definition history.h:136
ccf::kv::Version version
Definition history.h:120
const ccf::COSESignaturesConfig & get_cose_signatures_config() override
Definition history.h:194
void set_service_signing_identity(std::shared_ptr< ccf::crypto::ECKeyPair_OpenSSL > service_kp_, const ccf::COSESignaturesConfig &) override
Definition history.h:187
void rollback(const ccf::TxID &tx_id, ccf::kv::Term commit_term_) override
Definition history.h:155
std::vector< uint8_t > get_raw_leaf(uint64_t) override
Definition history.h:170
Definition history.h:250
std::shared_ptr< HistoryTree::Path > get_path()
Definition history.h:270
const HistoryTree::Hash & get_root() const
Definition history.h:265
Proof()=default
std::vector< uint8_t > to_v() const
Definition history.h:298
Proof(HistoryTree *tree, uint64_t index)
Definition history.h:275
Proof(const std::vector< uint8_t > &v)
Definition history.h:258
Proof(const Proof &)=delete
bool verify(HistoryTree *tree) const
Definition history.h:282
Definition ec_key_pair.h:16
std::vector< uint8_t > private_key_der() const override
Definition ec_key_pair.cpp:132
std::vector< uint8_t > public_key_der() const override
Definition ec_key_pair.cpp:127
Definition ec_key_pair.h:19
virtual std::vector< uint8_t > sign_hash(const uint8_t *hash, size_t hash_size) const =0
Definition pem.h:18
Definition sha256_hash.h:16
Representation h
Definition sha256_hash.h:20
static constexpr size_t SIZE
Definition sha256_hash.h:18
Definition kv_types.h:452
Definition store.h:88
ReservedTx create_reserved_tx(const TxID &tx_id)
Definition store.h:1321
ReadOnlyTx create_read_only_tx() override
Definition store.h:1296
size_t committable_gap() override
Definition store.h:1150
TxID next_txid() override
Definition store.h:1142
std::shared_ptr< Consensus > get_consensus() override
Definition store.h:183
CommitResult commit(const TxID &txid, std::unique_ptr< PendingTx > pending_tx, bool globally_committable) override
Definition store.h:903
Definition kv_types.h:332
virtual std::vector< uint8_t > serialise_tree(size_t to)=0
virtual ccf::crypto::Sha256Hash get_replicated_state_root()=0
static bool ok(LoggerLevel l)
Definition logger.h:232
int cose_sign_ledger(const CoseEvpKey *key, const uint8_t *kid_ptr, size_t kid_len, int64_t iat, const uint8_t *issuer_ptr, size_t issuer_len, const uint8_t *subject_ptr, size_t subject_len, const uint8_t *txid_ptr, size_t txid_len, const uint8_t *payload_ptr, size_t payload_len, uint8_t **out_ptr, size_t *out_len, uint8_t **err_ptr, size_t *err_len)
#define LOG_INFO_FMT
Definition internal_logger.h:15
#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::unique_ptr< COSEVerifier > COSEVerifierUniquePtr
Definition cose_verifier.h:28
COSEVerifierUniquePtr make_cose_verifier_from_pem_cert(const Pem &pem)
Definition cose_verifier.cpp:280
std::string kid_from_key(const std::vector< uint8_t > &public_key_der)
Definition public_key.cpp:10
uint64_t Term
Definition kv_types.h:46
uint64_t Version
Definition version.h:10
std::mutex Mutex
Definition locking.h:12
Task make_basic_task(Ts &&... ts)
Definition basic_task.h:33
void add_periodic_task(Task task, std::chrono::milliseconds initial_delay, std::chrono::milliseconds repeat_period)
Definition task_system.cpp:75
std::shared_ptr< BaseTask > Task
Definition task.h:36
Definition app_interface.h:13
merkle::TreeT< sha256_byte_size, ccf::sha256_history > HistoryTree
Definition history.h:247
constexpr int MAX_HISTORY_LEN
Definition history.h:50
std::vector< uint8_t > CoseSignature
Definition signatures.h:64
LedgerSignMode get_ledger_sign_mode()
Definition get_ledger_sign_mode_cose.cpp:8
HashOp
Definition history.h:40
@ COMPACT
Definition history.h:44
@ VERIFY
Definition history.h:42
@ APPEND
Definition history.h:41
@ ROLLBACK
Definition history.h:43
LedgerSignMode
Definition ledger_sign_mode.h:12
Definition consensus_types.h:23
STL namespace.
Definition cose_signatures_config.h:12
std::string issuer
Definition cose_signatures_config.h:13
std::string subject
Definition cose_signatures_config.h:14
Definition signatures.h:14
Definition tx_id.h:44
SeqNo seqno
Definition tx_id.h:46
View view
Definition tx_id.h:45
std::string to_str() const
Definition tx_id.h:48
Definition kv_types.h:430