14
14
// You should have received a copy of the GNU General Public License
15
15
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
16
16
17
- use bridge_node_runtime:: { BlockNumber , Hash , Header as RuntimeHeader } ;
18
- use codec:: Decode ;
17
+ use bridge_node_runtime:: { Block , BlockNumber , Hash , Header as RuntimeHeader } ;
18
+ use codec:: { Decode , Encode } ;
19
+ use ethereum_types:: U256 ;
19
20
use sp_blockchain:: Error as ClientError ;
21
+ use sp_finality_grandpa:: { AuthorityList , ConsensusLog , GRANDPA_ENGINE_ID } ;
20
22
21
23
/// Builtin errors.
22
24
#[ derive( Debug ) ]
23
25
pub enum Error {
26
+ /// Failed to decode block number.
27
+ BlockNumberDecode ,
24
28
/// Failed to decode Substrate header.
25
29
HeaderDecode ( codec:: Error ) ,
26
30
/// Failed to decode best voters set.
27
- BestVotersDecode ( codec:: Error ) ,
31
+ BestSetDecode ( codec:: Error ) ,
28
32
/// Failed to decode finality proof.
29
33
FinalityProofDecode ( codec:: Error ) ,
30
34
/// Failed to verify justification.
31
35
JustificationVerify ( ClientError ) ,
32
36
}
33
37
34
38
/// Substrate header.
35
- #[ derive( Debug ) ]
39
+ #[ derive( Debug , PartialEq ) ]
36
40
pub struct Header {
37
41
/// Header hash.
38
42
pub hash : Hash ,
@@ -45,35 +49,272 @@ pub struct Header {
45
49
}
46
50
47
51
/// GRANDPA validators set change signal.
48
- #[ derive( Debug ) ]
52
+ #[ derive( Debug , PartialEq ) ]
49
53
pub struct ValidatorsSetSignal {
50
54
/// Signal delay.
51
55
pub delay : BlockNumber ,
52
56
/// New validators set.
53
57
pub validators : Vec < u8 > ,
54
58
}
55
59
60
+ /// Convert from U256 to BlockNumber. Fails if `U256` value isn't fitting within `BlockNumber`
61
+ /// limits (the runtime referenced by this module uses u32 as `BlockNumber`).
62
+ pub fn to_substrate_block_number ( number : U256 ) -> Result < BlockNumber , Error > {
63
+ match number == number. low_u32 ( ) . into ( ) {
64
+ true => Ok ( number. low_u32 ( ) ) ,
65
+ false => Err ( Error :: BlockNumberDecode ) ,
66
+ }
67
+ }
68
+
69
+ /// Convert from BlockNumber to U256.
70
+ pub fn from_substrate_block_number ( number : BlockNumber ) -> Result < U256 , Error > {
71
+ Ok ( U256 :: from ( number as u64 ) )
72
+ }
73
+
56
74
/// Parse Substrate header.
57
75
pub fn parse_substrate_header ( raw_header : & [ u8 ] ) -> Result < Header , Error > {
58
76
RuntimeHeader :: decode ( & mut & raw_header[ ..] )
59
77
. map ( |header| Header {
60
78
hash : header. hash ( ) ,
61
79
parent_hash : header. parent_hash ,
62
80
number : header. number ,
63
- signal : None , // TODO: parse me
81
+ signal : sp_runtime:: traits:: Header :: digest ( & header)
82
+ . log ( |log| {
83
+ log. as_consensus ( ) . and_then ( |( engine_id, log) | {
84
+ if engine_id == GRANDPA_ENGINE_ID {
85
+ Some ( log)
86
+ } else {
87
+ None
88
+ }
89
+ } )
90
+ } )
91
+ . and_then ( |log| ConsensusLog :: decode ( & mut & log[ ..] ) . ok ( ) )
92
+ . and_then ( |log| match log {
93
+ ConsensusLog :: ScheduledChange ( scheduled_change) => Some ( ValidatorsSetSignal {
94
+ delay : scheduled_change. delay ,
95
+ validators : scheduled_change. next_authorities . encode ( ) ,
96
+ } ) ,
97
+ _ => None ,
98
+ } ) ,
64
99
} )
65
100
. map_err ( Error :: HeaderDecode )
66
101
}
67
102
68
103
/// Verify GRANDPA finality proof.
69
104
pub fn verify_substrate_finality_proof (
70
- _best_set_id : u64 ,
71
- _raw_best_voters : & [ u8 ] ,
72
- _raw_best_header : & [ u8 ] ,
73
- _raw_headers : & [ & [ u8 ] ] ,
74
- _raw_finality_proof : & [ u8 ] ,
75
- ) -> Result < ( usize , usize ) , Error > {
76
- Err ( Error :: JustificationVerify ( ClientError :: Msg (
77
- "Not yet implemented" . into ( ) ,
78
- ) ) ) // TODO: implement me
105
+ finality_target_number : BlockNumber ,
106
+ finality_target_hash : Hash ,
107
+ best_set_id : u64 ,
108
+ raw_best_set : & [ u8 ] ,
109
+ raw_finality_proof : & [ u8 ] ,
110
+ ) -> Result < ( ) , Error > {
111
+ let best_set = AuthorityList :: decode ( & mut & raw_best_set[ ..] ) . map_err ( Error :: BestSetDecode ) ?;
112
+ sc_finality_grandpa:: GrandpaJustification :: < Block > :: decode_and_verify_finalizes (
113
+ & raw_finality_proof,
114
+ ( finality_target_hash, finality_target_number) ,
115
+ best_set_id,
116
+ & best_set. into_iter ( ) . collect ( ) ,
117
+ )
118
+ . map_err ( Error :: JustificationVerify )
119
+ . map ( |_| ( ) )
120
+ }
121
+
122
+ #[ cfg( test) ]
123
+ mod tests {
124
+ use super :: * ;
125
+ use bridge_node_runtime:: DigestItem ;
126
+ use sp_core:: crypto:: Public ;
127
+ use sp_finality_grandpa:: { AuthorityId , ScheduledChange } ;
128
+ use sp_runtime:: generic:: Digest ;
129
+
130
+ #[ test]
131
+ fn to_substrate_block_number_succeeds ( ) {
132
+ assert_eq ! ( to_substrate_block_number( U256 :: zero( ) ) . unwrap( ) , 0 ) ;
133
+ assert_eq ! (
134
+ to_substrate_block_number( U256 :: from( std:: u32 :: MAX as u64 ) ) . unwrap( ) ,
135
+ 0xFFFFFFFF
136
+ ) ;
137
+ }
138
+
139
+ #[ test]
140
+ fn to_substrate_block_number_fails ( ) {
141
+ assert ! ( matches!(
142
+ to_substrate_block_number( U256 :: from( std:: u32 :: MAX as u64 + 1 ) ) ,
143
+ Err ( Error :: BlockNumberDecode )
144
+ ) ) ;
145
+ }
146
+
147
+ #[ test]
148
+ fn from_substrate_block_number_succeeds ( ) {
149
+ assert_eq ! ( from_substrate_block_number( 0 ) . unwrap( ) , U256 :: zero( ) ) ;
150
+ assert_eq ! (
151
+ from_substrate_block_number( std:: u32 :: MAX ) . unwrap( ) ,
152
+ U256 :: from( std:: u32 :: MAX )
153
+ ) ;
154
+ }
155
+
156
+ #[ test]
157
+ fn substrate_header_without_signal_parsed ( ) {
158
+ let raw_header = RuntimeHeader {
159
+ parent_hash : [ 0u8 ; 32 ] . into ( ) ,
160
+ number : 0 ,
161
+ state_root : "b2fc47904df5e355c6ab476d89fbc0733aeddbe302f0b94ba4eea9283f7e89e7"
162
+ . parse ( )
163
+ . unwrap ( ) ,
164
+ extrinsics_root : "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314"
165
+ . parse ( )
166
+ . unwrap ( ) ,
167
+ digest : Default :: default ( ) ,
168
+ }
169
+ . encode ( ) ;
170
+ assert_eq ! (
171
+ raw_header,
172
+ hex:: decode( "000000000000000000000000000000000000000000000000000000000000000000b2fc47904df5e355c6ab476d89fbc0733aeddbe302f0b94ba4eea9283f7e89e703170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c11131400" ) . unwrap( ) ,
173
+ ) ;
174
+
175
+ assert_eq ! (
176
+ parse_substrate_header( & raw_header) . unwrap( ) ,
177
+ Header {
178
+ hash: "afbbeb92bf6ff14f60bdef0aa89f043dd403659ae82665238810ace0d761f6d0"
179
+ . parse( )
180
+ . unwrap( ) ,
181
+ parent_hash: Default :: default ( ) ,
182
+ number: 0 ,
183
+ signal: None ,
184
+ } ,
185
+ ) ;
186
+ }
187
+
188
+ #[ test]
189
+ fn substrate_header_with_signal_parsed ( ) {
190
+ let authorities = vec ! [
191
+ ( AuthorityId :: from_slice( & [ 1 ; 32 ] ) , 101 ) ,
192
+ ( AuthorityId :: from_slice( & [ 3 ; 32 ] ) , 103 ) ,
193
+ ] ;
194
+ let mut digest = Digest :: default ( ) ;
195
+ digest. push ( DigestItem :: Consensus (
196
+ GRANDPA_ENGINE_ID ,
197
+ ConsensusLog :: ScheduledChange ( ScheduledChange {
198
+ next_authorities : authorities. clone ( ) ,
199
+ delay : 8 ,
200
+ } )
201
+ . encode ( ) ,
202
+ ) ) ;
203
+
204
+ let raw_header = RuntimeHeader {
205
+ parent_hash : "c0ac300d4005141ea690f3df593e049739c227316eb7f05052f3ee077388b68b"
206
+ . parse ( )
207
+ . unwrap ( ) ,
208
+ number : 8 ,
209
+ state_root : "822d6b412033aa9ac8e1722918eec5f25633529225754b3d4149982f5cacd4aa"
210
+ . parse ( )
211
+ . unwrap ( ) ,
212
+ extrinsics_root : "e7b07c0ce2799416ce7877b9cefc7f596bea5e8813bb2a0abf760414073ca928"
213
+ . parse ( )
214
+ . unwrap ( ) ,
215
+ digest,
216
+ }
217
+ . encode ( ) ;
218
+ assert_eq ! (
219
+ raw_header,
220
+ hex:: decode( "c0ac300d4005141ea690f3df593e049739c227316eb7f05052f3ee077388b68b20822d6b412033aa9ac8e1722918eec5f25633529225754b3d4149982f5cacd4aae7b07c0ce2799416ce7877b9cefc7f596bea5e8813bb2a0abf760414073ca928040446524e4b59010108010101010101010101010101010101010101010101010101010101010101010165000000000000000303030303030303030303030303030303030303030303030303030303030303670000000000000008000000" ) . unwrap( ) ,
221
+ ) ;
222
+
223
+ assert_eq ! (
224
+ parse_substrate_header( & raw_header) . unwrap( ) ,
225
+ Header {
226
+ hash: "3dfebb280bd87a4640f89d7f2adecd62b88148747bff5b63af6e1634ee37a56e"
227
+ . parse( )
228
+ . unwrap( ) ,
229
+ parent_hash: "c0ac300d4005141ea690f3df593e049739c227316eb7f05052f3ee077388b68b"
230
+ . parse( )
231
+ . unwrap( ) ,
232
+ number: 8 ,
233
+ signal: Some ( ValidatorsSetSignal {
234
+ delay: 8 ,
235
+ validators: authorities. encode( ) ,
236
+ } ) ,
237
+ } ,
238
+ ) ;
239
+ }
240
+
241
+ /// Number of the example block with justification.
242
+ const EXAMPLE_JUSTIFIED_BLOCK_NUMBER : u32 = 8 ;
243
+ /// Hash of the example block with justification.
244
+ const EXAMPLE_JUSTIFIED_BLOCK_HASH : & ' static str =
245
+ "a2f45892db86b2ad133ce57d81b7e4375bb7035ce9883e6b68c358164f343775" ;
246
+ /// Id of authorities set that have generated example justification. Could be computed by tracking
247
+ /// every set change in canonized headers.
248
+ const EXAMPLE_AUTHORITIES_SET_ID : u64 = 0 ;
249
+ /// Encoded authorities set that has generated example justification. Could be fetched from `ScheduledChange`
250
+ /// digest of the block that has scheduled this set OR by calling `GrandpaApi::grandpa_authorities()` at
251
+ /// appropriate block.
252
+ const EXAMPLE_AUTHORITIES_SET : & ' static str = "1488dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0ee0100000000000000d17c2d7823ebf260fd138f2d7e27d114c0145d968b5ff5006125f2414fadae690100000000000000439660b36c6c03afafca027b910b4fecf99801834c62a5e6006f27d978de234f01000000000000005e639b43e0052c47447dac87d6fd2b6ec50bdd4d0f614e4299c665249bbd09d901000000000000001dfe3e22cc0d45c70779c1095f7489a8ef3cf52d62fbd8c2fa38c9f1723502b50100000000000000" ;
253
+ /// Example justification. Could be fetched by calling 'chain_getBlock' RPC.
254
+ const EXAMPLE_JUSTIFICATION : & ' static str = "2600000000000000a2f45892db86b2ad133ce57d81b7e4375bb7035ce9883e6b68c358164f3437750800000010a2f45892db86b2ad133ce57d81b7e4375bb7035ce9883e6b68c358164f34377508000000d66b4ceb57ef8bcbc955071b597c8c5d2adcfdbb009c73f8438d342670fdeca9ac60686cbd58105b10f51d0a64a8e73b2e5829b2eab3248a008c472852130b00439660b36c6c03afafca027b910b4fecf99801834c62a5e6006f27d978de234fa2f45892db86b2ad133ce57d81b7e4375bb7035ce9883e6b68c358164f34377508000000f5730c14d3cd22b7661e2f5fcb3139dd5fef37f946314a441d01b40ce1200ef70d810525f23fd278b588cd67473c200bda83c338c407b479386aa83798e5970b5e639b43e0052c47447dac87d6fd2b6ec50bdd4d0f614e4299c665249bbd09d9a2f45892db86b2ad133ce57d81b7e4375bb7035ce9883e6b68c358164f34377508000000c78d6ec463f476461a695b4791d30e7626d16fdf72d7c252c2cad387495a97e8c2827ed4d5af853d6e05d31cb6fb7438c9481a7e9c6990d60a9bfaf6a6e1930988dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0eea2f45892db86b2ad133ce57d81b7e4375bb7035ce9883e6b68c358164f3437750800000052b4fc52d430286b3e2d650aa6e01b6ff4fae8b968893a62be789209eb97ee6e23780d3f5af7042d85bb48f1b202890b22724dfebce138826f66a5e00324320fd17c2d7823ebf260fd138f2d7e27d114c0145d968b5ff5006125f2414fadae6900" ;
255
+
256
+ #[ test]
257
+ fn substrate_header_parse_fails ( ) {
258
+ assert ! ( matches!( parse_substrate_header( & [ ] ) , Err ( _) ) ) ;
259
+ }
260
+
261
+ #[ test]
262
+ fn verify_substrate_finality_proof_succeeds ( ) {
263
+ verify_substrate_finality_proof (
264
+ EXAMPLE_JUSTIFIED_BLOCK_NUMBER ,
265
+ EXAMPLE_JUSTIFIED_BLOCK_HASH . parse ( ) . unwrap ( ) ,
266
+ EXAMPLE_AUTHORITIES_SET_ID ,
267
+ & hex:: decode ( EXAMPLE_AUTHORITIES_SET ) . unwrap ( ) ,
268
+ & hex:: decode ( EXAMPLE_JUSTIFICATION ) . unwrap ( ) ,
269
+ )
270
+ . unwrap ( ) ;
271
+ }
272
+
273
+ #[ test]
274
+ fn verify_substrate_finality_proof_fails_when_wrong_block_is_finalized ( ) {
275
+ verify_substrate_finality_proof (
276
+ 4 ,
277
+ Default :: default ( ) ,
278
+ EXAMPLE_AUTHORITIES_SET_ID ,
279
+ & hex:: decode ( EXAMPLE_AUTHORITIES_SET ) . unwrap ( ) ,
280
+ & hex:: decode ( EXAMPLE_JUSTIFICATION ) . unwrap ( ) ,
281
+ )
282
+ . unwrap_err ( ) ;
283
+ }
284
+
285
+ #[ test]
286
+ fn verify_substrate_finality_proof_fails_when_wrong_set_is_provided ( ) {
287
+ verify_substrate_finality_proof (
288
+ EXAMPLE_JUSTIFIED_BLOCK_NUMBER ,
289
+ EXAMPLE_JUSTIFIED_BLOCK_HASH . parse ( ) . unwrap ( ) ,
290
+ EXAMPLE_AUTHORITIES_SET_ID ,
291
+ & hex:: decode ( "deadbeef" ) . unwrap ( ) ,
292
+ & hex:: decode ( EXAMPLE_JUSTIFICATION ) . unwrap ( ) ,
293
+ )
294
+ . unwrap_err ( ) ;
295
+ }
296
+
297
+ #[ test]
298
+ fn verify_substrate_finality_proof_fails_when_wrong_set_id_is_provided ( ) {
299
+ verify_substrate_finality_proof (
300
+ EXAMPLE_JUSTIFIED_BLOCK_NUMBER ,
301
+ EXAMPLE_JUSTIFIED_BLOCK_HASH . parse ( ) . unwrap ( ) ,
302
+ 42 ,
303
+ & hex:: decode ( EXAMPLE_AUTHORITIES_SET ) . unwrap ( ) ,
304
+ & hex:: decode ( EXAMPLE_JUSTIFICATION ) . unwrap ( ) ,
305
+ )
306
+ . unwrap_err ( ) ;
307
+ }
308
+
309
+ #[ test]
310
+ fn verify_substrate_finality_proof_fails_when_wrong_proof_is_provided ( ) {
311
+ verify_substrate_finality_proof (
312
+ EXAMPLE_JUSTIFIED_BLOCK_NUMBER ,
313
+ EXAMPLE_JUSTIFIED_BLOCK_HASH . parse ( ) . unwrap ( ) ,
314
+ 0 ,
315
+ & hex:: decode ( EXAMPLE_AUTHORITIES_SET ) . unwrap ( ) ,
316
+ & hex:: decode ( "deadbeef" ) . unwrap ( ) ,
317
+ )
318
+ . unwrap_err ( ) ;
319
+ }
79
320
}
0 commit comments