@@ -14,35 +14,69 @@ use crate::{
14
14
/// BlockNumber is the block number of a Cardano transaction.
15
15
pub type BlockNumber = u64 ;
16
16
17
+ /// BlockRangeLength is the length of a block range.
18
+ pub type BlockRangeLength = u64 ;
19
+
17
20
/// BlockRange for the Cardano chain
18
21
#[ derive( Serialize , Deserialize , Clone , Eq , PartialEq , Debug , Hash ) ]
19
22
pub struct BlockRange {
20
23
inner_range : Range < u64 > ,
21
24
}
22
25
23
26
impl BlockRange {
27
+ /// The length of the block range
28
+ /// Important: this value should be updated with extreme care (probably with an era change) in order to avoid signing disruptions.
29
+ pub const LENGTH : BlockRangeLength = 15 ;
30
+
24
31
/// BlockRange factory
25
32
pub fn new ( start : BlockNumber , end : BlockNumber ) -> Self {
26
33
Self {
27
34
inner_range : start..end,
28
35
}
29
36
}
30
37
31
- /// Try to add two BlockRanges
32
- pub fn try_add ( & mut self , other : & BlockRange ) -> StdResult < BlockRange > {
33
- if self . inner_range . end . max ( other. inner_range . end )
34
- < self . inner_range . start . min ( other. inner_range . start )
35
- {
38
+ cfg_test_tools ! {
39
+ /// Try to add two BlockRanges
40
+ pub fn try_add( & self , other: & BlockRange ) -> StdResult <BlockRange > {
41
+ if self . inner_range. end. max( other. inner_range. end)
42
+ < self . inner_range. start. min( other. inner_range. start)
43
+ {
44
+ return Err ( anyhow!(
45
+ "BlockRange cannot be added as they don't strictly overlap"
46
+ ) ) ;
47
+ }
48
+
49
+ Ok ( Self {
50
+ inner_range: Range {
51
+ start: self . inner_range. start. min( other. inner_range. start) ,
52
+ end: self . inner_range. end. max( other. inner_range. end) ,
53
+ } ,
54
+ } )
55
+ }
56
+ }
57
+
58
+ /// Create a BlockRange from a block number
59
+ pub fn from_block_number ( number : BlockNumber ) -> Self {
60
+ // Unwrap is safe as the length is always strictly greater than 0
61
+ Self :: from_block_number_and_length ( number, Self :: LENGTH ) . unwrap ( )
62
+ }
63
+
64
+ /// Create a BlockRange from a block number and a range length
65
+ fn from_block_number_and_length (
66
+ number : BlockNumber ,
67
+ length : BlockRangeLength ,
68
+ ) -> StdResult < Self > {
69
+ if length == 0 {
36
70
return Err ( anyhow ! (
37
- "BlockRange cannot be added as they don't strictly overlap "
71
+ "BlockRange cannot be be computed with a length of 0 "
38
72
) ) ;
39
73
}
40
-
74
+ // The formula used to compute the lower bound of the block range is `⌊number / length⌋ * length`
75
+ // The computation of the floor is done with the integer division `/` of Rust
76
+ let block_range_start = ( number / length) * length;
77
+ let block_range_end = block_range_start + length;
41
78
Ok ( Self {
42
- inner_range : Range {
43
- start : self . inner_range . start . min ( other. inner_range . start ) ,
44
- end : self . inner_range . end . max ( other. inner_range . end ) ,
45
- } ,
79
+ inner_range : block_range_start..block_range_end,
46
80
} )
47
81
}
48
82
}
@@ -103,30 +137,79 @@ mod tests {
103
137
104
138
#[ test]
105
139
fn test_block_range_cmp ( ) {
106
- let range_1 = BlockRange :: new ( 1 , 10 ) ;
107
- let range_2 = BlockRange :: new ( 1 , 10 ) ;
108
- let range_3 = BlockRange :: new ( 1 , 11 ) ;
109
- let range_4 = BlockRange :: new ( 2 , 10 ) ;
110
-
111
- assert_eq ! ( range_1, range_2) ;
112
- assert_ne ! ( range_1, range_3) ;
113
- assert_ne ! ( range_1, range_4) ;
114
- assert_ne ! ( range_3, range_4) ;
115
-
116
- assert ! ( range_1 < range_3) ;
117
- assert ! ( range_1 < range_4) ;
118
- assert ! ( range_3 < range_4) ;
140
+ assert_eq ! ( BlockRange :: new( 1 , 10 ) , BlockRange :: new( 1 , 10 ) ) ;
141
+ assert_ne ! ( BlockRange :: new( 1 , 10 ) , BlockRange :: new( 1 , 11 ) ) ;
142
+ assert_ne ! ( BlockRange :: new( 1 , 10 ) , BlockRange :: new( 2 , 10 ) ) ;
143
+ assert_ne ! ( BlockRange :: new( 1 , 11 ) , BlockRange :: new( 2 , 10 ) ) ;
144
+
145
+ assert ! ( BlockRange :: new( 1 , 10 ) < BlockRange :: new( 1 , 11 ) ) ;
146
+ assert ! ( BlockRange :: new( 1 , 10 ) < BlockRange :: new( 2 , 10 ) ) ;
147
+ assert ! ( BlockRange :: new( 1 , 11 ) < BlockRange :: new( 2 , 10 ) ) ;
119
148
}
120
149
121
150
#[ test]
122
151
fn test_block_range_try_add ( ) {
123
- let mut range_1 = BlockRange :: new ( 1 , 10 ) ;
124
- let range_2 = BlockRange :: new ( 1 , 10 ) ;
125
- let range_3 = BlockRange :: new ( 1 , 11 ) ;
126
- let range_4 = BlockRange :: new ( 2 , 10 ) ;
127
-
128
- assert_eq ! ( range_1. try_add( & range_2) . unwrap( ) , range_1) ;
129
- assert_eq ! ( range_1. try_add( & range_3) . unwrap( ) , range_3) ;
130
- assert_eq ! ( range_1. try_add( & range_4) . unwrap( ) , BlockRange :: new( 1 , 10 ) ) ;
152
+ assert_eq ! (
153
+ BlockRange :: new( 1 , 10 )
154
+ . try_add( & BlockRange :: new( 1 , 10 ) )
155
+ . unwrap( ) ,
156
+ BlockRange :: new( 1 , 10 )
157
+ ) ;
158
+ assert_eq ! (
159
+ BlockRange :: new( 1 , 10 )
160
+ . try_add( & BlockRange :: new( 1 , 11 ) )
161
+ . unwrap( ) ,
162
+ BlockRange :: new( 1 , 11 )
163
+ ) ;
164
+ assert_eq ! (
165
+ BlockRange :: new( 1 , 10 )
166
+ . try_add( & BlockRange :: new( 2 , 10 ) )
167
+ . unwrap( ) ,
168
+ BlockRange :: new( 1 , 10 )
169
+ ) ;
170
+ }
171
+
172
+ #[ test]
173
+ fn test_block_range_from_number ( ) {
174
+ assert_eq ! ( BlockRange :: from_block_number( 0 ) , BlockRange :: new( 0 , 15 ) ) ;
175
+ assert_eq ! ( BlockRange :: from_block_number( 1 ) , BlockRange :: new( 0 , 15 ) ) ;
176
+ assert_eq ! ( BlockRange :: from_block_number( 14 ) , BlockRange :: new( 0 , 15 ) ) ;
177
+ assert_eq ! ( BlockRange :: from_block_number( 15 ) , BlockRange :: new( 15 , 30 ) ) ;
178
+ assert_eq ! ( BlockRange :: from_block_number( 16 ) , BlockRange :: new( 15 , 30 ) ) ;
179
+ assert_eq ! ( BlockRange :: from_block_number( 29 ) , BlockRange :: new( 15 , 30 ) ) ;
180
+ }
181
+
182
+ #[ test]
183
+ fn test_block_range_from_number_and_length_with_valid_input ( ) {
184
+ assert_eq ! (
185
+ BlockRange :: from_block_number_and_length( 0 , 10 ) . unwrap( ) ,
186
+ BlockRange :: new( 0 , 10 )
187
+ ) ;
188
+ assert_eq ! (
189
+ BlockRange :: from_block_number_and_length( 1 , 10 ) . unwrap( ) ,
190
+ BlockRange :: new( 0 , 10 )
191
+ ) ;
192
+ assert_eq ! (
193
+ BlockRange :: from_block_number_and_length( 9 , 10 ) . unwrap( ) ,
194
+ BlockRange :: new( 0 , 10 )
195
+ ) ;
196
+ assert_eq ! (
197
+ BlockRange :: from_block_number_and_length( 10 , 10 ) . unwrap( ) ,
198
+ BlockRange :: new( 10 , 20 )
199
+ ) ;
200
+ assert_eq ! (
201
+ BlockRange :: from_block_number_and_length( 11 , 10 ) . unwrap( ) ,
202
+ BlockRange :: new( 10 , 20 )
203
+ ) ;
204
+ assert_eq ! (
205
+ BlockRange :: from_block_number_and_length( 19 , 10 ) . unwrap( ) ,
206
+ BlockRange :: new( 10 , 20 )
207
+ ) ;
208
+ }
209
+
210
+ #[ test]
211
+ fn test_block_range_from_number_and_length_with_invalid_input ( ) {
212
+ BlockRange :: from_block_number_and_length ( 10 , 0 )
213
+ . expect_err ( "BlockRange should not be computed with a length of 0" ) ;
131
214
}
132
215
}
0 commit comments