Newer
Older
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
#[test]
fn para_past_code_meta_gives_right_code() {
let mut past_code = ParaPastCodeMeta::default();
assert_eq!(past_code.code_at(0u32), Some(UseCodeAt::Current));
past_code.note_replacement(10, 12);
assert_eq!(past_code.code_at(0), Some(UseCodeAt::ReplacedAt(10)));
assert_eq!(past_code.code_at(10), Some(UseCodeAt::ReplacedAt(10)));
assert_eq!(past_code.code_at(11), Some(UseCodeAt::Current));
past_code.note_replacement(20, 25);
assert_eq!(past_code.code_at(1), Some(UseCodeAt::ReplacedAt(10)));
assert_eq!(past_code.code_at(10), Some(UseCodeAt::ReplacedAt(10)));
assert_eq!(past_code.code_at(11), Some(UseCodeAt::ReplacedAt(20)));
assert_eq!(past_code.code_at(20), Some(UseCodeAt::ReplacedAt(20)));
assert_eq!(past_code.code_at(21), Some(UseCodeAt::Current));
past_code.last_pruned = Some(5);
assert_eq!(past_code.code_at(1), None);
assert_eq!(past_code.code_at(5), None);
assert_eq!(past_code.code_at(6), Some(UseCodeAt::ReplacedAt(10)));
}
#[test]
fn para_past_code_pruning_works_correctly() {
let mut past_code = ParaPastCodeMeta::default();
past_code.note_replacement(10u32, 10);
past_code.note_replacement(20, 25);
past_code.note_replacement(30, 35);
let old = past_code.clone();
assert!(past_code.prune_up_to(9).collect::<Vec<_>>().is_empty());
assert_eq!(old, past_code);
assert_eq!(past_code.prune_up_to(10).collect::<Vec<_>>(), vec![10]);
assert_eq!(past_code, ParaPastCodeMeta {
upgrade_times: vec![upgrade_at(20, 25), upgrade_at(30, 35)],
last_pruned: Some(10),
});
assert!(past_code.prune_up_to(21).collect::<Vec<_>>().is_empty());
assert_eq!(past_code.prune_up_to(26).collect::<Vec<_>>(), vec![20]);
assert_eq!(past_code, ParaPastCodeMeta {
upgrade_times: vec![upgrade_at(30, 35)],
last_pruned: Some(20),
});
past_code.note_replacement(40, 42);
past_code.note_replacement(50, 53);
past_code.note_replacement(60, 66);
assert_eq!(past_code, ParaPastCodeMeta {
upgrade_times: vec![upgrade_at(30, 35), upgrade_at(40, 42), upgrade_at(50, 53), upgrade_at(60, 66)],
last_pruned: Some(20),
});
assert_eq!(past_code.prune_up_to(60).collect::<Vec<_>>(), vec![30, 40, 50]);
assert_eq!(past_code, ParaPastCodeMeta {
upgrade_times: vec![upgrade_at(60, 66)],
last_pruned: Some(50),
});
assert_eq!(past_code.prune_up_to(66).collect::<Vec<_>>(), vec![60]);
assert_eq!(past_code, ParaPastCodeMeta {
upgrade_times: Vec::new(),
last_pruned: Some(60),
});
}
#[test]
fn para_past_code_pruning_in_initialize() {
let code_retention_period = 10;
let paras = vec![
(0u32.into(), ParaGenesisArgs {
parachain: true,
genesis_head: Default::default(),
validation_code: Default::default(),
}),
(1u32.into(), ParaGenesisArgs {
parachain: false,
genesis_head: Default::default(),
validation_code: Default::default(),
}),
];
let genesis_config = MockGenesisConfig {
paras: GenesisConfig { paras, ..Default::default() },
configuration: crate::configuration::GenesisConfig {
config: HostConfiguration {
code_retention_period,
..Default::default()
},
..Default::default()
},
..Default::default()
};
new_test_ext(genesis_config).execute_with(|| {
let id = ParaId::from(0u32);
let at_block: BlockNumber = 10;
let included_block: BlockNumber = 12;
let validation_code = ValidationCode(vec![1, 2, 3]);
Paras::increase_code_ref(&validation_code.hash(), &validation_code);
<Paras as Store>::PastCodeHash::insert(&(id, at_block), &validation_code.hash());
<Paras as Store>::PastCodePruning::put(&vec![(id, included_block)]);
{
let mut code_meta = Paras::past_code_meta(&id);
code_meta.note_replacement(at_block, included_block);
<Paras as Store>::PastCodeMeta::insert(&id, &code_meta);
}
let pruned_at: BlockNumber = included_block + code_retention_period + 1;
assert_eq!(<Paras as Store>::PastCodeHash::get(&(id, at_block)), Some(validation_code.hash()));
check_code_is_stored(&validation_code);
run_to_block(pruned_at - 1, None);
assert_eq!(<Paras as Store>::PastCodeHash::get(&(id, at_block)), Some(validation_code.hash()));
assert_eq!(Paras::past_code_meta(&id).most_recent_change(), Some(at_block));
check_code_is_stored(&validation_code);
run_to_block(pruned_at, None);
assert!(<Paras as Store>::PastCodeHash::get(&(id, at_block)).is_none());
assert!(Paras::past_code_meta(&id).most_recent_change().is_none());
check_code_is_not_stored(&validation_code);
#[test]
fn note_new_head_sets_head() {
let code_retention_period = 10;
let paras = vec![
(0u32.into(), ParaGenesisArgs {
parachain: true,
genesis_head: Default::default(),
validation_code: Default::default(),
}),
];
let genesis_config = MockGenesisConfig {
paras: GenesisConfig { paras, ..Default::default() },
configuration: crate::configuration::GenesisConfig {
config: HostConfiguration {
code_retention_period,
..Default::default()
},
..Default::default()
},
..Default::default()
};
new_test_ext(genesis_config).execute_with(|| {
let id_a = ParaId::from(0u32);
assert_eq!(Paras::para_head(&id_a), Some(Default::default()));
Paras::note_new_head(id_a, vec![1, 2, 3].into(), 0);
assert_eq!(Paras::para_head(&id_a), Some(vec![1, 2, 3].into()));
});
}
#[test]
fn note_past_code_sets_up_pruning_correctly() {
let code_retention_period = 10;
let paras = vec![
(0u32.into(), ParaGenesisArgs {
parachain: true,
genesis_head: Default::default(),
validation_code: Default::default(),
}),
(1u32.into(), ParaGenesisArgs {
parachain: false,
genesis_head: Default::default(),
validation_code: Default::default(),
}),
];
let genesis_config = MockGenesisConfig {
paras: GenesisConfig { paras, ..Default::default() },
configuration: crate::configuration::GenesisConfig {
config: HostConfiguration {
code_retention_period,
..Default::default()
},
..Default::default()
},
..Default::default()
};
new_test_ext(genesis_config).execute_with(|| {
let id_a = ParaId::from(0u32);
let id_b = ParaId::from(1u32);
Paras::note_past_code(id_a, 10, 12, ValidationCode(vec![1, 2, 3]).hash());
Paras::note_past_code(id_b, 20, 23, ValidationCode(vec![4, 5, 6]).hash());
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
assert_eq!(<Paras as Store>::PastCodePruning::get(), vec![(id_a, 12), (id_b, 23)]);
assert_eq!(
Paras::past_code_meta(&id_a),
ParaPastCodeMeta {
upgrade_times: vec![upgrade_at(10, 12)],
last_pruned: None,
}
);
assert_eq!(
Paras::past_code_meta(&id_b),
ParaPastCodeMeta {
upgrade_times: vec![upgrade_at(20, 23)],
last_pruned: None,
}
);
});
}
#[test]
fn code_upgrade_applied_after_delay() {
let code_retention_period = 10;
let validation_upgrade_delay = 5;
let original_code = ValidationCode(vec![1, 2, 3]);
let paras = vec![
(0u32.into(), ParaGenesisArgs {
parachain: true,
genesis_head: Default::default(),
validation_code: original_code.clone(),
}),
];
let genesis_config = MockGenesisConfig {
paras: GenesisConfig { paras, ..Default::default() },
configuration: crate::configuration::GenesisConfig {
config: HostConfiguration {
code_retention_period,
validation_upgrade_delay,
..Default::default()
},
..Default::default()
},
..Default::default()
};
new_test_ext(genesis_config).execute_with(|| {
check_code_is_stored(&original_code);
let para_id = ParaId::from(0);
let new_code = ValidationCode(vec![4, 5, 6]);
run_to_block(2, None);
assert_eq!(Paras::current_code(¶_id), Some(original_code.clone()));
let expected_at = {
// this parablock is in the context of block 1.
let expected_at = 1 + validation_upgrade_delay;
Paras::schedule_code_upgrade(para_id, new_code.clone(), expected_at);
Paras::note_new_head(para_id, Default::default(), 1);
assert!(Paras::past_code_meta(¶_id).most_recent_change().is_none());
assert_eq!(<Paras as Store>::FutureCodeUpgrades::get(¶_id), Some(expected_at));
assert_eq!(<Paras as Store>::FutureCodeHash::get(¶_id), Some(new_code.hash()));
assert_eq!(Paras::current_code(¶_id), Some(original_code.clone()));
check_code_is_stored(&original_code);
check_code_is_stored(&new_code);
expected_at
};
run_to_block(expected_at, None);
// the candidate is in the context of the parent of `expected_at`,
// thus does not trigger the code upgrade.
{
Paras::note_new_head(para_id, Default::default(), expected_at - 1);
assert!(Paras::past_code_meta(¶_id).most_recent_change().is_none());
assert_eq!(<Paras as Store>::FutureCodeUpgrades::get(¶_id), Some(expected_at));
assert_eq!(<Paras as Store>::FutureCodeHash::get(¶_id), Some(new_code.hash()));
assert_eq!(Paras::current_code(¶_id), Some(original_code.clone()));
check_code_is_stored(&original_code);
check_code_is_stored(&new_code);
}
run_to_block(expected_at + 1, None);
// the candidate is in the context of `expected_at`, and triggers
// the upgrade.
{
Paras::note_new_head(para_id, Default::default(), expected_at);
assert_eq!(
Paras::past_code_meta(¶_id).most_recent_change(),
Some(expected_at),
);
assert_eq!(
<Paras as Store>::PastCodeHash::get(&(para_id, expected_at)),
Some(original_code.hash()),
);
assert!(<Paras as Store>::FutureCodeUpgrades::get(¶_id).is_none());
assert!(<Paras as Store>::FutureCodeHash::get(¶_id).is_none());
assert_eq!(Paras::current_code(¶_id), Some(new_code.clone()));
check_code_is_stored(&original_code);
check_code_is_stored(&new_code);
}
});
}
#[test]
fn code_upgrade_applied_after_delay_even_when_late() {
let code_retention_period = 10;
let validation_upgrade_delay = 5;
let original_code = ValidationCode(vec![1, 2, 3]);
let paras = vec![
(0u32.into(), ParaGenesisArgs {
parachain: true,
genesis_head: Default::default(),
validation_code: original_code.clone(),
}),
];
let genesis_config = MockGenesisConfig {
paras: GenesisConfig { paras, ..Default::default() },
configuration: crate::configuration::GenesisConfig {
config: HostConfiguration {
code_retention_period,
validation_upgrade_delay,
..Default::default()
},
..Default::default()
},
..Default::default()
};
new_test_ext(genesis_config).execute_with(|| {
let para_id = ParaId::from(0);
let new_code = ValidationCode(vec![4, 5, 6]);
run_to_block(2, None);
assert_eq!(Paras::current_code(¶_id), Some(original_code.clone()));
let expected_at = {
// this parablock is in the context of block 1.
let expected_at = 1 + validation_upgrade_delay;
Paras::schedule_code_upgrade(para_id, new_code.clone(), expected_at);
Paras::note_new_head(para_id, Default::default(), 1);
assert!(Paras::past_code_meta(¶_id).most_recent_change().is_none());
assert_eq!(<Paras as Store>::FutureCodeUpgrades::get(¶_id), Some(expected_at));
assert_eq!(<Paras as Store>::FutureCodeHash::get(¶_id), Some(new_code.hash()));
assert_eq!(Paras::current_code(¶_id), Some(original_code.clone()));
expected_at
};
run_to_block(expected_at + 1 + 4, None);
// the candidate is in the context of the first descendent of `expected_at`, and triggers
// the upgrade.
{
Paras::note_new_head(para_id, Default::default(), expected_at + 4);
assert_eq!(
Paras::past_code_meta(¶_id).most_recent_change(),
Some(expected_at),
);
assert_eq!(
<Paras as Store>::PastCodeHash::get(&(para_id, expected_at)),
Some(original_code.hash()),
);
assert!(<Paras as Store>::FutureCodeUpgrades::get(¶_id).is_none());
assert!(<Paras as Store>::FutureCodeHash::get(¶_id).is_none());
assert_eq!(Paras::current_code(¶_id), Some(new_code.clone()));
}
});
}
#[test]
fn submit_code_change_when_not_allowed_is_err() {
let code_retention_period = 10;
let paras = vec![
(0u32.into(), ParaGenesisArgs {
parachain: true,
genesis_head: Default::default(),
validation_code: vec![1, 2, 3].into(),
}),
];
let genesis_config = MockGenesisConfig {
paras: GenesisConfig { paras, ..Default::default() },
configuration: crate::configuration::GenesisConfig {
config: HostConfiguration {
code_retention_period,
..Default::default()
},
..Default::default()
},
..Default::default()
};
new_test_ext(genesis_config).execute_with(|| {
let para_id = ParaId::from(0);
let new_code = ValidationCode(vec![4, 5, 6]);
let newer_code = ValidationCode(vec![4, 5, 6, 7]);
run_to_block(1, None);
Paras::schedule_code_upgrade(para_id, new_code.clone(), 8);
assert_eq!(<Paras as Store>::FutureCodeUpgrades::get(¶_id), Some(8));
assert_eq!(<Paras as Store>::FutureCodeHash::get(¶_id), Some(new_code.hash()));
check_code_is_stored(&new_code);
Paras::schedule_code_upgrade(para_id, newer_code.clone(), 10);
assert_eq!(<Paras as Store>::FutureCodeUpgrades::get(¶_id), Some(8));
assert_eq!(<Paras as Store>::FutureCodeHash::get(¶_id), Some(new_code.hash()));
check_code_is_not_stored(&newer_code);
});
}
#[test]
fn full_parachain_cleanup_storage() {
let code_retention_period = 10;
let original_code = ValidationCode(vec![1, 2, 3]);
let paras = vec![
(0u32.into(), ParaGenesisArgs {
parachain: true,
genesis_head: Default::default(),
validation_code: original_code.clone(),
}),
];
let genesis_config = MockGenesisConfig {
paras: GenesisConfig { paras, ..Default::default() },
configuration: crate::configuration::GenesisConfig {
config: HostConfiguration {
code_retention_period,
..Default::default()
},
..Default::default()
},
..Default::default()
};
new_test_ext(genesis_config).execute_with(|| {
check_code_is_stored(&original_code);
let para_id = ParaId::from(0);
let new_code = ValidationCode(vec![4, 5, 6]);
run_to_block(2, None);
assert_eq!(Paras::current_code(¶_id), Some(original_code.clone()));
check_code_is_stored(&original_code);
let expected_at = {
// this parablock is in the context of block 1.
let expected_at = 1 + 5;
Paras::schedule_code_upgrade(para_id, new_code.clone(), expected_at);
Paras::note_new_head(para_id, Default::default(), 1);
assert!(Paras::past_code_meta(¶_id).most_recent_change().is_none());
assert_eq!(<Paras as Store>::FutureCodeUpgrades::get(¶_id), Some(expected_at));
assert_eq!(<Paras as Store>::FutureCodeHash::get(¶_id), Some(new_code.hash()));
assert_eq!(Paras::current_code(¶_id), Some(original_code.clone()));
check_code_is_stored(&original_code);
check_code_is_stored(&new_code);
expected_at
};
assert_ok!(Paras::schedule_para_cleanup(para_id));
// Just scheduling cleanup shouldn't change anything.
{
assert_eq!(
<Paras as Store>::ActionsQueue::get(Paras::scheduled_session()),
vec![para_id],
);
assert_eq!(Paras::parachains(), vec![para_id]);
assert!(Paras::past_code_meta(¶_id).most_recent_change().is_none());
assert_eq!(<Paras as Store>::FutureCodeUpgrades::get(¶_id), Some(expected_at));
assert_eq!(<Paras as Store>::FutureCodeHash::get(¶_id), Some(new_code.hash()));
assert_eq!(Paras::current_code(¶_id), Some(original_code.clone()));
check_code_is_stored(&original_code);
check_code_is_stored(&new_code);
assert_eq!(<Paras as Store>::Heads::get(¶_id), Some(Default::default()));
}
// run to block #4, with a 2 session changes at the end of the block 2 & 3.
run_to_block(4, Some(vec![3,4]));
// cleaning up the parachain should place the current parachain code
// into the past code buffer & schedule cleanup.
assert_eq!(Paras::past_code_meta(¶_id).most_recent_change(), Some(3));
assert_eq!(<Paras as Store>::PastCodeHash::get(&(para_id, 3)), Some(original_code.hash()));
assert_eq!(<Paras as Store>::PastCodePruning::get(), vec![(para_id, 3)]);
check_code_is_stored(&original_code);
// any future upgrades haven't been used to validate yet, so those
// are cleaned up immediately.
assert!(<Paras as Store>::FutureCodeUpgrades::get(¶_id).is_none());
assert!(<Paras as Store>::FutureCodeHash::get(¶_id).is_none());
assert!(Paras::current_code(¶_id).is_none());
check_code_is_not_stored(&new_code);
// run to do the final cleanup
let cleaned_up_at = 3 + code_retention_period + 1;
run_to_block(cleaned_up_at, None);
// now the final cleanup: last past code cleaned up, and this triggers meta cleanup.
assert_eq!(Paras::past_code_meta(¶_id), Default::default());
assert!(<Paras as Store>::PastCodeHash::get(&(para_id, 3)).is_none());
assert!(<Paras as Store>::PastCodePruning::get().is_empty());
check_code_is_not_stored(&original_code);
});
}
#[test]
fn para_incoming_at_session() {
new_test_ext(Default::default()).execute_with(|| {
run_to_block(1, None);
let b = ParaId::from(525);
let a = ParaId::from(999);
let c = ParaId::from(333);
assert_ok!(Paras::schedule_para_initialize(
b,
ParaGenesisArgs {
parachain: true,
genesis_head: vec![1].into(),
validation_code: vec![1].into(),
},
assert_ok!(Paras::schedule_para_initialize(
a,
ParaGenesisArgs {
parachain: false,
genesis_head: vec![2].into(),
validation_code: vec![2].into(),
},
assert_ok!(Paras::schedule_para_initialize(
c,
ParaGenesisArgs {
parachain: true,
genesis_head: vec![3].into(),
validation_code: vec![3].into(),
},
assert_eq!(
<Paras as Store>::ActionsQueue::get(Paras::scheduled_session()),
vec![c, b, a],
);
// Lifecycle is tracked correctly
assert_eq!(ParaLifecycles::get(&a), Some(ParaLifecycle::Onboarding));
assert_eq!(ParaLifecycles::get(&b), Some(ParaLifecycle::Onboarding));
assert_eq!(ParaLifecycles::get(&c), Some(ParaLifecycle::Onboarding));
// run to block without session change.
run_to_block(2, None);
assert_eq!(Paras::parachains(), Vec::new());
assert_eq!(
<Paras as Store>::ActionsQueue::get(Paras::scheduled_session()),
vec![c, b, a],
);
// Lifecycle is tracked correctly
assert_eq!(ParaLifecycles::get(&a), Some(ParaLifecycle::Onboarding));
assert_eq!(ParaLifecycles::get(&b), Some(ParaLifecycle::Onboarding));
assert_eq!(ParaLifecycles::get(&c), Some(ParaLifecycle::Onboarding));
// Two sessions pass, so action queue is triggered
run_to_block(4, Some(vec![3,4]));
assert_eq!(Paras::parachains(), vec![c, b]);
assert_eq!(<Paras as Store>::ActionsQueue::get(Paras::scheduled_session()), Vec::new());
// Lifecycle is tracked correctly
assert_eq!(ParaLifecycles::get(&a), Some(ParaLifecycle::Parathread));
assert_eq!(ParaLifecycles::get(&b), Some(ParaLifecycle::Parachain));
assert_eq!(ParaLifecycles::get(&c), Some(ParaLifecycle::Parachain));
assert_eq!(Paras::current_code(&a), Some(vec![2].into()));
assert_eq!(Paras::current_code(&b), Some(vec![1].into()));
assert_eq!(Paras::current_code(&c), Some(vec![3].into()));
})
}
#[test]
fn code_at_with_intermediate() {
let code_retention_period = 10;
let paras = vec![
(0u32.into(), ParaGenesisArgs {
parachain: true,
genesis_head: Default::default(),
validation_code: vec![1, 2, 3].into(),
}),
];
let genesis_config = MockGenesisConfig {
paras: GenesisConfig { paras, ..Default::default() },
configuration: crate::configuration::GenesisConfig {
config: HostConfiguration {
code_retention_period,
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
..Default::default()
},
..Default::default()
},
..Default::default()
};
new_test_ext(genesis_config).execute_with(|| {
let para_id = ParaId::from(0);
let old_code: ValidationCode = vec![1, 2, 3].into();
let new_code: ValidationCode = vec![4, 5, 6].into();
Paras::schedule_code_upgrade(para_id, new_code.clone(), 10);
// no intermediate, falls back on current/past.
assert_eq!(Paras::validation_code_at(para_id, 1, None), Some(old_code.clone()));
assert_eq!(Paras::validation_code_at(para_id, 10, None), Some(old_code.clone()));
assert_eq!(Paras::validation_code_at(para_id, 100, None), Some(old_code.clone()));
// intermediate before upgrade meant to be applied, falls back on current.
assert_eq!(Paras::validation_code_at(para_id, 9, Some(8)), Some(old_code.clone()));
assert_eq!(Paras::validation_code_at(para_id, 10, Some(9)), Some(old_code.clone()));
assert_eq!(Paras::validation_code_at(para_id, 11, Some(9)), Some(old_code.clone()));
// intermediate at or after upgrade applied
assert_eq!(Paras::validation_code_at(para_id, 11, Some(10)), Some(new_code.clone()));
assert_eq!(Paras::validation_code_at(para_id, 100, Some(11)), Some(new_code.clone()));
run_to_block(code_retention_period + 5, None);
// at <= intermediate not allowed
assert_eq!(Paras::validation_code_at(para_id, 10, Some(10)), None);
assert_eq!(Paras::validation_code_at(para_id, 9, Some(10)), None);
});
}
#[test]
fn code_at_returns_up_to_end_of_code_retention_period() {
let code_retention_period = 10;
let paras = vec![
(0u32.into(), ParaGenesisArgs {
parachain: true,
genesis_head: Default::default(),
validation_code: vec![1, 2, 3].into(),
}),
];
let genesis_config = MockGenesisConfig {
paras: GenesisConfig { paras, ..Default::default() },
configuration: crate::configuration::GenesisConfig {
config: HostConfiguration {
code_retention_period,
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
..Default::default()
},
..Default::default()
},
..Default::default()
};
new_test_ext(genesis_config).execute_with(|| {
let para_id = ParaId::from(0);
let old_code: ValidationCode = vec![1, 2, 3].into();
let new_code: ValidationCode = vec![4, 5, 6].into();
Paras::schedule_code_upgrade(para_id, new_code.clone(), 2);
run_to_block(10, None);
Paras::note_new_head(para_id, Default::default(), 7);
assert_eq!(
Paras::past_code_meta(¶_id).upgrade_times,
vec![upgrade_at(2, 10)],
);
assert_eq!(Paras::validation_code_at(para_id, 2, None), Some(old_code.clone()));
assert_eq!(Paras::validation_code_at(para_id, 3, None), Some(new_code.clone()));
run_to_block(10 + code_retention_period, None);
assert_eq!(Paras::validation_code_at(para_id, 2, None), Some(old_code.clone()));
assert_eq!(Paras::validation_code_at(para_id, 3, None), Some(new_code.clone()));
run_to_block(10 + code_retention_period + 1, None);
// code entry should be pruned now.
assert_eq!(
Paras::past_code_meta(¶_id),
ParaPastCodeMeta {
upgrade_times: Vec::new(),
last_pruned: Some(2),
},
);
assert_eq!(Paras::validation_code_at(para_id, 2, None), None); // pruned :(
assert_eq!(Paras::validation_code_at(para_id, 3, None), Some(new_code.clone()));
});
}
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
#[test]
fn code_ref_is_cleaned_correctly() {
new_test_ext(Default::default()).execute_with(|| {
let code: ValidationCode = vec![1, 2, 3].into();
Paras::increase_code_ref(&code.hash(), &code);
Paras::increase_code_ref(&code.hash(), &code);
assert!(CodeByHash::contains_key(code.hash()));
assert_eq!(CodeByHashRefs::get(code.hash()), 2);
Paras::decrease_code_ref(&code.hash());
assert!(CodeByHash::contains_key(code.hash()));
assert_eq!(CodeByHashRefs::get(code.hash()), 1);
Paras::decrease_code_ref(&code.hash());
assert!(!CodeByHash::contains_key(code.hash()));
assert!(!CodeByHashRefs::contains_key(code.hash()));
});
}