Skip to content
client.rs 91.6 KiB
Newer Older
		assert_eq!(
			client.runtime_api().balance_of(
				&BlockId::Number(client.info().chain.best_number),
				AccountKeyring::Alice.into()
			).unwrap(),
			958
		);
		assert_eq!(
			client.runtime_api().balance_of(
				&BlockId::Number(client.info().chain.best_number),
				AccountKeyring::Ferdie.into()

	#[test]
	fn block_builder_does_not_include_invalid() {
		let client = test_client::new();

		let mut builder = client.new_block(Default::default()).unwrap();
		builder.push_transfer(Transfer {
			from: AccountKeyring::Alice.into(),
			to: AccountKeyring::Ferdie.into(),
			amount: 42,
			nonce: 0,
		assert!(builder.push_transfer(Transfer {
			from: AccountKeyring::Eve.into(),
			to: AccountKeyring::Alice.into(),
			amount: 42,
			nonce: 0,
		client.import(BlockOrigin::Own, builder.bake().unwrap()).unwrap();
		assert_eq!(client.info().chain.best_number, 1);
		assert_ne!(
			client.state_at(&BlockId::Number(1)).unwrap().pairs(),
			client.state_at(&BlockId::Number(0)).unwrap().pairs()
		);
		assert_eq!(client.body(&BlockId::Number(1)).unwrap().unwrap().len(), 1)
	}

	#[test]
	fn best_containing_with_genesis_block() {
		// block tree:
		// G

		let (client, longest_chain_select) = TestClientBuilder::new().build_with_longest_chain();
		let genesis_hash = client.info().chain.genesis_hash;
		assert_eq!(
			genesis_hash.clone(),
			longest_chain_select.finality_target(genesis_hash.clone(), None).unwrap().unwrap()
		);
	}

	#[test]
	fn best_containing_with_hash_not_found() {
		// block tree:
		// G

		let (client, longest_chain_select) = TestClientBuilder::new().build_with_longest_chain();
		let uninserted_block = client.new_block(Default::default()).unwrap().bake().unwrap();
		assert_eq!(
			None,
			longest_chain_select.finality_target(uninserted_block.hash().clone(), None).unwrap()
		);
	#[test]
	fn uncles_with_only_ancestors() {
		// block tree:
		// G -> A1 -> A2
		let client = test_client::new();

		// G -> A1
		let a1 = client.new_block(Default::default()).unwrap().bake().unwrap();
		client.import(BlockOrigin::Own, a1.clone()).unwrap();

		// A1 -> A2
		let a2 = client.new_block(Default::default()).unwrap().bake().unwrap();
		client.import(BlockOrigin::Own, a2.clone()).unwrap();
		let v: Vec<H256> = Vec::new();
		assert_eq!(v, client.uncles(a2.hash(), 3).unwrap());
	}

	#[test]
	fn uncles_with_multiple_forks() {
		// block tree:
		// G -> A1 -> A2 -> A3 -> A4 -> A5
		//      A1 -> B2 -> B3 -> B4
		//	          B2 -> C3
		//	    A1 -> D2
		let client = test_client::new();

		// G -> A1
		let a1 = client.new_block(Default::default()).unwrap().bake().unwrap();
		client.import(BlockOrigin::Own, a1.clone()).unwrap();

		// A1 -> A2
		let a2 = client.new_block_at(&BlockId::Hash(a1.hash()), Default::default()).unwrap().bake().unwrap();
		client.import(BlockOrigin::Own, a2.clone()).unwrap();

		// A2 -> A3
		let a3 = client.new_block_at(&BlockId::Hash(a2.hash()), Default::default()).unwrap().bake().unwrap();
		client.import(BlockOrigin::Own, a3.clone()).unwrap();

		// A3 -> A4
		let a4 = client.new_block_at(&BlockId::Hash(a3.hash()), Default::default()).unwrap().bake().unwrap();
		client.import(BlockOrigin::Own, a4.clone()).unwrap();

		// A4 -> A5
		let a5 = client.new_block_at(&BlockId::Hash(a4.hash()), Default::default()).unwrap().bake().unwrap();
		client.import(BlockOrigin::Own, a5.clone()).unwrap();

		// A1 -> B2
		let mut builder = client.new_block_at(&BlockId::Hash(a1.hash()), Default::default()).unwrap();
		// this push is required as otherwise B2 has the same hash as A2 and won't get imported
		builder.push_transfer(Transfer {
			from: AccountKeyring::Alice.into(),
			to: AccountKeyring::Ferdie.into(),
			amount: 41,
			nonce: 0,
		}).unwrap();
		let b2 = builder.bake().unwrap();
		client.import(BlockOrigin::Own, b2.clone()).unwrap();

		// B2 -> B3
		let b3 = client.new_block_at(&BlockId::Hash(b2.hash()), Default::default()).unwrap().bake().unwrap();
		client.import(BlockOrigin::Own, b3.clone()).unwrap();

		// B3 -> B4
		let b4 = client.new_block_at(&BlockId::Hash(b3.hash()), Default::default()).unwrap().bake().unwrap();
		client.import(BlockOrigin::Own, b4.clone()).unwrap();

		// // B2 -> C3
		let mut builder = client.new_block_at(&BlockId::Hash(b2.hash()), Default::default()).unwrap();
		// this push is required as otherwise C3 has the same hash as B3 and won't get imported
		builder.push_transfer(Transfer {
			from: AccountKeyring::Alice.into(),
			to: AccountKeyring::Ferdie.into(),
			amount: 1,
			nonce: 1,
		}).unwrap();
		let c3 = builder.bake().unwrap();
		client.import(BlockOrigin::Own, c3.clone()).unwrap();

		// A1 -> D2
		let mut builder = client.new_block_at(&BlockId::Hash(a1.hash()), Default::default()).unwrap();
		// this push is required as otherwise D2 has the same hash as B2 and won't get imported
		builder.push_transfer(Transfer {
			from: AccountKeyring::Alice.into(),
			to: AccountKeyring::Ferdie.into(),
			amount: 1,
			nonce: 0,
		}).unwrap();
		let d2 = builder.bake().unwrap();
		client.import(BlockOrigin::Own, d2.clone()).unwrap();

		let genesis_hash = client.info().chain.genesis_hash;

		let uncles1 = client.uncles(a4.hash(), 10).unwrap();
		assert_eq!(vec![b2.hash(), d2.hash()], uncles1);

		let uncles2 = client.uncles(a4.hash(), 0).unwrap();
		assert_eq!(0, uncles2.len());

		let uncles3 = client.uncles(a1.hash(), 10).unwrap();
		assert_eq!(0, uncles3.len());

		let uncles4 = client.uncles(genesis_hash, 10).unwrap();
		assert_eq!(0, uncles4.len());

		let uncles5 = client.uncles(d2.hash(), 10).unwrap();
		assert_eq!(vec![a2.hash(), b2.hash()], uncles5);

		let uncles6 = client.uncles(b3.hash(), 1).unwrap();
		assert_eq!(vec![c3.hash()], uncles6);
	}

	fn best_containing_on_longest_chain_with_single_chain_3_blocks() {
		// block tree:
		// G -> A1 -> A2

		let (client, longest_chain_select) = TestClientBuilder::new().build_with_longest_chain();
		let a1 = client.new_block(Default::default()).unwrap().bake().unwrap();
		client.import(BlockOrigin::Own, a1.clone()).unwrap();
		let a2 = client.new_block(Default::default()).unwrap().bake().unwrap();
		client.import(BlockOrigin::Own, a2.clone()).unwrap();
		let genesis_hash = client.info().chain.genesis_hash;
		assert_eq!(a2.hash(), longest_chain_select.finality_target(genesis_hash, None).unwrap().unwrap());
		assert_eq!(a2.hash(), longest_chain_select.finality_target(a1.hash(), None).unwrap().unwrap());
		assert_eq!(a2.hash(), longest_chain_select.finality_target(a2.hash(), None).unwrap().unwrap());
	fn best_containing_on_longest_chain_with_multiple_forks() {
		// block tree:
		// G -> A1 -> A2 -> A3 -> A4 -> A5
		//      A1 -> B2 -> B3 -> B4
		//	          B2 -> C3
		//	    A1 -> D2
		let (client, longest_chain_select) = TestClientBuilder::new().build_with_longest_chain();
		let a1 = client.new_block(Default::default()).unwrap().bake().unwrap();
		client.import(BlockOrigin::Own, a1.clone()).unwrap();
		let a2 = client.new_block_at(&BlockId::Hash(a1.hash()), Default::default()).unwrap().bake().unwrap();
		client.import(BlockOrigin::Own, a2.clone()).unwrap();
		let a3 = client.new_block_at(&BlockId::Hash(a2.hash()), Default::default()).unwrap().bake().unwrap();
		client.import(BlockOrigin::Own, a3.clone()).unwrap();
		let a4 = client.new_block_at(&BlockId::Hash(a3.hash()), Default::default()).unwrap().bake().unwrap();
		client.import(BlockOrigin::Own, a4.clone()).unwrap();
		let a5 = client.new_block_at(&BlockId::Hash(a4.hash()), Default::default()).unwrap().bake().unwrap();
		client.import(BlockOrigin::Own, a5.clone()).unwrap();
		let mut builder = client.new_block_at(&BlockId::Hash(a1.hash()), Default::default()).unwrap();
		// this push is required as otherwise B2 has the same hash as A2 and won't get imported
		builder.push_transfer(Transfer {
			from: AccountKeyring::Alice.into(),
			to: AccountKeyring::Ferdie.into(),
			amount: 41,
			nonce: 0,
		}).unwrap();
		let b2 = builder.bake().unwrap();
		client.import(BlockOrigin::Own, b2.clone()).unwrap();
		let b3 = client.new_block_at(&BlockId::Hash(b2.hash()), Default::default()).unwrap().bake().unwrap();
		client.import(BlockOrigin::Own, b3.clone()).unwrap();
		let b4 = client.new_block_at(&BlockId::Hash(b3.hash()), Default::default()).unwrap().bake().unwrap();
		client.import(BlockOrigin::Own, b4.clone()).unwrap();
		let mut builder = client.new_block_at(&BlockId::Hash(b2.hash()), Default::default()).unwrap();
		// this push is required as otherwise C3 has the same hash as B3 and won't get imported
		builder.push_transfer(Transfer {
			from: AccountKeyring::Alice.into(),
			to: AccountKeyring::Ferdie.into(),
			amount: 1,
			nonce: 1,
		}).unwrap();
		let c3 = builder.bake().unwrap();
		client.import(BlockOrigin::Own, c3.clone()).unwrap();
		let mut builder = client.new_block_at(&BlockId::Hash(a1.hash()), Default::default()).unwrap();
		// this push is required as otherwise D2 has the same hash as B2 and won't get imported
		builder.push_transfer(Transfer {
			from: AccountKeyring::Alice.into(),
			to: AccountKeyring::Ferdie.into(),
			amount: 1,
			nonce: 0,
		}).unwrap();
		let d2 = builder.bake().unwrap();
		client.import(BlockOrigin::Own, d2.clone()).unwrap();
		assert_eq!(client.info().chain.best_hash, a5.hash());
		let genesis_hash = client.info().chain.genesis_hash;
		let leaves = longest_chain_select.leaves().unwrap();

		assert!(leaves.contains(&a5.hash()));
		assert!(leaves.contains(&b4.hash()));
		assert!(leaves.contains(&c3.hash()));
		assert!(leaves.contains(&d2.hash()));
		assert_eq!(leaves.len(), 4);

		// search without restriction

		assert_eq!(a5.hash(), longest_chain_select.finality_target(
			genesis_hash, None).unwrap().unwrap());
		assert_eq!(a5.hash(), longest_chain_select.finality_target(
			a1.hash(), None).unwrap().unwrap());
		assert_eq!(a5.hash(), longest_chain_select.finality_target(
			a2.hash(), None).unwrap().unwrap());
		assert_eq!(a5.hash(), longest_chain_select.finality_target(
			a3.hash(), None).unwrap().unwrap());
		assert_eq!(a5.hash(), longest_chain_select.finality_target(
			a4.hash(), None).unwrap().unwrap());
		assert_eq!(a5.hash(), longest_chain_select.finality_target(
			a5.hash(), None).unwrap().unwrap());

		assert_eq!(b4.hash(), longest_chain_select.finality_target(
			b2.hash(), None).unwrap().unwrap());
		assert_eq!(b4.hash(), longest_chain_select.finality_target(
			b3.hash(), None).unwrap().unwrap());
		assert_eq!(b4.hash(), longest_chain_select.finality_target(
			b4.hash(), None).unwrap().unwrap());

		assert_eq!(c3.hash(), longest_chain_select.finality_target(
			c3.hash(), None).unwrap().unwrap());

		assert_eq!(d2.hash(), longest_chain_select.finality_target(
			d2.hash(), None).unwrap().unwrap());


		// search only blocks with number <= 5. equivalent to without restriction for this scenario

		assert_eq!(a5.hash(), longest_chain_select.finality_target(
			genesis_hash, Some(5)).unwrap().unwrap());
		assert_eq!(a5.hash(), longest_chain_select.finality_target(
			a1.hash(), Some(5)).unwrap().unwrap());
		assert_eq!(a5.hash(), longest_chain_select.finality_target(
			a2.hash(), Some(5)).unwrap().unwrap());
		assert_eq!(a5.hash(), longest_chain_select.finality_target(
			a3.hash(), Some(5)).unwrap().unwrap());
		assert_eq!(a5.hash(), longest_chain_select.finality_target(
			a4.hash(), Some(5)).unwrap().unwrap());
		assert_eq!(a5.hash(), longest_chain_select.finality_target(
			a5.hash(), Some(5)).unwrap().unwrap());

		assert_eq!(b4.hash(), longest_chain_select.finality_target(
			b2.hash(), Some(5)).unwrap().unwrap());
		assert_eq!(b4.hash(), longest_chain_select.finality_target(
			b3.hash(), Some(5)).unwrap().unwrap());
		assert_eq!(b4.hash(), longest_chain_select.finality_target(
			b4.hash(), Some(5)).unwrap().unwrap());

		assert_eq!(c3.hash(), longest_chain_select.finality_target(
			c3.hash(), Some(5)).unwrap().unwrap());

		assert_eq!(d2.hash(), longest_chain_select.finality_target(
			d2.hash(), Some(5)).unwrap().unwrap());


		// search only blocks with number <= 4

		assert_eq!(a4.hash(), longest_chain_select.finality_target(
			genesis_hash, Some(4)).unwrap().unwrap());
		assert_eq!(a4.hash(), longest_chain_select.finality_target(
			a1.hash(), Some(4)).unwrap().unwrap());
		assert_eq!(a4.hash(), longest_chain_select.finality_target(
			a2.hash(), Some(4)).unwrap().unwrap());
		assert_eq!(a4.hash(), longest_chain_select.finality_target(
			a3.hash(), Some(4)).unwrap().unwrap());
		assert_eq!(a4.hash(), longest_chain_select.finality_target(
			a4.hash(), Some(4)).unwrap().unwrap());
		assert_eq!(None, longest_chain_select.finality_target(
			a5.hash(), Some(4)).unwrap());

		assert_eq!(b4.hash(), longest_chain_select.finality_target(
			b2.hash(), Some(4)).unwrap().unwrap());
		assert_eq!(b4.hash(), longest_chain_select.finality_target(
			b3.hash(), Some(4)).unwrap().unwrap());
		assert_eq!(b4.hash(), longest_chain_select.finality_target(
			b4.hash(), Some(4)).unwrap().unwrap());

		assert_eq!(c3.hash(), longest_chain_select.finality_target(
			c3.hash(), Some(4)).unwrap().unwrap());

		assert_eq!(d2.hash(), longest_chain_select.finality_target(
			d2.hash(), Some(4)).unwrap().unwrap());


		// search only blocks with number <= 3

		assert_eq!(a3.hash(), longest_chain_select.finality_target(
			genesis_hash, Some(3)).unwrap().unwrap());
		assert_eq!(a3.hash(), longest_chain_select.finality_target(
			a1.hash(), Some(3)).unwrap().unwrap());
		assert_eq!(a3.hash(), longest_chain_select.finality_target(
			a2.hash(), Some(3)).unwrap().unwrap());
		assert_eq!(a3.hash(), longest_chain_select.finality_target(
			a3.hash(), Some(3)).unwrap().unwrap());
		assert_eq!(None, longest_chain_select.finality_target(
			a4.hash(), Some(3)).unwrap());
		assert_eq!(None, longest_chain_select.finality_target(
			a5.hash(), Some(3)).unwrap());

		assert_eq!(b3.hash(), longest_chain_select.finality_target(
			b2.hash(), Some(3)).unwrap().unwrap());
		assert_eq!(b3.hash(), longest_chain_select.finality_target(
			b3.hash(), Some(3)).unwrap().unwrap());
		assert_eq!(None, longest_chain_select.finality_target(
			b4.hash(), Some(3)).unwrap());

		assert_eq!(c3.hash(), longest_chain_select.finality_target(
			c3.hash(), Some(3)).unwrap().unwrap());

		assert_eq!(d2.hash(), longest_chain_select.finality_target(
			d2.hash(), Some(3)).unwrap().unwrap());


		// search only blocks with number <= 2

		assert_eq!(a2.hash(), longest_chain_select.finality_target(
			genesis_hash, Some(2)).unwrap().unwrap());
		assert_eq!(a2.hash(), longest_chain_select.finality_target(
			a1.hash(), Some(2)).unwrap().unwrap());
		assert_eq!(a2.hash(), longest_chain_select.finality_target(
			a2.hash(), Some(2)).unwrap().unwrap());
		assert_eq!(None, longest_chain_select.finality_target(
			a3.hash(), Some(2)).unwrap());
		assert_eq!(None, longest_chain_select.finality_target(
			a4.hash(), Some(2)).unwrap());
		assert_eq!(None, longest_chain_select.finality_target(
			a5.hash(), Some(2)).unwrap());

		assert_eq!(b2.hash(), longest_chain_select.finality_target(
			b2.hash(), Some(2)).unwrap().unwrap());
		assert_eq!(None, longest_chain_select.finality_target(
			b3.hash(), Some(2)).unwrap());
		assert_eq!(None, longest_chain_select.finality_target(
			b4.hash(), Some(2)).unwrap());

		assert_eq!(None, longest_chain_select.finality_target(
			c3.hash(), Some(2)).unwrap());

		assert_eq!(d2.hash(), longest_chain_select.finality_target(
			d2.hash(), Some(2)).unwrap().unwrap());


		// search only blocks with number <= 1

		assert_eq!(a1.hash(), longest_chain_select.finality_target(
			genesis_hash, Some(1)).unwrap().unwrap());
		assert_eq!(a1.hash(), longest_chain_select.finality_target(
			a1.hash(), Some(1)).unwrap().unwrap());
		assert_eq!(None, longest_chain_select.finality_target(
			a2.hash(), Some(1)).unwrap());
		assert_eq!(None, longest_chain_select.finality_target(
			a3.hash(), Some(1)).unwrap());
		assert_eq!(None, longest_chain_select.finality_target(
			a4.hash(), Some(1)).unwrap());
		assert_eq!(None, longest_chain_select.finality_target(
			a5.hash(), Some(1)).unwrap());

		assert_eq!(None, longest_chain_select.finality_target(
			b2.hash(), Some(1)).unwrap());
		assert_eq!(None, longest_chain_select.finality_target(
			b3.hash(), Some(1)).unwrap());
		assert_eq!(None, longest_chain_select.finality_target(
			b4.hash(), Some(1)).unwrap());

		assert_eq!(None, longest_chain_select.finality_target(
			c3.hash(), Some(1)).unwrap());

		assert_eq!(None, longest_chain_select.finality_target(
			d2.hash(), Some(1)).unwrap());

		// search only blocks with number <= 0

		assert_eq!(genesis_hash, longest_chain_select.finality_target(
			genesis_hash, Some(0)).unwrap().unwrap());
		assert_eq!(None, longest_chain_select.finality_target(
			a1.hash(), Some(0)).unwrap());
		assert_eq!(None, longest_chain_select.finality_target(
			a2.hash(), Some(0)).unwrap());
		assert_eq!(None, longest_chain_select.finality_target(
			a3.hash(), Some(0)).unwrap());
		assert_eq!(None, longest_chain_select.finality_target(
			a4.hash(), Some(0)).unwrap());
		assert_eq!(None, longest_chain_select.finality_target(
			a5.hash(), Some(0)).unwrap());

		assert_eq!(None, longest_chain_select.finality_target(
			b2.hash(), Some(0)).unwrap());
		assert_eq!(None, longest_chain_select.finality_target(
			b3.hash(), Some(0)).unwrap());
		assert_eq!(None, longest_chain_select.finality_target(
			b4.hash(), Some(0)).unwrap());

		assert_eq!(None, longest_chain_select.finality_target(
			c3.hash().clone(), Some(0)).unwrap());

		assert_eq!(None, longest_chain_select.finality_target(
			d2.hash().clone(), Some(0)).unwrap());
	fn best_containing_on_longest_chain_with_max_depth_higher_than_best() {
		let (client, longest_chain_select) = TestClientBuilder::new().build_with_longest_chain();
		let a1 = client.new_block(Default::default()).unwrap().bake().unwrap();
Wei Tang's avatar
Wei Tang committed
		client.import(BlockOrigin::Own, a1.clone()).unwrap();
		let a2 = client.new_block(Default::default()).unwrap().bake().unwrap();
Wei Tang's avatar
Wei Tang committed
		client.import(BlockOrigin::Own, a2.clone()).unwrap();
		let genesis_hash = client.info().chain.genesis_hash;
		assert_eq!(a2.hash(), longest_chain_select.finality_target(genesis_hash, Some(10)).unwrap().unwrap());
	#[test]
	fn key_changes_works() {
		let (client, _, test_cases) = prepare_client_with_key_changes();

		for (index, (begin, end, key, expected_result)) in test_cases.into_iter().enumerate() {
			let end = client.block_hash(end).unwrap().unwrap();
			let actual_result = client.key_changes(
				begin,
				BlockId::Hash(end),
				None,
				&StorageKey(key),
			).unwrap();
			match actual_result == expected_result {
				true => (),
				false => panic!(format!("Failed test {}: actual = {:?}, expected = {:?}",
					index, actual_result, expected_result)),
			}
		}
	}

	#[test]
	fn import_with_justification() {
		let client = test_client::new();

		// G -> A1
		let a1 = client.new_block(Default::default()).unwrap().bake().unwrap();
		client.import(BlockOrigin::Own, a1.clone()).unwrap();

		// A1 -> A2
		let a2 = client.new_block_at(&BlockId::Hash(a1.hash()), Default::default()).unwrap().bake().unwrap();
		client.import(BlockOrigin::Own, a2.clone()).unwrap();

		// A2 -> A3
		let justification = vec![1, 2, 3];
		let a3 = client.new_block_at(&BlockId::Hash(a2.hash()), Default::default()).unwrap().bake().unwrap();
		client.import_justified(BlockOrigin::Own, a3.clone(), justification.clone()).unwrap();

		assert_eq!(
			client.info().chain.finalized_hash,
			client.justification(&BlockId::Hash(a3.hash())).unwrap(),
			client.justification(&BlockId::Hash(a1.hash())).unwrap(),
			client.justification(&BlockId::Hash(a2.hash())).unwrap(),

	#[test]
	fn importing_diverged_finalized_block_should_trigger_reorg() {

		let client = test_client::new();

		// G -> A1 -> A2
		//   \
		//    -> B1
		let a1 = client.new_block_at(&BlockId::Number(0), Default::default()).unwrap().bake().unwrap();
		client.import(BlockOrigin::Own, a1.clone()).unwrap();

		let a2 = client.new_block_at(&BlockId::Hash(a1.hash()), Default::default()).unwrap().bake().unwrap();
		client.import(BlockOrigin::Own, a2.clone()).unwrap();

		let mut b1 = client.new_block_at(&BlockId::Number(0), Default::default()).unwrap();
		// needed to make sure B1 gets a different hash from A1
		b1.push_transfer(Transfer {
			from: AccountKeyring::Alice.into(),
			to: AccountKeyring::Ferdie.into(),
			amount: 1,
			nonce: 0,
		}).unwrap();
		// create but don't import B1 just yet
		let b1 = b1.bake().unwrap();

		// A2 is the current best since it's the longest chain
		assert_eq!(
			client.info().chain.best_hash,
			a2.hash(),
		);

		// importing B1 as finalized should trigger a re-org and set it as new best
		let justification = vec![1, 2, 3];
		client.import_justified(BlockOrigin::Own, b1.clone(), justification).unwrap();

		assert_eq!(
			client.info().chain.best_hash,
			client.info().chain.finalized_hash,
			b1.hash(),
		);
	}

	#[test]
	fn finalizing_diverged_block_should_trigger_reorg() {

		let (client, select_chain) = TestClientBuilder::new().build_with_longest_chain();

		// G -> A1 -> A2
		//   \
		//    -> B1 -> B2
		let a1 = client.new_block_at(&BlockId::Number(0), Default::default()).unwrap().bake().unwrap();
		client.import(BlockOrigin::Own, a1.clone()).unwrap();

		let a2 = client.new_block_at(&BlockId::Hash(a1.hash()), Default::default()).unwrap().bake().unwrap();
		client.import(BlockOrigin::Own, a2.clone()).unwrap();

		let mut b1 = client.new_block_at(&BlockId::Number(0), Default::default()).unwrap();
		// needed to make sure B1 gets a different hash from A1
		b1.push_transfer(Transfer {
			from: AccountKeyring::Alice.into(),
			to: AccountKeyring::Ferdie.into(),
			amount: 1,
			nonce: 0,
		}).unwrap();
		let b1 = b1.bake().unwrap();
		client.import(BlockOrigin::Own, b1.clone()).unwrap();

		let b2 = client.new_block_at(&BlockId::Hash(b1.hash()), Default::default()).unwrap().bake().unwrap();
		client.import(BlockOrigin::Own, b2.clone()).unwrap();

		// A2 is the current best since it's the longest chain
		assert_eq!(
			client.info().chain.best_hash,
			a2.hash(),
		);

		// we finalize block B1 which is on a different branch from current best
		// which should trigger a re-org.
		client.finalize_block(BlockId::Hash(b1.hash()), None).unwrap();

		// B1 should now be the latest finalized
		assert_eq!(
			client.info().chain.finalized_hash,
			b1.hash(),
		);

		// and B1 should be the new best block (`finalize_block` as no way of
		// knowing about B2)
		assert_eq!(
			client.info().chain.best_hash,
			b1.hash(),
		);

		// `SelectChain` should report B2 as best block though
		assert_eq!(
			select_chain.best_chain().unwrap().hash(),
			b2.hash(),
		);

		// after we build B3 on top of B2 and import it
		// it should be the new best block,
		let b3 = client.new_block_at(
			&BlockId::Hash(b2.hash()),
			Default::default(),
		).unwrap().bake().unwrap();
		client.import(BlockOrigin::Own, b3.clone()).unwrap();

		assert_eq!(
			client.info().chain.best_hash,

	#[test]
	fn get_header_by_block_number_doesnt_panic() {
		let client = test_client::new();

		// backend uses u32 for block numbers, make sure we don't panic when
		// trying to convert
		let id = BlockId::<Block>::Number(72340207214430721);
		client.header(&id).expect_err("invalid block number overflows u32");
	}

	#[test]
	fn state_reverted_on_reorg() {
		let _ = env_logger::try_init();
		let client = test_client::new();

		let current_balance = ||
			client.runtime_api().balance_of(
				&BlockId::number(client.info().chain.best_number), AccountKeyring::Alice.into()
			).unwrap();

		// G -> A1 -> A2
		//   \
		//    -> B1
		let mut a1 = client.new_block_at(&BlockId::Number(0), Default::default()).unwrap();
		a1.push_transfer(Transfer {
			from: AccountKeyring::Alice.into(),
			to: AccountKeyring::Bob.into(),
			amount: 10,
			nonce: 0,
		}).unwrap();
		let a1 = a1.bake().unwrap();
		client.import(BlockOrigin::Own, a1.clone()).unwrap();

		let mut b1 = client.new_block_at(&BlockId::Number(0), Default::default()).unwrap();
		b1.push_transfer(Transfer {
			from: AccountKeyring::Alice.into(),
			to: AccountKeyring::Ferdie.into(),
			amount: 50,
			nonce: 0,
		}).unwrap();
		let b1 = b1.bake().unwrap();
		// Reorg to B1
		client.import_as_best(BlockOrigin::Own, b1.clone()).unwrap();

		assert_eq!(950, current_balance());
		let mut a2 = client.new_block_at(&BlockId::Hash(a1.hash()), Default::default()).unwrap();
		a2.push_transfer(Transfer {
			from: AccountKeyring::Alice.into(),
			to: AccountKeyring::Charlie.into(),
			amount: 10,
			nonce: 1,
		}).unwrap();
		// Re-org to A2
		client.import_as_best(BlockOrigin::Own, a2.bake().unwrap()).unwrap();
		assert_eq!(980, current_balance());
	}

	#[test]
	fn doesnt_import_blocks_that_revert_finality() {
		let _ = env_logger::try_init();
		let tmp = tempfile::tempdir().unwrap();

		// we need to run with archive pruning to avoid pruning non-canonical
		// states
		let backend = Arc::new(Backend::new(
			DatabaseSettings {
				state_cache_size: 1 << 20,
				state_cache_child_ratio: None,
				pruning: PruningMode::ArchiveAll,
				source: DatabaseSettingsSrc::Path {
					path: tmp.path().into(),
					cache_size: None,
				}
			},
			u64::max_value(),
		).unwrap());

		let client = TestClientBuilder::with_backend(backend).build();

		//    -> C1
		//   /
		// G -> A1 -> A2
		//   \
		//    -> B1 -> B2 -> B3

		let a1 = client.new_block_at(&BlockId::Number(0), Default::default())
			.unwrap().bake().unwrap();
		client.import(BlockOrigin::Own, a1.clone()).unwrap();

		let a2 = client.new_block_at(&BlockId::Hash(a1.hash()), Default::default())
			.unwrap().bake().unwrap();
		client.import(BlockOrigin::Own, a2.clone()).unwrap();

		let mut b1 = client.new_block_at(&BlockId::Number(0), Default::default()).unwrap();

		// needed to make sure B1 gets a different hash from A1
		b1.push_transfer(Transfer {
			from: AccountKeyring::Alice.into(),
			to: AccountKeyring::Ferdie.into(),
			amount: 1,
			nonce: 0,
		}).unwrap();
		let b1 = b1.bake().unwrap();
		client.import(BlockOrigin::Own, b1.clone()).unwrap();

		let b2 = client.new_block_at(&BlockId::Hash(b1.hash()), Default::default())
			.unwrap().bake().unwrap();
		client.import(BlockOrigin::Own, b2.clone()).unwrap();

		// we will finalize A2 which should make it impossible to import a new
		// B3 at the same height but that doesnt't include it
		client.finalize_block(BlockId::Hash(a2.hash()), None).unwrap();

		let b3 = client.new_block_at(&BlockId::Hash(b2.hash()), Default::default())
			.unwrap().bake().unwrap();

		let import_err = client.import(BlockOrigin::Own, b3).err().unwrap();
		let expected_err = ConsensusError::ClientImport(
			error::Error::NotInFinalizedChain.to_string()
		);

		assert_eq!(
			import_err.to_string(),
			expected_err.to_string(),
		);

		// adding a C1 block which is lower than the last finalized should also
		// fail (with a cheaper check that doesn't require checking ancestry).
		let mut c1 = client.new_block_at(&BlockId::Number(0), Default::default()).unwrap();

		// needed to make sure C1 gets a different hash from A1 and B1
		c1.push_transfer(Transfer {
			from: AccountKeyring::Alice.into(),
			to: AccountKeyring::Ferdie.into(),
			amount: 2,
			nonce: 0,
		}).unwrap();
		let c1 = c1.bake().unwrap();

		let import_err = client.import(BlockOrigin::Own, c1).err().unwrap();
		let expected_err = ConsensusError::ClientImport(
			error::Error::NotInFinalizedChain.to_string()
		);

		assert_eq!(
			import_err.to_string(),
			expected_err.to_string(),
		);
	}