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

TEST CI #918 + #972 #973

Closed
wants to merge 35 commits into from
Closed
Changes from 1 commit
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
58941e2
upgrade primitives to allow changing validation function
rphmeier Mar 15, 2020
753ea08
set up storage schema for old parachains code
rphmeier Mar 15, 2020
ddfa72f
fix compilation errors
rphmeier Mar 16, 2020
d66a544
fix test compilation
rphmeier Mar 16, 2020
ba6b392
add some tests for past code meta
rphmeier Mar 16, 2020
d87c034
most of the runtime logic for code upgrades
rphmeier Mar 16, 2020
fd07208
implement old-code pruning
rphmeier Mar 18, 2020
dcd2a22
add a couple tests
rphmeier Mar 19, 2020
f26c6d5
clean up remaining TODOs
rphmeier Mar 19, 2020
85adf9f
add a whole bunch of tests for runtime functionality
rphmeier Mar 20, 2020
a7cc5a8
remove unused function
rphmeier Mar 20, 2020
847bbbb
fix runtime compilation
rphmeier Mar 20, 2020
b265719
extract some primitives to parachain crate
rphmeier Mar 20, 2020
7008912
add validation-code upgrades to validation params and result
rphmeier Mar 20, 2020
b331fd1
extend validation params with code upgrade fields
rphmeier Mar 20, 2020
554ed89
provide maximums to validation params
rphmeier Mar 20, 2020
c9b324b
port test-parachains
rphmeier Mar 20, 2020
38d724c
add a code-upgrader test-parachain and tests
rphmeier Mar 20, 2020
43888e3
fix collator tests
rphmeier Mar 22, 2020
71d23d3
Merge branch 'master' into rh-upgradeable-validation-function
rphmeier Mar 22, 2020
e638aa5
move test-parachains to own folder to work around compilation errors
rphmeier Mar 22, 2020
87e0dcc
Merge branch 'master' into rh-upgradeable-validation-function
rphmeier Mar 22, 2020
87de26e
Merge branch 'master' into rh-upgradeable-validation-function
rphmeier Mar 22, 2020
a4b5b09
fix test compilation
rphmeier Mar 22, 2020
1442886
Merge branch 'master' into rh-upgradeable-validation-function
rphmeier Mar 30, 2020
8026746
Merge branch 'master' into rh-upgradeable-validation-function
rphmeier Apr 1, 2020
052de96
update the Cargo.lock
rphmeier Apr 1, 2020
fa80d0a
fix parachains tests
rphmeier Apr 2, 2020
ff534ce
remove dbg! invocation
rphmeier Apr 2, 2020
a10ca44
refactor out validation hosts to pool struct
rphmeier Apr 3, 2020
c520c4a
Merge branch 'rh-validation-pool' into rh-upg-and-pool
rphmeier Apr 3, 2020
1102633
use new pool in code-upgrader
rphmeier Apr 3, 2020
8b5b2cc
make web-wasm compatible
rphmeier Apr 3, 2020
9170e81
typo
rphmeier Apr 3, 2020
64cb069
Merge branch 'rh-validation-pool' into rh-upg-and-pool
rphmeier Apr 3, 2020
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
Prev Previous commit
Next Next commit
add a whole bunch of tests for runtime functionality
  • Loading branch information
rphmeier committed Mar 20, 2020
commit 85adf9f293c5db92fd046c1730dc343c0e52e43e
275 changes: 272 additions & 3 deletions runtime/common/src/parachains.rs
Original file line number Diff line number Diff line change
Expand Up @@ -795,8 +795,10 @@ impl<T: Trait> Module<T> {
Scheduling::Always => {},
Scheduling::Dynamic => return None, // parathreads can't upgrade code.
}

// if perceived-height were not the parent of `now`, then this should
// not be drawn from current-runtime configuration.
// not be drawn from current-runtime configuration. however the sanity-check
// above prevents that.
let min_upgrade_frequency = T::ValidationUpgradeFrequency::get();
let upgrade_delay = T::ValidationUpgradeDelay::get();

Expand Down Expand Up @@ -833,6 +835,18 @@ impl<T: Trait> Module<T> {
}
}

/// Fetch the code used for verifying a parachain at a particular height.
pub fn parachain_code_at(id: &ParaId, at: T::BlockNumber) -> Option<Vec<u8>> {
// note - we don't check that the parachain is currently registered
// as this might be a deregistered parachain whose old code should still
// stick around on-chain for some time.
Self::past_code_meta(id).code_at(at).and_then(|to_use| match to_use {
UseCodeAt::Current => Self::parachain_code(id),
UseCodeAt::ReplacedAt(replaced_at) =>
<Self as Store>::PastCode::get(&(*id, replaced_at)),
})
}

