Newer
Older
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
let (changes2_1_0_root, _) = prepare_changes(changes2_1_0);
let anchor = state_machine::ChangesTrieAnchorBlockId { hash: block2_1_1, number: 4 };
assert_eq!(backend.changes_tries_storage.root(&anchor, 3), Ok(Some(changes2_1_0_root)));
// branch2: when asking for non-finalized block hash (search using canonicalized hint)
let (changes2_2_0_root, _) = prepare_changes(changes2_2_0);
let anchor = state_machine::ChangesTrieAnchorBlockId { hash: block2_2_1, number: 4 };
assert_eq!(backend.changes_tries_storage.root(&anchor, 3), Ok(Some(changes2_2_0_root)));
// finalize first block of branch2 (block2_2_0)
backend.changes_tries_storage.meta.write().finalized_number = 3;
// branch2: when asking for finalized block of this branch
assert_eq!(backend.changes_tries_storage.root(&anchor, 3), Ok(Some(changes2_2_0_root)));
// branch1: when asking for finalized block of other branch
// => result is incorrect (returned for the block of branch1), but this is expected,
// because the other fork is abandoned (forked before finalized header)
let anchor = state_machine::ChangesTrieAnchorBlockId { hash: block2_1_1, number: 4 };
assert_eq!(backend.changes_tries_storage.root(&anchor, 3), Ok(Some(changes2_2_0_root)));
}
fn changes_tries_with_digest_are_pruned_on_finalization() {
let mut backend = Backend::<Block>::new_test(1000, 100);
backend.changes_tries_storage.min_blocks_to_keep = Some(8);
let config = ChangesTrieConfiguration {
digest_interval: 2,
digest_levels: 2,
};
// insert some blocks
let block0 = insert_header(&backend, 0, Default::default(), vec![(b"key_at_0".to_vec(), b"val_at_0".to_vec())], Default::default());
let block1 = insert_header(&backend, 1, block0, vec![(b"key_at_1".to_vec(), b"val_at_1".to_vec())], Default::default());
let block2 = insert_header(&backend, 2, block1, vec![(b"key_at_2".to_vec(), b"val_at_2".to_vec())], Default::default());
let block3 = insert_header(&backend, 3, block2, vec![(b"key_at_3".to_vec(), b"val_at_3".to_vec())], Default::default());
let block4 = insert_header(&backend, 4, block3, vec![(b"key_at_4".to_vec(), b"val_at_4".to_vec())], Default::default());
let block5 = insert_header(&backend, 5, block4, vec![(b"key_at_5".to_vec(), b"val_at_5".to_vec())], Default::default());
let block6 = insert_header(&backend, 6, block5, vec![(b"key_at_6".to_vec(), b"val_at_6".to_vec())], Default::default());
let block7 = insert_header(&backend, 7, block6, vec![(b"key_at_7".to_vec(), b"val_at_7".to_vec())], Default::default());
let block8 = insert_header(&backend, 8, block7, vec![(b"key_at_8".to_vec(), b"val_at_8".to_vec())], Default::default());
let block9 = insert_header(&backend, 9, block8, vec![(b"key_at_9".to_vec(), b"val_at_9".to_vec())], Default::default());
let block10 = insert_header(&backend, 10, block9, vec![(b"key_at_10".to_vec(), b"val_at_10".to_vec())], Default::default());
let block11 = insert_header(&backend, 11, block10, vec![(b"key_at_11".to_vec(), b"val_at_11".to_vec())], Default::default());
let block12 = insert_header(&backend, 12, block11, vec![(b"key_at_12".to_vec(), b"val_at_12".to_vec())], Default::default());
let block13 = insert_header(&backend, 13, block12, vec![(b"key_at_13".to_vec(), b"val_at_13".to_vec())], Default::default());
backend.changes_tries_storage.meta.write().finalized_number = 13;
// check that roots of all tries are in the columns::CHANGES_TRIE
let anchor = state_machine::ChangesTrieAnchorBlockId { hash: block13, number: 13 };
fn read_changes_trie_root(backend: &Backend<Block>, num: u64) -> H256 {
backend.blockchain().header(BlockId::Number(num)).unwrap().unwrap().digest().logs().iter()
.find(|i| i.as_changes_trie_root().is_some()).unwrap().as_changes_trie_root().unwrap().clone()
}
let root1 = read_changes_trie_root(&backend, 1); assert_eq!(backend.changes_tries_storage.root(&anchor, 1).unwrap(), Some(root1));
let root2 = read_changes_trie_root(&backend, 2); assert_eq!(backend.changes_tries_storage.root(&anchor, 2).unwrap(), Some(root2));
let root3 = read_changes_trie_root(&backend, 3); assert_eq!(backend.changes_tries_storage.root(&anchor, 3).unwrap(), Some(root3));
let root4 = read_changes_trie_root(&backend, 4); assert_eq!(backend.changes_tries_storage.root(&anchor, 4).unwrap(), Some(root4));
let root5 = read_changes_trie_root(&backend, 5); assert_eq!(backend.changes_tries_storage.root(&anchor, 5).unwrap(), Some(root5));
let root6 = read_changes_trie_root(&backend, 6); assert_eq!(backend.changes_tries_storage.root(&anchor, 6).unwrap(), Some(root6));
let root7 = read_changes_trie_root(&backend, 7); assert_eq!(backend.changes_tries_storage.root(&anchor, 7).unwrap(), Some(root7));
let root8 = read_changes_trie_root(&backend, 8); assert_eq!(backend.changes_tries_storage.root(&anchor, 8).unwrap(), Some(root8));
let root9 = read_changes_trie_root(&backend, 9); assert_eq!(backend.changes_tries_storage.root(&anchor, 9).unwrap(), Some(root9));
let root10 = read_changes_trie_root(&backend, 10); assert_eq!(backend.changes_tries_storage.root(&anchor, 10).unwrap(), Some(root10));
let root11 = read_changes_trie_root(&backend, 11); assert_eq!(backend.changes_tries_storage.root(&anchor, 11).unwrap(), Some(root11));
let root12 = read_changes_trie_root(&backend, 12); assert_eq!(backend.changes_tries_storage.root(&anchor, 12).unwrap(), Some(root12));
// now simulate finalization of block#12, causing prune of tries at #1..#4
let mut tx = DBTransaction::new();
backend.changes_tries_storage.prune(&config, &mut tx, Default::default(), 12);
backend.storage.db.write(tx).unwrap();
assert!(backend.changes_tries_storage.get(&root1, EMPTY_PREFIX).unwrap().is_none());
assert!(backend.changes_tries_storage.get(&root2, EMPTY_PREFIX).unwrap().is_none());
assert!(backend.changes_tries_storage.get(&root3, EMPTY_PREFIX).unwrap().is_none());
assert!(backend.changes_tries_storage.get(&root4, EMPTY_PREFIX).unwrap().is_none());
assert!(backend.changes_tries_storage.get(&root5, EMPTY_PREFIX).unwrap().is_some());
assert!(backend.changes_tries_storage.get(&root6, EMPTY_PREFIX).unwrap().is_some());
assert!(backend.changes_tries_storage.get(&root7, EMPTY_PREFIX).unwrap().is_some());
assert!(backend.changes_tries_storage.get(&root8, EMPTY_PREFIX).unwrap().is_some());
// now simulate finalization of block#16, causing prune of tries at #5..#8
let mut tx = DBTransaction::new();
backend.changes_tries_storage.prune(&config, &mut tx, Default::default(), 16);
backend.storage.db.write(tx).unwrap();
assert!(backend.changes_tries_storage.get(&root5, EMPTY_PREFIX).unwrap().is_none());
assert!(backend.changes_tries_storage.get(&root6, EMPTY_PREFIX).unwrap().is_none());
assert!(backend.changes_tries_storage.get(&root7, EMPTY_PREFIX).unwrap().is_none());
assert!(backend.changes_tries_storage.get(&root8, EMPTY_PREFIX).unwrap().is_none());
// now "change" pruning mode to archive && simulate finalization of block#20
// => no changes tries are pruned, because we never prune in archive mode
backend.changes_tries_storage.min_blocks_to_keep = None;
let mut tx = DBTransaction::new();
backend.changes_tries_storage.prune(&config, &mut tx, Default::default(), 20);
backend.storage.db.write(tx).unwrap();
assert!(backend.changes_tries_storage.get(&root9, EMPTY_PREFIX).unwrap().is_some());
assert!(backend.changes_tries_storage.get(&root10, EMPTY_PREFIX).unwrap().is_some());
assert!(backend.changes_tries_storage.get(&root11, EMPTY_PREFIX).unwrap().is_some());
assert!(backend.changes_tries_storage.get(&root12, EMPTY_PREFIX).unwrap().is_some());
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
#[test]
fn changes_tries_without_digest_are_pruned_on_finalization() {
let mut backend = Backend::<Block>::new_test(1000, 100);
backend.changes_tries_storage.min_blocks_to_keep = Some(4);
let config = ChangesTrieConfiguration {
digest_interval: 0,
digest_levels: 0,
};
// insert some blocks
let block0 = insert_header(&backend, 0, Default::default(), vec![(b"key_at_0".to_vec(), b"val_at_0".to_vec())], Default::default());
let block1 = insert_header(&backend, 1, block0, vec![(b"key_at_1".to_vec(), b"val_at_1".to_vec())], Default::default());
let block2 = insert_header(&backend, 2, block1, vec![(b"key_at_2".to_vec(), b"val_at_2".to_vec())], Default::default());
let block3 = insert_header(&backend, 3, block2, vec![(b"key_at_3".to_vec(), b"val_at_3".to_vec())], Default::default());
let block4 = insert_header(&backend, 4, block3, vec![(b"key_at_4".to_vec(), b"val_at_4".to_vec())], Default::default());
let block5 = insert_header(&backend, 5, block4, vec![(b"key_at_5".to_vec(), b"val_at_5".to_vec())], Default::default());
let block6 = insert_header(&backend, 6, block5, vec![(b"key_at_6".to_vec(), b"val_at_6".to_vec())], Default::default());
// check that roots of all tries are in the columns::CHANGES_TRIE
let anchor = state_machine::ChangesTrieAnchorBlockId { hash: block6, number: 6 };
fn read_changes_trie_root(backend: &Backend<Block>, num: u64) -> H256 {
backend.blockchain().header(BlockId::Number(num)).unwrap().unwrap().digest().logs().iter()
.find(|i| i.as_changes_trie_root().is_some()).unwrap().as_changes_trie_root().unwrap().clone()
}
let root1 = read_changes_trie_root(&backend, 1); assert_eq!(backend.changes_tries_storage.root(&anchor, 1).unwrap(), Some(root1));
let root2 = read_changes_trie_root(&backend, 2); assert_eq!(backend.changes_tries_storage.root(&anchor, 2).unwrap(), Some(root2));
let root3 = read_changes_trie_root(&backend, 3); assert_eq!(backend.changes_tries_storage.root(&anchor, 3).unwrap(), Some(root3));
let root4 = read_changes_trie_root(&backend, 4); assert_eq!(backend.changes_tries_storage.root(&anchor, 4).unwrap(), Some(root4));
let root5 = read_changes_trie_root(&backend, 5); assert_eq!(backend.changes_tries_storage.root(&anchor, 5).unwrap(), Some(root5));
let root6 = read_changes_trie_root(&backend, 6); assert_eq!(backend.changes_tries_storage.root(&anchor, 6).unwrap(), Some(root6));
// now simulate finalization of block#5, causing prune of trie at #1
let mut tx = DBTransaction::new();
backend.changes_tries_storage.prune(&config, &mut tx, block5, 5);
backend.storage.db.write(tx).unwrap();
assert!(backend.changes_tries_storage.get(&root1, EMPTY_PREFIX).unwrap().is_none());
assert!(backend.changes_tries_storage.get(&root2, EMPTY_PREFIX).unwrap().is_some());
// now simulate finalization of block#6, causing prune of tries at #2
let mut tx = DBTransaction::new();
backend.changes_tries_storage.prune(&config, &mut tx, block6, 6);
backend.storage.db.write(tx).unwrap();
assert!(backend.changes_tries_storage.get(&root2, EMPTY_PREFIX).unwrap().is_none());
assert!(backend.changes_tries_storage.get(&root3, EMPTY_PREFIX).unwrap().is_some());
#[test]
fn tree_route_works() {
let backend = Backend::<Block>::new_test(1000, 100);
let blockchain = backend.blockchain();
let block0 = insert_header(&backend, 0, Default::default(), Vec::new(), Default::default());
// fork from genesis: 3 prong.
let a1 = insert_header(&backend, 1, block0, Vec::new(), Default::default());
let a2 = insert_header(&backend, 2, a1, Vec::new(), Default::default());
let a3 = insert_header(&backend, 3, a2, Vec::new(), Default::default());
// fork from genesis: 2 prong.
let b1 = insert_header(&backend, 1, block0, Vec::new(), H256::from([1; 32]));
let b2 = insert_header(&backend, 2, b1, Vec::new(), Default::default());
{
let tree_route = tree_route(blockchain, a3, b2).unwrap();
assert_eq!(tree_route.common_block().hash, block0);
assert_eq!(tree_route.retracted().iter().map(|r| r.hash).collect::<Vec<_>>(), vec![a3, a2, a1]);
assert_eq!(tree_route.enacted().iter().map(|r| r.hash).collect::<Vec<_>>(), vec![b1, b2]);
}
{
let tree_route = tree_route(blockchain, a1, a3).unwrap();
assert_eq!(tree_route.common_block().hash, a1);
assert!(tree_route.retracted().is_empty());
assert_eq!(tree_route.enacted().iter().map(|r| r.hash).collect::<Vec<_>>(), vec![a2, a3]);
}
{
let tree_route = tree_route(blockchain, a3, a1).unwrap();
assert_eq!(tree_route.common_block().hash, a1);
assert_eq!(tree_route.retracted().iter().map(|r| r.hash).collect::<Vec<_>>(), vec![a3, a2]);
assert!(tree_route.enacted().is_empty());
}
{
let tree_route = tree_route(blockchain, a2, a2).unwrap();
assert_eq!(tree_route.common_block().hash, a2);
assert!(tree_route.retracted().is_empty());
assert!(tree_route.enacted().is_empty());
}
}
#[test]
fn tree_route_child() {
let backend = Backend::<Block>::new_test(1000, 100);
let blockchain = backend.blockchain();
let block0 = insert_header(&backend, 0, Default::default(), Vec::new(), Default::default());
let block1 = insert_header(&backend, 1, block0, Vec::new(), Default::default());
{
let tree_route = tree_route(blockchain, block0, block1).unwrap();
assert_eq!(tree_route.common_block().hash, block0);
assert!(tree_route.retracted().is_empty());
assert_eq!(tree_route.enacted().iter().map(|r| r.hash).collect::<Vec<_>>(), vec![block1]);
}
}
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
#[test]
fn lowest_common_ancestor_works() {
let backend = Backend::<Block>::new_test(1000, 100);
let blockchain = backend.blockchain();
let block0 = insert_header(&backend, 0, Default::default(), Vec::new(), Default::default());
// fork from genesis: 3 prong.
let a1 = insert_header(&backend, 1, block0, Vec::new(), Default::default());
let a2 = insert_header(&backend, 2, a1, Vec::new(), Default::default());
let a3 = insert_header(&backend, 3, a2, Vec::new(), Default::default());
// fork from genesis: 2 prong.
let b1 = insert_header(&backend, 1, block0, Vec::new(), H256::from([1; 32]));
let b2 = insert_header(&backend, 2, b1, Vec::new(), Default::default());
{
let lca = lowest_common_ancestor(blockchain, a3, b2).unwrap();
assert_eq!(lca.hash, block0);
assert_eq!(lca.number, 0);
}
{
let lca = lowest_common_ancestor(blockchain, a1, a3).unwrap();
assert_eq!(lca.hash, a1);
assert_eq!(lca.number, 1);
}
{
let lca = lowest_common_ancestor(blockchain, a3, a1).unwrap();
assert_eq!(lca.hash, a1);
assert_eq!(lca.number, 1);
}
{
let lca = lowest_common_ancestor(blockchain, a2, a3).unwrap();
assert_eq!(lca.hash, a2);
assert_eq!(lca.number, 2);
}
{
let lca = lowest_common_ancestor(blockchain, a2, a1).unwrap();
assert_eq!(lca.hash, a1);
assert_eq!(lca.number, 1);
}
{
let lca = lowest_common_ancestor(blockchain, a2, a2).unwrap();
assert_eq!(lca.hash, a2);
assert_eq!(lca.number, 2);
}
}
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
#[test]
fn test_tree_route_regression() {
// NOTE: this is a test for a regression introduced in #3665, the result
// of tree_route would be erroneously computed, since it was taking into
// account the `ancestor` in `CachedHeaderMetadata` for the comparison.
// in this test we simulate the same behavior with the side-effect
// triggering the issue being eviction of a previously fetched record
// from the cache, therefore this test is dependent on the LRU cache
// size for header metadata, which is currently set to 5000 elements.
let backend = Backend::<Block>::new_test(10000, 10000);
let blockchain = backend.blockchain();
let genesis = insert_header(&backend, 0, Default::default(), Vec::new(), Default::default());
let block100 = (1..=100).fold(genesis, |parent, n| {
insert_header(&backend, n, parent, Vec::new(), Default::default())
});
let block7000 = (101..=7000).fold(block100, |parent, n| {
insert_header(&backend, n, parent, Vec::new(), Default::default())
});
// This will cause the ancestor of `block100` to be set to `genesis` as a side-effect.
lowest_common_ancestor(blockchain, genesis, block100).unwrap();
// While traversing the tree we will have to do 6900 calls to
// `header_metadata`, which will make sure we will exhaust our cache
// which only takes 5000 elements. In particular, the `CachedHeaderMetadata` struct for
// block #100 will be evicted and will get a new value (with ancestor set to its parent).
let tree_route = tree_route(blockchain, block100, block7000).unwrap();
assert!(tree_route.retracted().is_empty());
}
#[test]
fn test_leaves_with_complex_block_tree() {
let backend: Arc<Backend<test_client::runtime::Block>> = Arc::new(Backend::new_test(20, 20));
test_client::trait_tests::test_leaves_for_backend(backend);
}
#[test]
fn test_children_with_complex_block_tree() {
let backend: Arc<Backend<test_client::runtime::Block>> = Arc::new(Backend::new_test(20, 20));
test_client::trait_tests::test_children_for_backend(backend);
}
#[test]
fn test_blockchain_query_by_number_gets_canonical() {
let backend: Arc<Backend<test_client::runtime::Block>> = Arc::new(Backend::new_test(20, 20));
test_client::trait_tests::test_blockchain_query_by_number_gets_canonical(backend);
}
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
#[test]
fn test_leaves_pruned_on_finality() {
let backend: Backend<Block> = Backend::new_test(10, 10);
let block0 = insert_header(&backend, 0, Default::default(), Default::default(), Default::default());
let block1_a = insert_header(&backend, 1, block0, Default::default(), Default::default());
let block1_b = insert_header(&backend, 1, block0, Default::default(), [1; 32].into());
let block1_c = insert_header(&backend, 1, block0, Default::default(), [2; 32].into());
assert_eq!(backend.blockchain().leaves().unwrap(), vec![block1_a, block1_b, block1_c]);
let block2_a = insert_header(&backend, 2, block1_a, Default::default(), Default::default());
let block2_b = insert_header(&backend, 2, block1_b, Default::default(), Default::default());
let block2_c = insert_header(&backend, 2, block1_b, Default::default(), [1; 32].into());
assert_eq!(backend.blockchain().leaves().unwrap(), vec![block2_a, block2_b, block2_c, block1_c]);
backend.finalize_block(BlockId::hash(block1_a), None).unwrap();
backend.finalize_block(BlockId::hash(block2_a), None).unwrap();
// leaves at same height stay. Leaves at lower heights pruned.
assert_eq!(backend.blockchain().leaves().unwrap(), vec![block2_a, block2_b, block2_c]);
}
#[test]
fn test_aux() {
let backend: Backend<test_client::runtime::Block> = Backend::new_test(0, 0);
assert!(backend.get_aux(b"test").unwrap().is_none());
backend.insert_aux(&[(&b"test"[..], &b"hello"[..])], &[]).unwrap();
assert_eq!(b"hello", &backend.get_aux(b"test").unwrap().unwrap()[..]);
backend.insert_aux(&[], &[&b"test"[..]]).unwrap();
assert!(backend.get_aux(b"test").unwrap().is_none());
}
#[test]
fn test_finalize_block_with_justification() {
use client::blockchain::{Backend as BlockChainBackend};
let backend = Backend::<Block>::new_test(10, 10);
let block0 = insert_header(&backend, 0, Default::default(), Default::default(), Default::default());
let _ = insert_header(&backend, 1, block0, Default::default(), Default::default());
let justification = Some(vec![1, 2, 3]);
backend.finalize_block(BlockId::Number(1), justification.clone()).unwrap();
backend.blockchain().justification(BlockId::Number(1)).unwrap(),
justification,
);
}
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
#[test]
fn test_finalize_multiple_blocks_in_single_op() {
let backend = Backend::<Block>::new_test(10, 10);
let block0 = insert_header(&backend, 0, Default::default(), Default::default(), Default::default());
let block1 = insert_header(&backend, 1, block0, Default::default(), Default::default());
let block2 = insert_header(&backend, 2, block1, Default::default(), Default::default());
{
let mut op = backend.begin_operation().unwrap();
backend.begin_state_operation(&mut op, BlockId::Hash(block0)).unwrap();
op.mark_finalized(BlockId::Hash(block1), None).unwrap();
op.mark_finalized(BlockId::Hash(block2), None).unwrap();
backend.commit_operation(op).unwrap();
}
}
#[test]
fn test_finalize_non_sequential() {
let backend = Backend::<Block>::new_test(10, 10);
let block0 = insert_header(&backend, 0, Default::default(), Default::default(), Default::default());
let block1 = insert_header(&backend, 1, block0, Default::default(), Default::default());
let block2 = insert_header(&backend, 2, block1, Default::default(), Default::default());
{
let mut op = backend.begin_operation().unwrap();
backend.begin_state_operation(&mut op, BlockId::Hash(block0)).unwrap();
op.mark_finalized(BlockId::Hash(block2), None).unwrap();
backend.commit_operation(op).unwrap_err();
}
}