1use std::sync::Arc;
2
3use brk_error::Result;
4use brk_reader::Reader;
5use brk_rpc::Client;
6use brk_types::{BlockHash, Height};
7
8mod iterator;
9mod range;
10mod source;
11mod state;
12
13use iterator::*;
14use range::*;
15use source::*;
16use state::*;
17
18#[derive(Clone)]
27pub struct Blocks(Arc<Source>);
28
29impl Blocks {
30 pub fn new(client: &Client, reader: &Reader) -> Self {
32 Self::new_inner(Source::Smart {
33 client: client.clone(),
34 reader: reader.clone(),
35 })
36 }
37
38 pub fn new_rpc(client: &Client) -> Self {
40 Self::new_inner(Source::Rpc {
41 client: client.clone(),
42 })
43 }
44
45 pub fn new_reader(reader: &Reader) -> Self {
47 Self::new_inner(Source::Reader {
48 reader: reader.clone(),
49 })
50 }
51
52 fn new_inner(source: Source) -> Self {
53 Self(Arc::new(source))
54 }
55
56 pub fn range(&self, start: Height, end: Height) -> Result<BlockIterator> {
58 self.iter(BlockRange::Span { start, end })
59 }
60
61 pub fn start(&self, start: Height) -> Result<BlockIterator> {
63 self.iter(BlockRange::Start { start })
64 }
65
66 pub fn end(&self, end: Height) -> Result<BlockIterator> {
68 self.iter(BlockRange::End { end })
69 }
70
71 pub fn last(&self, n: u32) -> Result<BlockIterator> {
73 self.iter(BlockRange::Last { n })
74 }
75
76 pub fn after(&self, hash: Option<BlockHash>) -> Result<BlockIterator> {
78 self.iter(BlockRange::After { hash })
79 }
80
81 fn iter(&self, range: BlockRange) -> Result<BlockIterator> {
82 let (start, end, hash_opt) = self.resolve_range(range)?;
83
84 let count = end.saturating_sub(*start) + 1;
85
86 let state = match &*self.0 {
87 Source::Smart { client, reader } => {
88 if count <= 10 {
89 State::new_rpc(client.clone(), start, end, hash_opt)
90 } else {
91 State::new_reader(reader.clone(), start, end, hash_opt)
92 }
93 }
94 Source::Rpc { client } => State::new_rpc(client.clone(), start, end, hash_opt),
95 Source::Reader { reader, .. } => {
96 State::new_reader(reader.clone(), start, end, hash_opt)
97 }
98 };
99
100 Ok(BlockIterator::new(state))
101 }
102
103 fn resolve_range(&self, range: BlockRange) -> Result<(Height, Height, Option<BlockHash>)> {
104 let client = self.0.client();
105
106 match range {
107 BlockRange::Span { start, end } => Ok((start, end, None)),
108 BlockRange::Start { start } => {
109 let end = client.get_last_height()?;
110 Ok((start, end, None))
111 }
112 BlockRange::End { end } => Ok((Height::ZERO, end, None)),
113 BlockRange::Last { n } => {
114 let end = client.get_last_height()?;
115 let start = Height::new((*end).saturating_sub(n - 1));
116 Ok((start, end, None))
117 }
118 BlockRange::After { hash } => {
119 let start = if let Some(hash) = hash.as_ref() {
120 let block_info = client.get_block_header_info(hash)?;
121 (block_info.height + 1).into()
122 } else {
123 Height::ZERO
124 };
125 let end = client.get_last_height()?;
126 Ok((start, end, hash))
127 }
128 }
129 }
130}