/// Get the currently active set of parachains.
pub fn active_parachains() -> Vec<(ParaId, Option<(CollatorId, Retriable)>)> {
T::ActiveParachains::active_paras()
Expand Down Expand Up @@ -2182,11 +2196,266 @@ mod tests {

#[test]
fn code_upgrade_applied_after_delay() {
// TODO [now]
let parachains = vec![
(0u32.into(), vec![1, 2, 3], vec![]),
];

new_test_ext(parachains.clone()).execute_with(|| {
let para_id = ParaId::from(0);
let new_code = vec![4, 5, 6];

run_to_block(2);
assert_eq!(Parachains::active_parachains().len(), 1);
assert_eq!(Parachains::parachain_code(&para_id), Some(vec![1, 2, 3]));

let applied_after ={
let raw_candidate = raw_candidate(para_id);
let applied_after = raw_candidate.local_validation.code_upgrade_allowed.unwrap();
let mut candidate_a = make_blank_attested(raw_candidate);

candidate_a.candidate.commitments.new_validation_code = Some(new_code.clone());

// this parablock is in the context of block 1.
assert_eq!(applied_after, 1 + ValidationUpgradeDelay::get());
make_attestations(&mut candidate_a);

assert_ok!(Parachains::dispatch(
set_heads(vec![candidate_a.clone()]),
Origin::NONE,
));

assert!(Parachains::past_code_meta(&para_id).most_recent_change().is_none());
assert_eq!(Parachains::code_upgrade_schedule(&para_id), Some(applied_after));
assert_eq!(<Parachains as Store>::FutureCode::get(&para_id), new_code);
assert_eq!(Parachains::parachain_code(&para_id), Some(vec![1, 2, 3]));

applied_after
};

run_to_block(applied_after);

// the candidate is in the context of the parent of `applied_after`,
// thus does not trigger the code upgrade.
{
let raw_candidate = raw_candidate(para_id);
assert!(raw_candidate.local_validation.code_upgrade_allowed.is_none());
let mut candidate_a = make_blank_attested(raw_candidate);

make_attestations(&mut candidate_a);

assert_ok!(Parachains::dispatch(
set_heads(vec![candidate_a.clone()]),
Origin::NONE,
));

assert!(Parachains::past_code_meta(&para_id).most_recent_change().is_none());
assert_eq!(Parachains::code_upgrade_schedule(&para_id), Some(applied_after));
assert_eq!(<Parachains as Store>::FutureCode::get(&para_id), new_code);
assert_eq!(Parachains::parachain_code(&para_id), Some(vec![1, 2, 3]));
}

run_to_block(applied_after + 1);

// the candidate is in the context of `applied_after`, and triggers
// the upgrade.
{
let raw_candidate = raw_candidate(para_id);
assert!(raw_candidate.local_validation.code_upgrade_allowed.is_some());
let mut candidate_a = make_blank_attested(raw_candidate);

make_attestations(&mut candidate_a);

assert_ok!(Parachains::dispatch(
set_heads(vec![candidate_a.clone()]),
Origin::NONE,
));

assert_eq!(
Parachains::past_code_meta(&para_id).most_recent_change(),
Some(applied_after),
);
assert_eq!(
<Parachains as Store>::PastCode::get(&(para_id, applied_after)),
Some(vec![1, 2, 3,]),
);
assert!(Parachains::code_upgrade_schedule(&para_id).is_none());
assert!(<Parachains as Store>::FutureCode::get(&para_id).is_empty());
assert_eq!(Parachains::parachain_code(&para_id), Some(new_code));
}
});
}


#[test]
fn code_upgrade_applied_after_delay_even_when_late() {
let parachains = vec![
(0u32.into(), vec![1, 2, 3], vec![]),
];

new_test_ext(parachains.clone()).execute_with(|| {
let para_id = ParaId::from(0);
let new_code = vec![4, 5, 6];

run_to_block(2);
assert_eq!(Parachains::active_parachains().len(), 1);
assert_eq!(Parachains::parachain_code(&para_id), Some(vec![1, 2, 3]));

let applied_after ={
let raw_candidate = raw_candidate(para_id);
let applied_after = raw_candidate.local_validation.code_upgrade_allowed.unwrap();
let mut candidate_a = make_blank_attested(raw_candidate);

candidate_a.candidate.commitments.new_validation_code = Some(new_code.clone());

// this parablock is in the context of block 1.
assert_eq!(applied_after, 1 + ValidationUpgradeDelay::get());
make_attestations(&mut candidate_a);

assert_ok!(Parachains::dispatch(
set_heads(vec![candidate_a.clone()]),
Origin::NONE,
));

assert!(Parachains::past_code_meta(&para_id).most_recent_change().is_none());
assert_eq!(Parachains::code_upgrade_schedule(&para_id), Some(applied_after));
assert_eq!(<Parachains as Store>::FutureCode::get(&para_id), new_code);
assert_eq!(Parachains::parachain_code(&para_id), Some(vec![1, 2, 3]));

applied_after
};

run_to_block(applied_after + 1 + 4);

{
let raw_candidate = raw_candidate(para_id);
assert!(raw_candidate.local_validation.code_upgrade_allowed.is_some());
let mut candidate_a = make_blank_attested(raw_candidate);

make_attestations(&mut candidate_a);

assert_ok!(Parachains::dispatch(
set_heads(vec![candidate_a.clone()]),
Origin::NONE,
));

assert_eq!(
Parachains::past_code_meta(&para_id).most_recent_change(),
Some(applied_after + 4),
);
assert_eq!(
<Parachains as Store>::PastCode::get(&(para_id, applied_after + 4)),
Some(vec![1, 2, 3,]),
);
assert!(Parachains::code_upgrade_schedule(&para_id).is_none());
assert!(<Parachains as Store>::FutureCode::get(&para_id).is_empty());
assert_eq!(Parachains::parachain_code(&para_id), Some(new_code));
}
});
}

#[test]
fn submit_code_change_when_not_allowed_is_err() {
let parachains = vec![
(0u32.into(), vec![1, 2, 3], vec![]),
];

new_test_ext(parachains.clone()).execute_with(|| {
let para_id = ParaId::from(0);
let new_code = vec![4, 5, 6];

run_to_block(2);

{
let raw_candidate = raw_candidate(para_id);
let mut candidate_a = make_blank_attested(raw_candidate);

candidate_a.candidate.commitments.new_validation_code = Some(new_code.clone());

make_attestations(&mut candidate_a);

assert_ok!(Parachains::dispatch(
set_heads(vec![candidate_a.clone()]),
Origin::NONE,
));
};

run_to_block(3);

{
let raw_candidate = raw_candidate(para_id);
assert!(raw_candidate.local_validation.code_upgrade_allowed.is_none());
let mut candidate_a = make_blank_attested(raw_candidate);
candidate_a.candidate.commitments.new_validation_code = Some(vec![1, 2, 3]);

make_attestations(&mut candidate_a);

assert_err!(
Parachains::dispatch(
set_heads(vec![candidate_a.clone()]),
Origin::NONE,
),
Error::<Test>::DisallowedCodeUpgrade,
);
}
});
}

#[test]
fn full_parachain_cleanup_storage() {
// TODO [now]
let parachains = vec![
(0u32.into(), vec![1, 2, 3], vec![]),
];

new_test_ext(parachains.clone()).execute_with(|| {
let para_id = ParaId::from(0);
let new_code = vec![4, 5, 6];

run_to_block(2);
{
let raw_candidate = raw_candidate(para_id);
let applied_after = raw_candidate.local_validation.code_upgrade_allowed.unwrap();
let mut candidate_a = make_blank_attested(raw_candidate);

candidate_a.candidate.commitments.new_validation_code = Some(new_code.clone());

// this parablock is in the context of block 1.
assert_eq!(applied_after, 1 + ValidationUpgradeDelay::get());
make_attestations(&mut candidate_a);

assert_ok!(Parachains::dispatch(
set_heads(vec![candidate_a.clone()]),
Origin::NONE,
));

assert!(Parachains::past_code_meta(&para_id).most_recent_change().is_none());
assert_eq!(Parachains::code_upgrade_schedule(&para_id), Some(applied_after));
assert_eq!(<Parachains as Store>::FutureCode::get(&para_id), new_code);
assert_eq!(Parachains::parachain_code(&para_id), Some(vec![1, 2, 3]));

assert!(Parachains::past_code_pruning_tasks().is_empty());
};

Parachains::cleanup_para(para_id);

// cleaning up the parachain should place the current parachain code
// into the past code buffer & schedule cleanup.
assert_eq!(Parachains::past_code_meta(&para_id).most_recent_change(), Some(2));
assert_eq!(<Parachains as Store>::PastCode::get(&(para_id, 2)), Some(vec![1, 2, 3]));
assert_eq!(Parachains::past_code_pruning_tasks(), vec![(para_id, 2)]);

// any future upgrades haven't been used to validate yet, so those
// are cleaned up immediately.
assert!(Parachains::code_upgrade_schedule(&para_id).is_none());
assert!(<Parachains as Store>::FutureCode::get(&para_id).is_empty());
assert!(Parachains::parachain_code(&para_id).is_none());

let cleaned_up_at = 2 + SlashPeriod::get() + 1;
run_to_block(cleaned_up_at);

// now the final cleanup: last past code cleaned up, and this triggers meta cleanup.
assert_eq!(Parachains::past_code_meta(&para_id), Default::default());
assert!(<Parachains as Store>::PastCode::get(&(para_id, 2)).is_none());
assert!(Parachains::past_code_pruning_tasks().is_empty());
});
}
}