Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split shares KV table #2140

Merged
merged 51 commits into from
Feb 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
c74502c
Historical queries after rekey
Jan 21, 2021
8e4a279
Cleanup PR
Jan 21, 2021
d8ce3d1
Fix null encryptor
Jan 21, 2021
78c8987
Merge branch 'master' into historical_ledger_secrets
achamayou Jan 21, 2021
0103472
Remove flag and use hot path
Jan 21, 2021
9b37218
Cleanup
Jan 21, 2021
bc12dca
Fix null encryptor
Jan 21, 2021
5582ada
Merge branch 'master' into historical_ledger_secrets
achamayou Jan 21, 2021
7177d70
Remove compaction
Jan 21, 2021
add7dc1
Merge branch 'historical_ledger_secrets' of github.com:jumaffre/CCF i…
Jan 21, 2021
34efc74
Merge branch 'master' into historical_ledger_secrets
achamayou Jan 21, 2021
d6c8546
Merge branch 'master' into historical_ledger_secrets
jumaffre Jan 22, 2021
1b9f8d0
Merge branch 'master' into historical_ledger_secrets
jumaffre Jan 22, 2021
e75a280
Update src/node/ledger_secrets.h
jumaffre Jan 22, 2021
970baef
Performance!
Jan 22, 2021
f2a4b50
WIP: Faster on backup catchup
Jan 22, 2021
03cd273
Re-add hint for historical queries
Jan 22, 2021
e1bb80d
Simplify logic
Jan 22, 2021
13e9793
Cleanup
Jan 22, 2021
33d754a
Merge branch 'master' into historical_ledger_secrets
jumaffre Jan 22, 2021
6f6c72c
fmt
Jan 22, 2021
4d775ac
Decouple store's strict version from historical flag
Jan 22, 2021
ad79b69
WIP
Jan 23, 2021
bc4b1f5
WIP - recovering previous ledger secret version
Jan 27, 2021
5b771c2
Merge remote-tracking branch 'upstream/master' into recovery_historic…
Jan 28, 2021
b849552
Cleanup
Jan 28, 2021
5b693f4
Simplify issue recovery share interface
Jan 29, 2021
9ae2bb3
WIP splitting recovery shares table
Jan 29, 2021
1cd7d44
Merge remote-tracking branch 'upstream/master' into recovery_historic…
Jan 29, 2021
0b8e232
Compiles
Jan 29, 2021
d096e82
Recovery works again
Jan 29, 2021
1dbe721
Simplify shares table
Jan 29, 2021
57208fe
Recovery test works again!
Jan 29, 2021
e18f912
Add pure reshuffle
Jan 29, 2021
af8918e
Snapshot fix
Jan 31, 2021
83d3548
Fixed unit test
Jan 31, 2021
d3ccde4
Cleanup
Jan 31, 2021
f9f1a42
Rename
Jan 31, 2021
2476047
Format
Jan 31, 2021
24fe8dd
Shuffle instead of new shares
Jan 31, 2021
21c8b08
Set recovery hook before deserialising snapshot
Feb 1, 2021
bda0848
Merge branch 'master' into recovery_historical_secrets
jumaffre Feb 1, 2021
94d375f
Merge branch 'master' into recovery_historical_secrets
achamayou Feb 2, 2021
ae306d9
PR comments
Feb 3, 2021
6d1743c
d'oh
Feb 3, 2021
e9dbfe7
Merge remote-tracking branch 'upstream/master' into recovery_historic…
Feb 3, 2021
e4d4854
Merge branch 'master' into recovery_historical_secrets
jumaffre Feb 4, 2021
a6c354d
Merge branch 'master' into recovery_historical_secrets
jumaffre Feb 4, 2021
2f22cd6
Added comment to clarify optional value being always set
Feb 4, 2021
56b775c
Merge branch 'master' into recovery_historical_secrets
eddyashton Feb 4, 2021
b332e2a
Merge branch 'master' into recovery_historical_secrets
achamayou Feb 4, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ if(BUILD_TESTS)
NAME recovery_test
PYTHON_SCRIPT ${CMAKE_SOURCE_DIR}/tests/recovery.py
CONSENSUS cft
ADDITIONAL_ARGS --recovery 2
ADDITIONAL_ARGS --recovery 3
)

add_e2e_test(
Expand Down
3 changes: 1 addition & 2 deletions src/crypto/symmetric_key.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,9 @@ namespace crypto
return serial;
}

