Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

RollingSessionWindow cleanup #7204

Merged
merged 46 commits into from
May 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
5eb24c6
Replace `RollingSessionWindow` with `RuntimeInfo` - initial commit
tdimitrov Apr 13, 2023
b0da049
Fix tests in import
tdimitrov Apr 20, 2023
93e6863
Fix the rest of the tests
tdimitrov Apr 20, 2023
a7b74cc
Remove dead code
tdimitrov Apr 20, 2023
0f84b42
Fix todos
tdimitrov Apr 21, 2023
0e486d4
Simplify session caching
tdimitrov Apr 21, 2023
f6a9d98
Comments for `SessionInfoProvider`
tdimitrov Apr 21, 2023
2918b42
Separate `SessionInfoProvider` from `State`
tdimitrov Apr 21, 2023
837f952
`cache_session_info_for_head` becomes freestanding function
tdimitrov Apr 21, 2023
6f609f3
Remove unneeded `mut` usage
tdimitrov Apr 21, 2023
82a0ebc
fn session_info -> fn get_session_info() to avoid name clashes. The f…
tdimitrov Apr 24, 2023
dca7287
Fix SessionInfo retrieval
tdimitrov Apr 24, 2023
360b96d
Code cleanup
tdimitrov Apr 24, 2023
caa2529
Don't wrap `SessionInfoProvider` in an `Option`
tdimitrov Apr 25, 2023
7665ecd
Remove `earliest_session()`
tdimitrov Apr 27, 2023
3f2b85c
Remove pre-caching -> wip
tdimitrov Apr 28, 2023
19e9588
Fix some tests and code cleanup
tdimitrov May 2, 2023
70d136f
Fix all tests
tdimitrov May 2, 2023
6e348c9
Fixes in tests
tdimitrov May 2, 2023
4fa4403
Fix comments, variable names and small style changes
tdimitrov May 2, 2023
dc0542a
Fix a warning
tdimitrov May 2, 2023
233478e
impl From<SessionWindowSize> for NonZeroUsize
tdimitrov May 5, 2023
d27220a
Fix logging for `get_session_info` - remove redundant logs and decrea…
tdimitrov May 6, 2023
407eb27
Merge branch 'master' into tsv-rolling-session-approval-voting
tdimitrov May 6, 2023
2ed7dfd
Code review feedback
tdimitrov May 9, 2023
dcac680
Merge branch 'master' into tsv-rolling-session-approval-voting
tdimitrov May 10, 2023
96ffefe
Storage migration removing `COL_SESSION_WINDOW_DATA` from parachains db
tdimitrov May 9, 2023
81acb35
Remove `col_session_data` usages
tdimitrov May 9, 2023
14eb540
Storage migration clearing columns w/o removing them
tdimitrov May 11, 2023
0606eee
Remove session data column usages from `approval-voting` and `dispute…
tdimitrov May 11, 2023
6a2a9e2
Add some test cases from `RollingSessionWindow` to `dispute-coordinat…
tdimitrov May 12, 2023
0f94664
Fix formatting in initialized.rs
tdimitrov May 12, 2023
db120f6
Fix a corner case in `SessionInfo` caching for `dispute-coordinator`
tdimitrov May 12, 2023
0ffd17f
Remove `RollingSessionWindow` ;(
tdimitrov May 12, 2023
7d83f95
Revert "Fix formatting in initialized.rs"
tdimitrov May 12, 2023
b938b92
Merge branch 'master' into tsv-rolling-session-window-cleanup
tdimitrov May 16, 2023
39ae191
v2 to v3 migration drops `COL_DISPUTE_COORDINATOR_DATA` instead of cl…
tdimitrov May 16, 2023
84c134a
Fix `NUM_COLUMNS` in `approval-voting`
tdimitrov May 16, 2023
c7439c5
Use `columns::v3::NUM_COLUMNS` when opening db
tdimitrov May 18, 2023
2f6b33b
Update node/service/src/parachains_db/upgrade.rs
tdimitrov May 25, 2023
0ccfe2c
Don't write in `COL_DISPUTE_COORDINATOR_DATA` for `test_rocksdb_migra…
tdimitrov May 25, 2023
ab7197d
Fix `NUM+COLUMNS` in approval_voting
tdimitrov May 25, 2023
40daf94
Merge branch 'master' into tsv-rolling-session-window-cleanup
tdimitrov May 29, 2023
44fe75a
Fix formatting
tdimitrov May 29, 2023
bbbd5ee
Fix columns usage
tdimitrov May 29, 2023
4b45afb
Clarification comments about the different db versions
tdimitrov May 29, 2023
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
8 changes: 6 additions & 2 deletions node/core/approval-voting/src/approval_db/v1/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.

//! Version 1 of the DB schema.
//!
//! Note that the version here differs from the actual version of the parachains
//! database (check `CURRENT_VERSION` in `node/service/src/parachains_db/upgrade.rs`).
//! The code in this module implements the way approval voting works with
//! its data in the database. Any breaking changes here will still
//! require a db migration (check `node/service/src/parachains_db/upgrade.rs`).

use parity_scale_codec::{Decode, Encode};
use polkadot_node_primitives::approval::{AssignmentCert, DelayTranche};
Expand Down Expand Up @@ -154,8 +160,6 @@ pub type Bitfield = BitVec<u8, BitOrderLsb0>;
pub struct Config {
/// The column family in the database where data is stored.
pub col_approval_data: u32,
/// The column of the database where rolling session window data is stored.
pub col_session_data: u32,
}

/// Details pertaining to our assignment on a block.
Expand Down
6 changes: 2 additions & 4 deletions node/core/approval-voting/src/approval_db/v1/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,10 @@ use std::{collections::HashMap, sync::Arc};
use ::test_helpers::{dummy_candidate_receipt, dummy_candidate_receipt_bad_sig, dummy_hash};

const DATA_COL: u32 = 0;
const SESSION_DATA_COL: u32 = 1;

const NUM_COLUMNS: u32 = 2;
const NUM_COLUMNS: u32 = 1;

const TEST_CONFIG: Config =
Config { col_approval_data: DATA_COL, col_session_data: SESSION_DATA_COL };
const TEST_CONFIG: Config = Config { col_approval_data: DATA_COL };

fn make_db() -> (DbBackend, Arc<dyn Database>) {
let db = kvdb_memorydb::create(NUM_COLUMNS);
Expand Down
6 changes: 2 additions & 4 deletions node/core/approval-voting/src/import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -609,12 +609,10 @@ pub(crate) mod tests {
use crate::{approval_db::v1::Config as DatabaseConfig, criteria, BlockEntry};

const DATA_COL: u32 = 0;
const SESSION_DATA_COL: u32 = 1;

const NUM_COLUMNS: u32 = 2;
const NUM_COLUMNS: u32 = 1;

const TEST_CONFIG: DatabaseConfig =
DatabaseConfig { col_approval_data: DATA_COL, col_session_data: SESSION_DATA_COL };
const TEST_CONFIG: DatabaseConfig = DatabaseConfig { col_approval_data: DATA_COL };
#[derive(Default)]
struct MockClock;

Expand Down
13 changes: 3 additions & 10 deletions node/core/approval-voting/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,6 @@ const LOG_TARGET: &str = "parachain::approval-voting";
pub struct Config {
/// The column family in the DB where approval-voting data is stored.
pub col_approval_data: u32,
/// The of the DB where rolling session info is stored.
pub col_session_data: u32,
/// The slot duration of the consensus algorithm, in milliseconds. Should be evenly
/// divisible by 500.
pub slot_duration_millis: u64,
Expand Down Expand Up @@ -357,10 +355,7 @@ impl ApprovalVotingSubsystem {
keystore,
slot_duration_millis: config.slot_duration_millis,
db,
db_config: DatabaseConfig {
col_approval_data: config.col_approval_data,
col_session_data: config.col_session_data,
},
db_config: DatabaseConfig { col_approval_data: config.col_approval_data },
mode: Mode::Syncing(sync_oracle),
metrics,
}
Expand All @@ -369,10 +364,8 @@ impl ApprovalVotingSubsystem {
/// Revert to the block corresponding to the specified `hash`.
/// The operation is not allowed for blocks older than the last finalized one.
pub fn revert_to(&self, hash: Hash) -> Result<(), SubsystemError> {
let config = approval_db::v1::Config {
col_approval_data: self.db_config.col_approval_data,
col_session_data: self.db_config.col_session_data,
};
let config =
approval_db::v1::Config { col_approval_data: self.db_config.col_approval_data };
let mut backend = approval_db::v1::DbBackend::new(self.db.clone(), config);
let mut overlay = OverlayedBackend::new(&backend);

Expand Down
9 changes: 2 additions & 7 deletions node/core/approval-voting/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.

use crate::tests::test_constants::TEST_CONFIG;

use super::*;
use polkadot_node_primitives::{
approval::{
Expand Down Expand Up @@ -115,12 +113,10 @@ fn make_sync_oracle(val: bool) -> (Box<dyn SyncOracle + Send>, TestSyncOracleHan
pub mod test_constants {
use crate::approval_db::v1::Config as DatabaseConfig;
const DATA_COL: u32 = 0;
const SESSION_DATA_COL: u32 = 1;

pub(crate) const NUM_COLUMNS: u32 = 2;
pub(crate) const NUM_COLUMNS: u32 = 1;

pub(crate) const TEST_CONFIG: DatabaseConfig =
DatabaseConfig { col_approval_data: DATA_COL, col_session_data: SESSION_DATA_COL };
pub(crate) const TEST_CONFIG: DatabaseConfig = DatabaseConfig { col_approval_data: DATA_COL };
}

struct MockSupportsParachains;
Expand Down Expand Up @@ -493,7 +489,6 @@ fn test_harness<T: Future<Output = VirtualOverseer>>(
Config {
col_approval_data: test_constants::TEST_CONFIG.col_approval_data,
slot_duration_millis: SLOT_DURATION_MILLIS,
col_session_data: TEST_CONFIG.col_session_data,
},
Arc::new(db),
Arc::new(keystore),
Expand Down
10 changes: 7 additions & 3 deletions node/core/dispute-coordinator/src/db/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.

//! `V1` database for the dispute coordinator.
//!
//! Note that the version here differs from the actual version of the parachains
//! database (check `CURRENT_VERSION` in `node/service/src/parachains_db/upgrade.rs`).
//! The code in this module implements the way dispute coordinator works with
//! the dispute data in the database. Any breaking changes here will still
//! require a db migration (check `node/service/src/parachains_db/upgrade.rs`).

use polkadot_node_primitives::DisputeStatus;
use polkadot_node_subsystem_util::database::{DBTransaction, Database};
Expand Down Expand Up @@ -206,8 +212,6 @@ fn candidate_votes_session_prefix(session: SessionIndex) -> [u8; 15 + 4] {
pub struct ColumnConfiguration {
/// The column in the key-value DB where data is stored.
pub col_dispute_data: u32,
/// The column in the key-value DB where session data is stored.
pub col_session_data: u32,
}

/// Tracked votes on candidates, for the purposes of dispute resolution.
Expand Down Expand Up @@ -378,7 +382,7 @@ mod tests {
let db = kvdb_memorydb::create(1);
let db = polkadot_node_subsystem_util::database::kvdb_impl::DbAdapter::new(db, &[0]);
let store = Arc::new(db);
let config = ColumnConfiguration { col_dispute_data: 0, col_session_data: 1 };
let config = ColumnConfiguration { col_dispute_data: 0 };
DbBackend::new(store, config, Metrics::default())
}

Expand Down
13 changes: 6 additions & 7 deletions node/core/dispute-coordinator/src/initialized.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,13 +305,12 @@ impl Initialized {
Ok(session_idx)
if self.gaps_in_cache || session_idx > self.highest_session_seen =>
{
// If error has occurred during last session caching - fetch the whole window
// Otherwise - cache only the new sessions
let lower_bound = if self.gaps_in_cache {
session_idx.saturating_sub(DISPUTE_WINDOW.get() - 1)
} else {
self.highest_session_seen + 1
};
// Fetch the last `DISPUTE_WINDOW` number of sessions unless there are no gaps in
// cache and we are not missing too many `SessionInfo`s
let mut lower_bound = session_idx.saturating_sub(DISPUTE_WINDOW.get() - 1);
if !self.gaps_in_cache && self.highest_session_seen > lower_bound {
lower_bound = self.highest_session_seen + 1
}

// There is a new session. Perform a dummy fetch to cache it.
for idx in lower_bound..=session_idx {
Expand Down
7 changes: 1 addition & 6 deletions node/core/dispute-coordinator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,16 +127,11 @@ pub struct DisputeCoordinatorSubsystem {
pub struct Config {
/// The data column in the store to use for dispute data.
pub col_dispute_data: u32,
/// The data column in the store to use for session data.
pub col_session_data: u32,
}

impl Config {
fn column_config(&self) -> db::v1::ColumnConfiguration {
db::v1::ColumnConfiguration {
col_dispute_data: self.col_dispute_data,
col_session_data: self.col_session_data,
}
db::v1::ColumnConfiguration { col_dispute_data: self.col_dispute_data }
}
}

Expand Down
180 changes: 177 additions & 3 deletions node/core/dispute-coordinator/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ use polkadot_node_subsystem_util::database::Database;

use polkadot_node_primitives::{
DisputeMessage, DisputeStatus, SignedDisputeStatement, SignedFullStatement, Statement,
DISPUTE_WINDOW,
};
use polkadot_node_subsystem::{
messages::{
Expand Down Expand Up @@ -214,9 +215,9 @@ impl Default for TestState {
make_keystore(vec![Sr25519Keyring::Alice.to_seed()].into_iter()).into();

let db = kvdb_memorydb::create(1);
let db = polkadot_node_subsystem_util::database::kvdb_impl::DbAdapter::new(db, &[]);
let db = polkadot_node_subsystem_util::database::kvdb_impl::DbAdapter::new(db, &[0]);
let db = Arc::new(db);
let config = Config { col_dispute_data: 0, col_session_data: 1 };
let config = Config { col_dispute_data: 0 };

let genesis_header = Header {
parent_hash: Hash::zero(),
Expand Down Expand Up @@ -330,9 +331,11 @@ impl TestState {
assert_eq!(h, block_hash);
let _ = tx.send(Ok(session));

let first_expected_session = session.saturating_sub(DISPUTE_WINDOW.get() - 1);

// Queries for session caching - see `handle_startup`
if self.known_session.is_none() {
for i in 0..=session {
for i in first_expected_session..=session {
assert_matches!(
overseer_recv(virtual_overseer).await,
AllMessages::RuntimeApi(RuntimeApiMessage::Request(
Expand Down Expand Up @@ -3393,3 +3396,174 @@ fn informs_chain_selection_when_dispute_concluded_against() {
})
});
}

// On startup `SessionInfo` cache should be populated
#[test]
fn session_info_caching_on_startup_works() {
test_harness(|mut test_state, mut virtual_overseer| {
Box::pin(async move {
let session = 1;

test_state.handle_resume_sync(&mut virtual_overseer, session).await;

test_state
})
});
}

// Underflow means that no more than `DISPUTE_WINDOW` sessions should be fetched on startup
#[test]
fn session_info_caching_doesnt_underflow() {
test_harness(|mut test_state, mut virtual_overseer| {
Box::pin(async move {
let session = DISPUTE_WINDOW.get() + 1;

test_state.handle_resume_sync(&mut virtual_overseer, session).await;

test_state
})
});
}

// Cached `SessionInfo` shouldn't be re-requested from the runtime
#[test]
fn session_info_is_requested_only_once() {
test_harness(|mut test_state, mut virtual_overseer| {
Box::pin(async move {
let session = 1;

test_state.handle_resume_sync(&mut virtual_overseer, session).await;

// This leaf activation shouldn't fetch `SessionInfo` because the session is already cached
test_state
.activate_leaf_at_session(
&mut virtual_overseer,
session,
3,
vec![make_candidate_included_event(make_valid_candidate_receipt())],
)
.await;

// This leaf activation should fetch `SessionInfo` because the session is new
test_state
.activate_leaf_at_session(
&mut virtual_overseer,
session + 1,
4,
vec![make_candidate_included_event(make_valid_candidate_receipt())],
)
.await;

assert_matches!(
virtual_overseer.recv().await,
AllMessages::RuntimeApi(RuntimeApiMessage::Request(
_,
RuntimeApiRequest::SessionInfo(session_index, tx),
)) => {
assert_eq!(session_index, 2);
let _ = tx.send(Ok(Some(test_state.session_info())));
}
);
test_state
})
});
}

// Big jump means the new session we see with a leaf update is at least a `DISPUTE_WINDOW` bigger than
// the already known one. In this case The whole `DISPUTE_WINDOW` should be fetched.
#[test]
fn session_info_big_jump_works() {
test_harness(|mut test_state, mut virtual_overseer| {
Box::pin(async move {
let session_on_startup = 1;

test_state.handle_resume_sync(&mut virtual_overseer, session_on_startup).await;

// This leaf activation shouldn't fetch `SessionInfo` because the session is already cached
test_state
.activate_leaf_at_session(
&mut virtual_overseer,
session_on_startup,
3,
vec![make_candidate_included_event(make_valid_candidate_receipt())],
)
.await;

let session_after_jump = session_on_startup + DISPUTE_WINDOW.get() + 10;
// This leaf activation should cache all missing `SessionInfo`s
test_state
.activate_leaf_at_session(
&mut virtual_overseer,
session_after_jump,
4,
vec![make_candidate_included_event(make_valid_candidate_receipt())],
)
.await;

let first_expected_session =
session_after_jump.saturating_sub(DISPUTE_WINDOW.get() - 1);
for expected_idx in first_expected_session..=session_after_jump {
assert_matches!(
virtual_overseer.recv().await,
AllMessages::RuntimeApi(RuntimeApiMessage::Request(
_,
RuntimeApiRequest::SessionInfo(session_index, tx),
)) => {
assert_eq!(session_index, expected_idx);
let _ = tx.send(Ok(Some(test_state.session_info())));
}
);
}
test_state
})
});
}

// Small jump means the new session we see with a leaf update is at less than last known one + `DISPUTE_WINDOW`. In this
// case fetching should start from last known one + 1.
#[test]
fn session_info_small_jump_works() {
test_harness(|mut test_state, mut virtual_overseer| {
Box::pin(async move {
let session_on_startup = 1;

test_state.handle_resume_sync(&mut virtual_overseer, session_on_startup).await;

// This leaf activation shouldn't fetch `SessionInfo` because the session is already cached
test_state
.activate_leaf_at_session(
&mut virtual_overseer,
session_on_startup,
3,
vec![make_candidate_included_event(make_valid_candidate_receipt())],
)
.await;

let session_after_jump = session_on_startup + DISPUTE_WINDOW.get() - 1;
// This leaf activation should cache all missing `SessionInfo`s
test_state
.activate_leaf_at_session(
&mut virtual_overseer,
session_after_jump,
4,
vec![make_candidate_included_event(make_valid_candidate_receipt())],
)
.await;

let first_expected_session = session_on_startup + 1;
for expected_idx in first_expected_session..=session_after_jump {
assert_matches!(
virtual_overseer.recv().await,
AllMessages::RuntimeApi(RuntimeApiMessage::Request(
_,
RuntimeApiRequest::SessionInfo(session_index, tx),
)) => {
assert_eq!(session_index, expected_idx);
let _ = tx.send(Ok(Some(test_state.session_info())));
}
);
}
test_state
})
});
}
Loading