in src/node/node_state.h [726:848]
void recover_public_ledger_entry(const std::vector<uint8_t>& ledger_entry)
{
std::lock_guard<std::mutex> guard(lock);
std::shared_ptr<kv::Store> store;
if (sm.check(State::readingPublicLedger))
{
// In recovery, use the main store to deserialise public entries
store = network.tables;
}
else if (sm.check(State::verifyingSnapshot))
{
store = startup_snapshot_info->store;
}
else
{
LOG_FAIL_FMT(
"Node should be in state {} or {} to recover public ledger entry",
State::readingPublicLedger,
State::verifyingSnapshot);
return;
}
LOG_INFO_FMT(
"Deserialising public ledger entry ({})", ledger_entry.size());
auto r = store->deserialize(ledger_entry, ConsensusType::CFT, true);
auto result = r->apply();
if (result == kv::ApplyResult::FAIL)
{
LOG_FAIL_FMT("Failed to deserialise entry in public ledger");
recover_public_ledger_end_unsafe();
return;
}
// Not synchronised because consensus isn't effectively running then
for (auto& hook : r->get_hooks())
{
hook->call(consensus.get());
}
// If the ledger entry is a signature, it is safe to compact the store
if (result == kv::ApplyResult::PASS_SIGNATURE)
{
// If the ledger entry is a signature, it is safe to compact the store
store->compact(ledger_idx);
auto tx = store->create_tx();
GenesisGenerator g(network, tx);
auto last_sig = tx.ro(network.signatures)->get();
if (!last_sig.has_value())
{
throw std::logic_error("Signature missing");
}
LOG_DEBUG_FMT(
"Read signature at {} for view {}", ledger_idx, last_sig->view);
// Initial transactions, before the first signature, must have
// happened in the first signature's view (eg - if the first
// signature is at seqno 20 in view 4, then transactions 1->19 must
// also have been in view 4). The brief justification is that while
// the first node may start in an arbitrarily high view (it does not
// necessarily start in view 1), it cannot _change_ view before a
// valid signature.
const auto view_start_idx =
view_history.empty() ? 1 : last_recovered_signed_idx + 1;
CCF_ASSERT_FMT(
last_sig->view >= 0, "last_sig->view is invalid, {}", last_sig->view);
for (auto i = view_history.size();
i < static_cast<size_t>(last_sig->view);
++i)
{
view_history.push_back(view_start_idx);
}
last_recovered_signed_idx = ledger_idx;
if (
startup_snapshot_info && startup_snapshot_info->has_evidence &&
startup_snapshot_info->evidence_seqno.has_value() &&
static_cast<consensus::Index>(last_sig->commit_seqno) >=
startup_snapshot_info->evidence_seqno.value())
{
startup_snapshot_info->is_evidence_committed = true;
}
if (sm.check(State::readingPublicLedger))
{
// Inform snapshotter of all signature entries so that this node can
// continue generating snapshots at the correct interval once the
// recovery is complete
snapshotter->record_committable(ledger_idx);
snapshotter->commit(ledger_idx, false);
}
}
else if (
result == kv::ApplyResult::PASS_SNAPSHOT_EVIDENCE &&
startup_snapshot_info)
{
auto tx = store->create_read_only_tx();
auto snapshot_evidence = tx.ro(network.snapshot_evidence);
if (
startup_snapshot_info->evidence_seqno.has_value() &&
ledger_idx == startup_snapshot_info->evidence_seqno.value())
{
auto evidence = snapshot_evidence->get();
if (!evidence.has_value())
{
throw std::logic_error("Invalid snapshot evidence");
}
if (evidence->hash == crypto::Sha256Hash(startup_snapshot_info->raw))
{
LOG_DEBUG_FMT(
"Snapshot evidence for snapshot found at {}",
startup_snapshot_info->evidence_seqno.value());
startup_snapshot_info->has_evidence = true;
}
}
}
read_ledger_idx(++ledger_idx);
}