void apply(const std::vector<uint8_t>& serial)
void deserialise(const std::vector<uint8_t>& serial)
{
auto size = serial.size();

auto data_ = serial.data();
hdr = serialized::read(data_, size, GcmHeader<>::RAW_DATA_SIZE);
cipher = serialized::read(data_, size, size);
Expand Down
2 changes: 2 additions & 0 deletions src/node/entities.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ namespace ccf
static constexpr auto GOV_HISTORY = "public:ccf.gov.governance.history";
static constexpr auto SERVICE = "public:ccf.gov.service";
static constexpr auto SHARES = "public:ccf.gov.shares";
static constexpr auto ENCRYPTED_LEDGER_SECRETS =
jumaffre marked this conversation as resolved.
Show resolved Hide resolved
"public:ccf.internal.encrypted_ledger_secrets";
static constexpr auto CONFIGURATION = "public:ccf.gov.config";
static constexpr auto SUBMITTED_SHARES = "public:ccf.gov.submitted_shares";
static constexpr auto SNAPSHOT_EVIDENCE =
Expand Down
6 changes: 0 additions & 6 deletions src/node/genesis_gen.h
Original file line number Diff line number Diff line change
Expand Up @@ -443,12 +443,6 @@ namespace ccf
codeid->put(node_code_id, CodeStatus::ALLOWED_TO_JOIN);
}

void add_key_share_info(const RecoverySharesInfo& key_share_info)
{
auto shares = tx.rw(tables.shares);
shares->put(0, key_share_info);
}

bool set_recovery_threshold(size_t threshold, bool allow_zero = false)
{
auto config = tx.rw(tables.config);
Expand Down
14 changes: 6 additions & 8 deletions src/node/ledger_secrets.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ namespace ccf
}

using LedgerSecretsMap = std::map<kv::Version, LedgerSecret>;
using VersionedLedgerSecret = LedgerSecretsMap::value_type;

class LedgerSecrets
{
Expand Down Expand Up @@ -160,7 +161,7 @@ namespace ccf
self = id;
}

LedgerSecretsMap::value_type get_latest(kv::Tx& tx)
VersionedLedgerSecret get_latest(kv::Tx& tx)
{
std::lock_guard<SpinLock> guard(lock);

Expand All @@ -172,12 +173,10 @@ namespace ccf
"Could not retrieve latest ledger secret: no secret set");
}

const auto& latest_ledger_secret = ledger_secrets.rbegin();
return std::make_pair(
latest_ledger_secret->first, latest_ledger_secret->second);
return *ledger_secrets.rbegin();
}

std::pair<LedgerSecret, std::optional<LedgerSecret>>
std::pair<VersionedLedgerSecret, std::optional<VersionedLedgerSecret>>
get_latest_and_penultimate(kv::Tx& tx)
{
std::lock_guard<SpinLock> guard(lock);
Expand All @@ -193,11 +192,10 @@ namespace ccf
const auto& latest_ledger_secret = ledger_secrets.rbegin();
if (ledger_secrets.size() < 2)
{
return std::make_pair(latest_ledger_secret->second, std::nullopt);
return std::make_pair(*latest_ledger_secret, std::nullopt);
}
return std::make_pair(
latest_ledger_secret->second,
std::next(ledger_secrets.rbegin())->second);
*latest_ledger_secret, *std::next(latest_ledger_secret));
}

