@@ -5,11 +5,9 @@ use crate::{BlockHeaderData, BlockSourceError};
5
5
use bitcoin:: blockdata:: block:: { Block , BlockHeader } ;
6
6
use bitcoin:: consensus:: encode;
7
7
use bitcoin:: hash_types:: { BlockHash , TxMerkleNode , Txid } ;
8
- use bitcoin:: hashes:: hex:: { FromHex , ToHex } ;
8
+ use bitcoin:: hashes:: hex:: FromHex ;
9
9
use bitcoin:: Transaction ;
10
10
11
- use serde:: Deserialize ;
12
-
13
11
use serde_json;
14
12
15
13
use std:: convert:: From ;
@@ -46,7 +44,7 @@ impl TryInto<BlockHeaderData> for JsonResponse {
46
44
type Error = std:: io:: Error ;
47
45
48
46
fn try_into ( self ) -> std:: io:: Result < BlockHeaderData > {
49
- let mut header = match self . 0 {
47
+ let header = match self . 0 {
50
48
serde_json:: Value :: Array ( mut array) if !array. is_empty ( ) => array. drain ( ..) . next ( ) . unwrap ( ) ,
51
49
serde_json:: Value :: Object ( _) => self . 0 ,
52
50
_ => return Err ( std:: io:: Error :: new ( std:: io:: ErrorKind :: InvalidData , "unexpected JSON type" ) ) ,
@@ -57,51 +55,34 @@ impl TryInto<BlockHeaderData> for JsonResponse {
57
55
}
58
56
59
57
// Add an empty previousblockhash for the genesis block.
60
- if let None = header. get ( "previousblockhash" ) {
61
- let hash: BlockHash = BlockHash :: all_zeros ( ) ;
62
- header. as_object_mut ( ) . unwrap ( ) . insert ( "previousblockhash" . to_string ( ) , serde_json:: json!( hash. to_hex( ) ) ) ;
63
- }
64
-
65
- match serde_json:: from_value :: < GetHeaderResponse > ( header) {
66
- Err ( _) => Err ( std:: io:: Error :: new ( std:: io:: ErrorKind :: InvalidData , "invalid header response" ) ) ,
67
- Ok ( response) => match response. try_into ( ) {
68
- Err ( _) => Err ( std:: io:: Error :: new ( std:: io:: ErrorKind :: InvalidData , "invalid header data" ) ) ,
69
- Ok ( header) => Ok ( header) ,
70
- } ,
58
+ match header. try_into ( ) {
59
+ Err ( _) => Err ( std:: io:: Error :: new ( std:: io:: ErrorKind :: InvalidData , "invalid header data" ) ) ,
60
+ Ok ( header) => Ok ( header) ,
71
61
}
72
62
}
73
63
}
74
64
75
- /// Response data from `getblockheader` RPC and `headers` REST requests.
76
- #[ derive( Deserialize ) ]
77
- struct GetHeaderResponse {
78
- pub version : i32 ,
79
- pub merkleroot : String ,
80
- pub time : u32 ,
81
- pub nonce : u32 ,
82
- pub bits : String ,
83
- pub previousblockhash : String ,
84
-
85
- pub chainwork : String ,
86
- pub height : u32 ,
87
- }
65
+ impl TryFrom < serde_json:: Value > for BlockHeaderData {
66
+ type Error = ( ) ;
88
67
89
- /// Converts from `GetHeaderResponse` to `BlockHeaderData`.
90
- impl TryFrom < GetHeaderResponse > for BlockHeaderData {
91
- type Error = bitcoin:: hashes:: hex:: Error ;
68
+ fn try_from ( response : serde_json:: Value ) -> Result < Self , ( ) > {
69
+ macro_rules! get_field { ( $name: expr, $ty_access: tt) => {
70
+ response. get( $name) . ok_or( ( ) ) ?. $ty_access( ) . ok_or( ( ) ) ?
71
+ } }
92
72
93
- fn try_from ( response : GetHeaderResponse ) -> Result < Self , bitcoin:: hashes:: hex:: Error > {
94
73
Ok ( BlockHeaderData {
95
74
header : BlockHeader {
96
- version : response. version ,
97
- prev_blockhash : BlockHash :: from_hex ( & response. previousblockhash ) ?,
98
- merkle_root : TxMerkleNode :: from_hex ( & response. merkleroot ) ?,
99
- time : response. time ,
100
- bits : u32:: from_be_bytes ( <[ u8 ; 4 ] >:: from_hex ( & response. bits ) ?) ,
101
- nonce : response. nonce ,
75
+ version : get_field ! ( "version" , as_i64) . try_into ( ) . map_err ( |_| ( ) ) ?,
76
+ prev_blockhash : if let Some ( hash_str) = response. get ( "previousblockhash" ) {
77
+ BlockHash :: from_hex ( hash_str. as_str ( ) . ok_or ( ( ) ) ?) . map_err ( |_| ( ) ) ?
78
+ } else { BlockHash :: all_zeros ( ) } ,
79
+ merkle_root : TxMerkleNode :: from_hex ( get_field ! ( "merkleroot" , as_str) ) . map_err ( |_| ( ) ) ?,
80
+ time : get_field ! ( "time" , as_u64) . try_into ( ) . map_err ( |_| ( ) ) ?,
81
+ bits : u32:: from_be_bytes ( <[ u8 ; 4 ] >:: from_hex ( get_field ! ( "bits" , as_str) ) . map_err ( |_| ( ) ) ?) ,
82
+ nonce : get_field ! ( "nonce" , as_u64) . try_into ( ) . map_err ( |_| ( ) ) ?,
102
83
} ,
103
- chainwork : hex_to_uint256 ( & response . chainwork ) ?,
104
- height : response . height ,
84
+ chainwork : hex_to_uint256 ( get_field ! ( " chainwork" , as_str ) ) . map_err ( |_| ( ) ) ?,
85
+ height : get_field ! ( " height" , as_u64 ) . try_into ( ) . map_err ( |_| ( ) ) ? ,
105
86
} )
106
87
}
107
88
}
@@ -250,6 +231,7 @@ pub(crate) mod tests {
250
231
use super :: * ;
251
232
use bitcoin:: blockdata:: constants:: genesis_block;
252
233
use bitcoin:: hashes:: Hash ;
234
+ use bitcoin:: hashes:: hex:: ToHex ;
253
235
use bitcoin:: network:: constants:: Network ;
254
236
use serde_json:: value:: Number ;
255
237
use serde_json:: Value ;
@@ -308,7 +290,7 @@ pub(crate) mod tests {
308
290
match TryInto :: < BlockHeaderData > :: try_into ( response) {
309
291
Err ( e) => {
310
292
assert_eq ! ( e. kind( ) , std:: io:: ErrorKind :: InvalidData ) ;
311
- assert_eq ! ( e. get_ref( ) . unwrap( ) . to_string( ) , "invalid header response " ) ;
293
+ assert_eq ! ( e. get_ref( ) . unwrap( ) . to_string( ) , "invalid header data " ) ;
312
294
} ,
313
295
Ok ( _) => panic ! ( "Expected error" ) ,
314
296
}
0 commit comments