Skip to main content

avail_rust_client/subscription/
block.rs

1//! Subscription adapters focused on block headers, bodies, and emitted events.
2
3use crate::{
4	AvailHeader, Client, LegacyBlock, RpcError, Sub,
5	block::{Block, events::BlockEventsQuery},
6};
7use avail_rust_core::{H256, rpc::BlockPhaseEvent};
8use std::time::Duration;
9
10/// Subscription wrapper that streams [`LegacyBlock`] values.
11#[derive(Clone)]
12pub struct LegacyBlockSub {
13	sub: Sub,
14}
15
16impl LegacyBlockSub {
17	/// Creates a subscription that yields legacy blocks as you iterate.
18	///
19	/// The client is cloned and no network traffic occurs until [`LegacyBlockSub::next`] or
20	/// [`LegacyBlockSub::prev`] is awaited.
21	///
22	/// # Arguments
23	/// * `client` - Client used to drive the subscription.
24	///
25	/// # Returns
26	/// Returns a [`LegacyBlockSub`] ready to iterate over legacy blocks.
27	pub fn new(client: Client) -> Self {
28		Self { sub: Sub::new(client) }
29	}
30
31	/// Fetches the next legacy block; rewinds the cursor if the RPC call fails.
32	///
33	/// # Returns
34	/// - `Ok(Some(LegacyBlock))` when the node provides a block for the current cursor.
35	/// - `Ok(None)` when the block exists but contains no legacy payload.
36	/// - `Err(RpcError)` when the RPC call fails; the internal block height resets so a retry will
37	///   reattempt the same block.
38	///
39	/// # Errors
40	/// Returns `Err(RpcError)` when the underlying RPC request fails.
41	pub async fn next(&mut self) -> Result<Option<LegacyBlock>, RpcError> {
42		let info = self.sub.next().await?;
43		let block = match self
44			.sub
45			.client_ref()
46			.chain()
47			.retry_on(Some(self.sub.should_retry_on_error()), Some(true))
48			.legacy_block(Some(info.hash))
49			.await
50		{
51			Ok(x) => x,
52			Err(err) => {
53				// Revet block height if we fail to fetch block
54				self.sub.set_block_height(info.height);
55				return Err(err);
56			},
57		};
58		Ok(block)
59	}
60
61	/// Fetches the previous legacy block; rewinds the cursor if the RPC call fails.
62	///
63	/// The result semantics mirror [`LegacyBlockSub::next`].
64	///
65	/// # Returns
66	/// - `Ok(Some(LegacyBlock))` when the previous block is available.
67	/// - `Ok(None)` when the block exists but contains no legacy payload.
68	/// - `Err(RpcError)` when the RPC call fails and the cursor is rewound.
69	///
70	/// # Errors
71	/// Returns `Err(RpcError)` when the underlying RPC request fails.
72	pub async fn prev(&mut self) -> Result<Option<LegacyBlock>, RpcError> {
73		let info = self.sub.prev().await?;
74		let block = match self
75			.sub
76			.client_ref()
77			.chain()
78			.retry_on(Some(self.sub.should_retry_on_error()), Some(true))
79			.legacy_block(Some(info.hash))
80			.await
81		{
82			Ok(x) => x,
83			Err(err) => {
84				// Revet block height if we fail to fetch block
85				self.sub.set_block_height(info.height);
86				return Err(err);
87			},
88		};
89		Ok(block)
90	}
91
92	/// Reports whether the subscription retries after RPC failures.
93	///
94	/// # Returns
95	/// Returns `true` when retries are enabled, otherwise `false`.
96	pub fn should_retry_on_error(&self) -> bool {
97		self.sub.should_retry_on_error()
98	}
99
100	/// Follow best blocks instead of finalized ones.
101	///
102	/// # Arguments
103	/// * `value` - `true` to follow best blocks, `false` for finalized blocks.
104	pub fn use_best_block(&mut self, value: bool) {
105		self.sub.use_best_block(value);
106	}
107
108	/// Jump the cursor to a specific starting height.
109	///
110	/// # Arguments
111	/// * `block_height` - Height used as the starting point for iteration.
112	pub fn set_block_height(&mut self, block_height: u32) {
113		self.sub.set_block_height(block_height);
114	}
115
116	/// Change how often we poll for new blocks when following the chain head.
117	///
118	/// # Arguments
119	/// * `value` - Poll interval used while tailing the head.
120	pub fn set_pool_rate(&mut self, value: Duration) {
121		self.sub.set_pool_rate(value);
122	}
123
124	/// Controls retry behaviour: `Some(true)` forces retries, `Some(false)` disables them, and `None`
125	/// keeps the client's default.
126	///
127	/// # Arguments
128	/// * `value` - Retry override applied to the underlying subscription.
129	pub fn set_retry_on_error(&mut self, value: Option<bool>) {
130		self.sub.set_retry_on_error(value);
131	}
132}
133
134#[derive(Clone)]
135pub struct BlockSubValue {
136	pub value: Block,
137	pub block_height: u32,
138	pub block_hash: H256,
139}
140
141/// Subscription wrapper that streams block handles (`Block`).
142#[derive(Clone)]
143pub struct BlockSub {
144	sub: Sub,
145}
146
147impl BlockSub {
148	/// Creates a subscription that yields [`Block`] handles as you iterate. The handlers can be
149	/// used to inspect extrinsics, events, or raw data.
150	///
151	/// # Arguments
152	/// * `client` - Client used to drive the subscription.
153	///
154	/// # Returns
155	/// Returns a [`BlockSub`] ready to iterate over blocks.
156	pub fn new(client: Client) -> Self {
157		Self { sub: Sub::new(client) }
158	}
159
160	/// Fetches the next block handle along with its `BlockInfo`.
161	///
162	/// # Returns
163	/// - `Ok(BlockSubValue)` when a block is available at the current cursor.
164	/// - `Err(RpcError)` when the underlying subscription fails to advance.
165	///
166	/// # Errors
167	/// Returns `Err(RpcError)` when fetching the next block fails.
168	pub async fn next(&mut self) -> Result<BlockSubValue, RpcError> {
169		let info = self.sub.next().await?;
170		let value = Block::new(self.sub.client_ref().clone(), info.hash);
171		Ok(BlockSubValue { value, block_hash: info.hash, block_height: info.height })
172	}
173
174	/// Fetches the previous block handle along with its `BlockInfo`.
175	///
176	/// Return semantics mirror [`BlockSub::next`].
177	///
178	/// # Returns
179	/// Returns the previous block handle and metadata, or `Err(RpcError)` on failure.
180	///
181	/// # Errors
182	/// Returns `Err(RpcError)` when fetching the previous block fails.
183	pub async fn prev(&mut self) -> Result<BlockSubValue, RpcError> {
184		let info = self.sub.prev().await?;
185		let value = Block::new(self.sub.client_ref().clone(), info.hash);
186		Ok(BlockSubValue { value, block_hash: info.hash, block_height: info.height })
187	}
188
189	/// Reports whether failed RPC calls will be retried.
190	pub fn should_retry_on_error(&self) -> bool {
191		self.sub.should_retry_on_error()
192	}
193
194	/// Follow best blocks instead of finalized ones.
195	///
196	/// # Arguments
197	/// * `value` - `true` to follow best blocks, `false` for finalized blocks.
198	pub fn use_best_block(&mut self, value: bool) {
199		self.sub.use_best_block(value);
200	}
201
202	/// Jump the cursor to a specific starting height.
203	///
204	/// # Arguments
205	/// * `block_height` - Height used as the starting point for iteration.
206	pub fn set_block_height(&mut self, block_height: u32) {
207		self.sub.set_block_height(block_height);
208	}
209
210	/// Change how often we poll for new blocks when tailing the head.
211	///
212	/// # Arguments
213	/// * `value` - Poll interval used while tailing the head.
214	pub fn set_pool_rate(&mut self, value: Duration) {
215		self.sub.set_pool_rate(value);
216	}
217
218	/// Controls retry behaviour: `Some(true)` forces retries, `Some(false)` disables them, and `None`
219	/// keeps the client's default.
220	///
221	/// # Arguments
222	/// * `value` - Retry override applied to the underlying subscription.
223	pub fn set_retry_on_error(&mut self, value: Option<bool>) {
224		self.sub.set_retry_on_error(value);
225	}
226}
227
228#[derive(Debug, Clone)]
229pub struct BlockEventsSubValue {
230	pub list: Vec<BlockPhaseEvent>,
231	pub block_height: u32,
232	pub block_hash: H256,
233}
234
235/// Subscription wrapper that streams [`BlockPhaseEvent`] lists.
236#[derive(Clone)]
237pub struct BlockEventsSub {
238	sub: Sub,
239	opts: avail_rust_core::rpc::EventOpts,
240}
241
242impl BlockEventsSub {
243	/// Creates a subscription that yields event batches filtered by the supplied options. No network
244	/// calls are made until [`BlockEventsSub::next`] is awaited.
245	pub fn new(client: Client, opts: avail_rust_core::rpc::EventOpts) -> Self {
246		Self { sub: Sub::new(client), opts }
247	}
248
249	/// Fetches the next block with events matching the configured filters.
250	///
251	/// This function automatically skips blocks with empty event lists and continues searching
252	/// until a block with events is found. For direct access to all blocks (including those with empty events),
253	/// use [`BlockEventsSub::next_step`].
254	///
255	/// # Returns
256	/// - `Ok(BlockEventsSubValue)` when a block with events matching the configured filters is found.
257	/// - `Err(crate::Error)` when the RPC request fails; the internal cursor rewinds so the block can be
258	///   retried.
259	///
260	/// # Behavior
261	/// - Blocks with empty event lists are automatically skipped
262	/// - The function will continue to the next block until events are found
263	/// - On RPC failure, the cursor is rewound to allow retrying the same block
264	///
265	/// # Errors
266	/// Returns `Err(crate::Error)` when the underlying RPC request fails.
267	pub async fn next(&mut self) -> Result<BlockEventsSubValue, crate::Error> {
268		loop {
269			let events = self.next_step().await?;
270			if events.list.is_empty() {
271				continue;
272			}
273			return Ok(events);
274		}
275	}
276
277	/// Fetches the next block's events without filtering empty results.
278	///
279	/// This is a lower-level function that returns events for the next block regardless of whether
280	/// the event list is empty. Use [`BlockEventsSub::next`] for automatic filtering of empty event lists.
281	///
282	/// # Returns
283	/// - `Ok(BlockEventsSubValue)` containing the block's events, height, and hash.
284	/// - `Err(crate::Error)` when the RPC request fails; the internal cursor rewinds so the block can be
285	///   retried.
286	///
287	/// # Errors
288	/// Returns `Err(crate::Error)` when the underlying RPC request to fetch block events fails.
289	pub async fn next_step(&mut self) -> Result<BlockEventsSubValue, crate::Error> {
290		let info = self.sub.next().await?;
291		let block = BlockEventsQuery::new(self.sub.client_ref().clone(), info.hash);
292		let events = match block.raw(self.opts.clone()).await {
293			Ok(x) => x,
294			Err(err) => {
295				// Revet block height if we fail to fetch events
296				self.sub.set_block_height(info.height);
297				return Err(err);
298			},
299		};
300
301		return Ok(BlockEventsSubValue {
302			list: events,
303			block_height: info.height,
304			block_hash: info.hash,
305		});
306	}
307
308	/// Replaces the filter options applied to subsequent `next` calls.
309	///
310	/// # Arguments
311	/// * `value` - New event filtering options supplied to the RPC query.
312	pub fn set_options(&mut self, value: avail_rust_core::rpc::EventOpts) {
313		self.opts = value;
314	}
315
316	/// Reports whether failed RPC calls will be retried.
317	pub fn should_retry_on_error(&self) -> bool {
318		self.sub.should_retry_on_error()
319	}
320
321	/// Follow best blocks instead of finalized ones.
322	pub fn use_best_block(&mut self, value: bool) {
323		self.sub.use_best_block(value);
324	}
325
326	/// Jump the cursor to a specific starting height.
327	pub fn set_block_height(&mut self, block_height: u32) {
328		self.sub.set_block_height(block_height);
329	}
330
331	/// Change how often the subscription polls for new blocks when following the head.
332	pub fn set_pool_rate(&mut self, value: Duration) {
333		self.sub.set_pool_rate(value);
334	}
335
336	/// Override the retry behaviour (`Some(true)` = force, `Some(false)` = disable).
337	pub fn set_retry_on_error(&mut self, value: Option<bool>) {
338		self.sub.set_retry_on_error(value);
339	}
340}
341
342/// Subscription that mirrors [`Sub`] but yields [`AvailHeader`].
343#[derive(Clone)]
344pub struct BlockHeaderSub {
345	sub: Sub,
346}
347
348impl BlockHeaderSub {
349	/// Creates a new [`AvailHeader`] subscription.
350	/// Creates a subscription that yields legacy blocks as you iterate.
351	///
352	/// The client is cloned and no network traffic occurs until [`LegacyBlockSub::next`] or
353	/// [`LegacyBlockSub::prev`] is awaited.
354	///
355	/// # Arguments
356	/// * `client` - Client used to drive the subscription.
357	///
358	/// # Returns
359	/// Returns a [`LegacyBlockSub`] ready to iterate over legacy blocks.
360	pub fn new(client: Client) -> Self {
361		Self { sub: Sub::new(client) }
362	}
363
364	/// Returns the next [`AvailHeader`] matching the underlying [`Sub::next`] cursor.
365	///
366	/// When the RPC call fails, the internal height is rewound so the same block can be retried.
367	pub async fn next(&mut self) -> Result<Option<AvailHeader>, crate::Error> {
368		let info = self.sub.next().await?;
369		let header = match self
370			.sub
371			.client_ref()
372			.chain()
373			.retry_on(Some(self.sub.should_retry_on_error()), Some(true))
374			.block_header(Some(info.hash))
375			.await
376		{
377			Ok(x) => x,
378			Err(err) => {
379				// Revet block height if we fail to fetch block header
380				self.sub.set_block_height(info.height);
381				return Err(err);
382			},
383		};
384
385		Ok(header)
386	}
387
388	/// Returns the previous [`AvailHeader`] using [`Sub::prev`] as the cursor source.
389	///
390	/// When the RPC call fails, the internal height is rewound so the same block can be retried.
391	pub async fn prev(&mut self) -> Result<Option<AvailHeader>, crate::Error> {
392		let info = self.sub.prev().await?;
393		let header = match self
394			.sub
395			.client_ref()
396			.chain()
397			.retry_on(Some(self.sub.should_retry_on_error()), Some(true))
398			.block_header(Some(info.hash))
399			.await
400		{
401			Ok(x) => x,
402			Err(err) => {
403				// Revet block height if we fail to fetch block header
404				self.sub.set_block_height(info.height);
405				return Err(err);
406			},
407		};
408
409		Ok(header)
410	}
411
412	/// Reports whether the subscription retries after RPC failures.
413	pub fn should_retry_on_error(&self) -> bool {
414		self.sub.should_retry_on_error()
415	}
416
417	/// Follow best blocks instead of finalized ones.
418	pub fn use_best_block(&mut self, value: bool) {
419		self.sub.use_best_block(value);
420	}
421
422	/// Jump the cursor to a specific starting height.
423	pub fn set_block_height(&mut self, block_height: u32) {
424		self.sub.set_block_height(block_height);
425	}
426
427	/// Change how often we poll for new blocks.
428	pub fn set_pool_rate(&mut self, value: Duration) {
429		self.sub.set_pool_rate(value);
430	}
431
432	/// Choose whether this subscription should retry after RPC failures.
433	pub fn set_retry_on_error(&mut self, value: Option<bool>) {
434		self.sub.set_retry_on_error(value);
435	}
436}
437
438#[cfg(test)]
439mod tests {
440	use super::*;
441	use crate::{clients::mock_client::MockClient, error::Error, prelude::*, subxt_rpcs::RpcClient};
442
443	// This test will be by flaky and that is OK.
444	#[tokio::test]
445	async fn block_sub_test() -> Result<(), Error> {
446		let client = Client::new(TURING_ENDPOINT).await?;
447
448		//
449		// Test Case 1: Latest Block Height + Next
450		//
451		let mut sub = BlockSub::new(client.clone());
452
453		let block_height = client.finalized().block_height().await?;
454		let value = sub.next().await?;
455		assert_eq!(value.block_height, block_height);
456
457		//
458		// Test Case 2: Latest Block Height + Prev
459		//
460		let mut sub = BlockSub::new(client.clone());
461
462		let block_height = client.finalized().block_height().await?;
463		let value = sub.prev().await?;
464		assert_eq!(value.block_height, block_height - 1);
465
466		//
467		// Test Case 3: Set Block Height + Next + Next + Next
468		//
469		let block_height = 1900000u32;
470		let mut sub = BlockSub::new(client.clone());
471		sub.set_block_height(block_height);
472		for i in 0..3 {
473			let value = sub.next().await?;
474			assert_eq!(value.block_height, block_height + i);
475		}
476
477		//
478		// Test Case 4: Set Block Height + Prev + Prev + Prev
479		//
480		let block_height = 1900000u32;
481		let mut sub = BlockSub::new(client.clone());
482		sub.set_block_height(block_height);
483		for i in 0..3 {
484			let value = sub.prev().await?;
485			assert_eq!(value.block_height, block_height - i - 1);
486		}
487
488		//
489		// Test Case 5: Set Block Height + Next + Prev
490		//
491		let block_height = 1900000u32;
492		let mut sub = BlockSub::new(client.clone());
493		sub.set_block_height(block_height);
494
495		let value = sub.next().await?;
496		assert_eq!(value.block_height, block_height);
497
498		let value = sub.prev().await?;
499		assert_eq!(value.block_height, block_height - 1);
500
501		//
502		// Test Case 6: Set Block Height + Prev + Next
503		//
504		let block_height = 1900000u32;
505		let mut sub = BlockSub::new(client.clone());
506		sub.set_block_height(block_height);
507
508		let value = sub.prev().await?;
509		assert_eq!(value.block_height, block_height - 1);
510
511		let value = sub.next().await?;
512		assert_eq!(value.block_height, block_height);
513
514		Ok(())
515	}
516
517	// This test will be by flaky and that is OK.
518	#[tokio::test]
519	async fn header_sub_test() -> Result<(), Error> {
520		let (rpc_client, mut commander) = MockClient::new(TURING_ENDPOINT);
521		let client = Client::from_rpc_client(RpcClient::new(rpc_client)).await?;
522
523		//
524		// Test Case 1: Latest Block Height + Next
525		//
526		let mut sub = BlockHeaderSub::new(client.clone());
527
528		let block_height = client.finalized().block_height().await?;
529		let value = sub.next().await?.expect("Should be there");
530		assert_eq!(value.number, block_height);
531
532		//
533		// Test Case 2: Latest Block Height + Prev
534		//
535		let mut sub = BlockHeaderSub::new(client.clone());
536
537		let block_height = client.finalized().block_height().await?;
538		let value = sub.prev().await?.expect("Should be there");
539		assert_eq!(value.number, block_height - 1);
540
541		//
542		// Test Case 3: Set Block Height + Next + Next + Next
543		//
544		let block_height = 1900000u32;
545		let mut sub = BlockHeaderSub::new(client.clone());
546		sub.set_block_height(block_height);
547		for i in 0..3 {
548			let value = sub.next().await?.expect("Should be there");
549			assert_eq!(value.number, block_height + i);
550		}
551
552		//
553		// Test Case 4: Set Block Height + Prev + Prev + Prev
554		//
555		let block_height = 1900000u32;
556		let mut sub = BlockHeaderSub::new(client.clone());
557		sub.set_block_height(block_height);
558		for i in 0..3 {
559			let value = sub.prev().await?.expect("Should be there");
560			assert_eq!(value.number, block_height - i - 1);
561		}
562
563		//
564		// Test Case 5: Set Block Height + Next + Prev
565		//
566		let block_height = 1900000u32;
567		let mut sub = BlockHeaderSub::new(client.clone());
568		sub.set_block_height(block_height);
569
570		let value = sub.next().await?.expect("Should be there");
571		assert_eq!(value.number, block_height);
572
573		let value = sub.prev().await?.expect("Should be there");
574		assert_eq!(value.number, block_height - 1);
575
576		//
577		// Test Case 6: Set Block Height + Prev + Next
578		//
579		let block_height = 1900000u32;
580		let mut sub = BlockHeaderSub::new(client.clone());
581		sub.set_block_height(block_height);
582
583		let value = sub.prev().await?.expect("Should be there");
584		assert_eq!(value.number, block_height - 1);
585
586		let value = sub.next().await?.expect("Should be there");
587		assert_eq!(value.number, block_height);
588
589		//
590		// Test Case 6: Set Block Height + Next + Fail + Next
591		//
592		let block_height = 1900000u32;
593		let mut sub = BlockHeaderSub::new(client.clone());
594		sub.set_retry_on_error(Some(false));
595		sub.set_block_height(block_height);
596
597		let value = sub.next().await?.expect("Should be there");
598		assert_eq!(value.number, block_height);
599		assert_eq!(sub.sub.as_finalized().next_block_height, block_height + 1);
600
601		commander.block_header_err(None);
602		let _ = sub.next().await.expect_err("Should fail");
603		assert_eq!(sub.sub.as_finalized().next_block_height, block_height + 1);
604
605		let value = sub.next().await?.expect("Should be there");
606		assert_eq!(value.number, block_height + 1);
607		assert_eq!(sub.sub.as_finalized().next_block_height, block_height + 2);
608
609		Ok(())
610	}
611
612	// This test will be by flaky and that is OK.
613	#[tokio::test]
614	async fn legacy_block_sub_test() -> Result<(), Error> {
615		let (rpc_client, mut commander) = MockClient::new(TURING_ENDPOINT);
616		let client = Client::from_rpc_client(RpcClient::new(rpc_client)).await?;
617
618		//
619		// Test Case 1: Latest Block Height + Next
620		//
621		let mut sub = LegacyBlockSub::new(client.clone());
622
623		let block_height = client.finalized().block_height().await?;
624		let value = sub.next().await?.expect("Should be there");
625		assert_eq!(value.block.header.number, block_height);
626
627		//
628		// Test Case 2: Latest Block Height + Prev
629		//
630		let mut sub = LegacyBlockSub::new(client.clone());
631
632		let block_height = client.finalized().block_height().await?;
633		let value = sub.prev().await?.expect("Should be there");
634		assert_eq!(value.block.header.number, block_height - 1);
635
636		//
637		// Test Case 3: Set Block Height + Next + Next + Next
638		//
639		let block_height = 1900000u32;
640		let mut sub = LegacyBlockSub::new(client.clone());
641		sub.set_block_height(block_height);
642		for i in 0..3 {
643			let value = sub.next().await?.expect("Should be there");
644			assert_eq!(value.block.header.number, block_height + i);
645		}
646
647		//
648		// Test Case 4: Set Block Height + Prev + Prev + Prev
649		//
650		let block_height = 1900000u32;
651		let mut sub = LegacyBlockSub::new(client.clone());
652		sub.set_block_height(block_height);
653		for i in 0..3 {
654			let value = sub.prev().await?.expect("Should be there");
655			assert_eq!(value.block.header.number, block_height - i - 1);
656		}
657
658		//
659		// Test Case 5: Set Block Height + Next + Prev
660		//
661		let block_height = 1900000u32;
662		let mut sub = LegacyBlockSub::new(client.clone());
663		sub.set_block_height(block_height);
664
665		let value = sub.next().await?.expect("Should be there");
666		assert_eq!(value.block.header.number, block_height);
667
668		let value = sub.prev().await?.expect("Should be there");
669		assert_eq!(value.block.header.number, block_height - 1);
670
671		//
672		// Test Case 6: Set Block Height + Prev + Next
673		//
674		let block_height = 1900000u32;
675		let mut sub = LegacyBlockSub::new(client.clone());
676		sub.set_block_height(block_height);
677
678		let value = sub.prev().await?.expect("Should be there");
679		assert_eq!(value.block.header.number, block_height - 1);
680
681		let value = sub.next().await?.expect("Should be there");
682		assert_eq!(value.block.header.number, block_height);
683
684		//
685		// Test Case 6: Set Block Height + Next + Fail + Next
686		//
687		let block_height = 1900000u32;
688		let mut sub = LegacyBlockSub::new(client.clone());
689		sub.set_retry_on_error(Some(false));
690		sub.set_block_height(block_height);
691
692		let value = sub.next().await?.expect("Should be there");
693		assert_eq!(value.block.header.number, block_height);
694		assert_eq!(sub.sub.as_finalized().next_block_height, block_height + 1);
695
696		commander.legacy_block_err(None);
697		let _ = sub.next().await.expect_err("Should fail");
698		assert_eq!(sub.sub.as_finalized().next_block_height, block_height + 1);
699
700		let value = sub.next().await?.expect("Should be there");
701		assert_eq!(value.block.header.number, block_height + 1);
702		assert_eq!(sub.sub.as_finalized().next_block_height, block_height + 2);
703
704		Ok(())
705	}
706}