LedgerSecretsMap get(
Expand Down
4 changes: 3 additions & 1 deletion src/node/network_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ namespace ccf
CodeIDs node_code_ids;
MemberAcks member_acks;
GovernanceHistory governance_history;
Shares shares;
RecoveryShares shares;
EncryptedLedgerSecretsInfo encrypted_ledger_secrets;
SubmittedShares submitted_shares;
Configuration config;

Expand Down Expand Up @@ -121,6 +122,7 @@ namespace ccf
member_acks(Tables::MEMBER_ACKS),
governance_history(Tables::GOV_HISTORY),
shares(Tables::SHARES),
encrypted_ledger_secrets(Tables::ENCRYPTED_LEDGER_SECRETS),
submitted_shares(Tables::SUBMITTED_SHARES),
config(Tables::CONFIGURATION),
ca_certs(Tables::CA_CERT_DERS),
Expand Down
104 changes: 44 additions & 60 deletions src/node/node_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ namespace ccf
crypto::Sha256Hash recovery_root;
std::vector<kv::Version> view_history;
consensus::Index last_recovered_signed_idx = 1;
std::list<RecoveredLedgerSecret> recovery_ledger_secrets;
RecoveredEncryptedLedgerSecrets recovery_ledger_secrets;
consensus::Index ledger_idx = 0;

struct StartupSnapshotInfo
Expand Down Expand Up @@ -380,7 +380,7 @@ namespace ccf

setup_snapshotter(config.snapshot_tx_interval);
bool from_snapshot = !config.startup_snapshot.empty();
setup_recovery_hook(from_snapshot);
setup_recovery_hook();

if (from_snapshot)
{
Expand Down Expand Up @@ -480,6 +480,14 @@ namespace ccf
setup_progress_tracker();
setup_history();

if (resp.network_info.public_only)
{
last_recovered_signed_idx =
resp.network_info.last_recovered_signed_idx;
setup_recovery_hook();
snapshotter->set_snapshot_generation(false);
}

if (startup_snapshot_info)
{
// It is only possible to deserialise the entire snapshot then,
Expand Down Expand Up @@ -538,11 +546,6 @@ namespace ccf

if (resp.network_info.public_only)
{
last_recovered_signed_idx =
resp.network_info.last_recovered_signed_idx;
setup_recovery_hook(startup_snapshot_info != nullptr);
snapshotter->set_snapshot_generation(false);

sm.advance(State::partOfPublicNetwork);
}
else
Expand Down Expand Up @@ -1004,8 +1007,7 @@ namespace ccf

// Shares for the new ledger secret can only be issued now, once the
// previous ledger secrets have been recovered
share_manager.issue_shares_on_recovery(
tx, last_recovered_signed_idx + 1);
share_manager.issue_recovery_shares(tx);
GenesisGenerator g(network, tx);
if (!g.open_service())
{
Expand Down Expand Up @@ -1116,8 +1118,8 @@ namespace ccf
std::lock_guard<SpinLock> guard(lock);
sm.expect(State::partOfPublicNetwork);

auto restored_ledger_secrets =
share_manager.restore_recovery_shares_info(tx, recovery_ledger_secrets);
auto restored_ledger_secrets = share_manager.restore_recovery_shares_info(
tx, std::move(recovery_ledger_secrets));

// Broadcast decrypted ledger secrets to other nodes for them to initiate
// private recovery too
Expand All @@ -1139,7 +1141,6 @@ namespace ccf
ledger_idx = recovery_store->current_version();
read_ledger_idx(++ledger_idx);

recovery_ledger_secrets.clear();
sm.advance(State::readingPrivateLedger);
}

Expand Down Expand Up @@ -1280,7 +1281,7 @@ namespace ccf
// once the local hook on the secrets table has been triggered.

auto new_ledger_secret = make_ledger_secret();
share_manager.issue_shares_on_rekey(tx, new_ledger_secret);
share_manager.issue_recovery_shares(tx, new_ledger_secret);
LedgerSecretsBroadcast::broadcast_new(
network, node_encrypt_kp, tx, std::move(new_ledger_secret));

Expand Down Expand Up @@ -1595,68 +1596,51 @@ namespace ccf
return last_recovered_signed_idx;
}

void setup_recovery_hook(bool from_snapshot)
void setup_recovery_hook()
{
// When recoverying from a snapshot, the first secret is valid from the
// version at which it was recorded
static bool is_first_secret = !from_snapshot;

network.tables->set_map_hook(
network.shares.get_name(),
network.shares.wrap_map_hook(
[this](kv::Version version, const Shares::Write& w)
network.encrypted_ledger_secrets.get_name(),
network.encrypted_ledger_secrets.wrap_map_hook(
[this](
kv::Version version, const EncryptedLedgerSecretsInfo::Write& w)
-> kv::ConsensusHookPtr {
for (const auto& [k, opt_v] : w)
if (w.size() > 1)
{
if (!opt_v.has_value())
{
throw std::logic_error(
fmt::format("Unexpected: removal from shares table ({})", k));
}
throw std::logic_error(fmt::format(
"Transaction contains {} writes to map {}, expected one",
w.size(),
network.encrypted_ledger_secrets.get_name()));
}

const auto& v = opt_v.value();
auto encrypted_ledger_secret_info = w.at(0);
if (!encrypted_ledger_secret_info.has_value())
{
throw std::logic_error(fmt::format(
"Removal from {} table",
network.encrypted_ledger_secrets.get_name()));
}

kv::Version ledger_secret_version;
if (is_first_secret)
{
// Special case for the first recovery share issuing (at network
// open), which is applicable from the very first transaction.
ledger_secret_version = 1;
is_first_secret = false;
}
else
{
// If the version is not set (rekeying), use the version
// from the hook plus one. Otherwise (recovery), use the
// version specified.
ledger_secret_version =
v.wrapped_latest_ledger_secret.version == kv::NoVersion ?
(version + 1) :
v.wrapped_latest_ledger_secret.version;
}
// If the version of the next ledger secret is not set, deduce it
// from the hook version (i.e. ledger rekey)
if (!encrypted_ledger_secret_info->next_version.has_value())
{
encrypted_ledger_secret_info->next_version = version + 1;
}

// No encrypted ledger secret are stored in the case of a pure
// re-share (i.e. no ledger rekey).
if (
!v.encrypted_previous_ledger_secret.empty() ||
ledger_secret_version == 1)
{
LOG_TRACE_FMT(
"Adding one encrypted recovery ledger secret at {}",
ledger_secret_version);
LOG_DEBUG_FMT(
"Recovering encrypted ledger secret valid at seqno {}", version);

recovery_ledger_secrets.push_back(
{ledger_secret_version, v.encrypted_previous_ledger_secret});
}
}
recovery_ledger_secrets.emplace_back(
std::move(encrypted_ledger_secret_info.value()));

return kv::ConsensusHookPtr(nullptr);
}));
}

void reset_recovery_hook()
{
network.tables->unset_map_hook(network.shares.get_name());
network.tables->unset_map_hook(
network.encrypted_ledger_secrets.get_name());
}

void setup_n2n_channels()
Expand Down
9 changes: 4 additions & 5 deletions src/node/rpc/member_frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -936,7 +936,7 @@ namespace ccf
// allocated to each recovery member
try
{
share_manager.issue_shares(tx);
share_manager.issue_recovery_shares(tx);
}
catch (const std::logic_error& e)
{
Expand Down Expand Up @@ -975,7 +975,7 @@ namespace ccf
const ProposalId& proposal_id, kv::Tx& tx, const nlohmann::json&) {
try
{
share_manager.issue_shares(tx);
share_manager.shuffle_recovery_shares(tx);
}
catch (const std::logic_error& e)
{
Expand Down Expand Up @@ -1008,10 +1008,9 @@ namespace ccf
return false;
}

// Update recovery shares (same number of shares)
try
{
share_manager.issue_shares(tx);
share_manager.shuffle_recovery_shares(tx);
}
catch (const std::logic_error& e)
{
Expand Down Expand Up @@ -1715,7 +1714,7 @@ namespace ccf
// member, all recovery members are allocated new recovery shares
try
{
share_manager.issue_shares(ctx.tx);
share_manager.shuffle_recovery_shares(ctx.tx);
}
catch (const std::logic_error& e)
{
Expand Down
2 changes: 1 addition & 1 deletion src/node/rpc/test/member_voting_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1784,7 +1784,7 @@ DOCTEST_TEST_CASE("Submit recovery shares")
members[id] = {cert, enc_kp};
}
gen.set_recovery_threshold(recovery_threshold);
share_manager.issue_shares(gen_tx);
share_manager.issue_recovery_shares(gen_tx);
gen.finalize();
frontend.open();
}
Expand Down
8 changes: 7 additions & 1 deletion src/node/rpc/test/node_stub.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,13 @@ namespace ccf

void initiate_private_recovery(kv::Tx& tx) override
{
share_manager.restore_recovery_shares_info(tx, {});
kv::Version current_ledger_secret_version = 1;
RecoveredEncryptedLedgerSecrets recovered_secrets;
recovered_secrets.push_back(
EncryptedLedgerSecretInfo{std::nullopt, current_ledger_secret_version});

share_manager.restore_recovery_shares_info(
tx, std::move(recovered_secrets));
}
};
}
2 changes: 1 addition & 1 deletion src/node/secret_broadcast.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ namespace ccf
const std::vector<uint8_t>& cipher)
{
crypto::GcmCipher gcmcipher;
gcmcipher.apply(cipher);
gcmcipher.deserialise(cipher);
std::vector<uint8_t> plain(gcmcipher.cipher.size());

crypto::KeyAesGcm primary_shared_key(
Expand Down
Loading