use serde_json;
+use bitcoin::hashes::Hash;
use std::convert::From;
use std::convert::TryFrom;
use std::convert::TryInto;
use std::io;
use std::str::FromStr;
-use bitcoin::hashes::Hash;
impl TryInto<serde_json::Value> for JsonResponse {
type Error = io::Error;
- fn try_into(self) -> Result<serde_json::Value, io::Error> { Ok(self.0) }
+ fn try_into(self) -> Result<serde_json::Value, io::Error> {
+ Ok(self.0)
+ }
}
/// Conversion from `io::Error` into `BlockSourceError`.
type Error = io::Error;
fn try_into(self) -> io::Result<BlockHash> {
- BlockHash::from_slice(&self.0).map_err(|_|
- io::Error::new(io::ErrorKind::InvalidData, "bad block hash length")
- )
+ BlockHash::from_slice(&self.0)
+ .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "bad block hash length"))
}
}
fn try_into(self) -> io::Result<BlockHeaderData> {
let header = match self.0 {
- serde_json::Value::Array(mut array) if !array.is_empty() => array.drain(..).next().unwrap(),
+ serde_json::Value::Array(mut array) if !array.is_empty() => {
+ array.drain(..).next().unwrap()
+ },
serde_json::Value::Object(_) => self.0,
_ => return Err(io::Error::new(io::ErrorKind::InvalidData, "unexpected JSON type")),
};
type Error = ();
fn try_from(response: serde_json::Value) -> Result<Self, ()> {
- macro_rules! get_field { ($name: expr, $ty_access: tt) => {
- response.get($name).ok_or(())?.$ty_access().ok_or(())?
- } }
+ macro_rules! get_field {
+ ($name: expr, $ty_access: tt) => {
+ response.get($name).ok_or(())?.$ty_access().ok_or(())?
+ };
+ }
Ok(BlockHeaderData {
header: Header {
version: bitcoin::blockdata::block::Version::from_consensus(
- get_field!("version", as_i64).try_into().map_err(|_| ())?
+ get_field!("version", as_i64).try_into().map_err(|_| ())?,
),
prev_blockhash: if let Some(hash_str) = response.get("previousblockhash") {
- BlockHash::from_str(hash_str.as_str().ok_or(())?).map_err(|_| ())?
- } else { BlockHash::all_zeros() },
- merkle_root: TxMerkleNode::from_str(get_field!("merkleroot", as_str)).map_err(|_| ())?,
+ BlockHash::from_str(hash_str.as_str().ok_or(())?).map_err(|_| ())?
+ } else {
+ BlockHash::all_zeros()
+ },
+ merkle_root: TxMerkleNode::from_str(get_field!("merkleroot", as_str))
+ .map_err(|_| ())?,
time: get_field!("time", as_u64).try_into().map_err(|_| ())?,
- bits: bitcoin::CompactTarget::from_consensus(
- u32::from_be_bytes(<[u8; 4]>::from_hex(get_field!("bits", as_str)).map_err(|_| ())?)
- ),
+ bits: bitcoin::CompactTarget::from_consensus(u32::from_be_bytes(
+ <[u8; 4]>::from_hex(get_field!("bits", as_str)).map_err(|_| ())?,
+ )),
nonce: get_field!("nonce", as_u64).try_into().map_err(|_| ())?,
},
chainwork: hex_to_work(get_field!("chainwork", as_str)).map_err(|_| ())?,
let hash = match &self.0["bestblockhash"] {
serde_json::Value::String(hex_data) => match BlockHash::from_str(&hex_data) {
- Err(_) => return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid hex data")),
+ Err(_) => {
+ return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid hex data"))
+ },
Ok(block_hash) => block_hash,
},
_ => return Err(io::Error::new(io::ErrorKind::InvalidData, "expected JSON string")),
serde_json::Value::Number(height) => match height.as_u64() {
None => return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid height")),
Some(height) => match height.try_into() {
- Err(_) => return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid height")),
+ Err(_) => {
+ return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid height"))
+ },
Ok(height) => Some(height),
- }
+ },
},
_ => return Err(io::Error::new(io::ErrorKind::InvalidData, "expected JSON number")),
};
impl TryInto<Txid> for JsonResponse {
type Error = io::Error;
fn try_into(self) -> io::Result<Txid> {
- let hex_data = self.0.as_str().ok_or(io::Error::new(io::ErrorKind::InvalidData, "expected JSON string" ))?;
- Txid::from_str(hex_data).map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err.to_string() ))
+ let hex_data = self
+ .0
+ .as_str()
+ .ok_or(io::Error::new(io::ErrorKind::InvalidData, "expected JSON string"))?;
+ Txid::from_str(hex_data)
+ .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err.to_string()))
}
}
} else {
hex_data
}
- }
+ },
// result is a complete transaction (e.g. getrawtranaction verbose)
_ => hex_data,
},
_ => {
- return Err(io::Error::new(
- io::ErrorKind::InvalidData,
- "expected JSON string",
- ));
- }
+ return Err(io::Error::new(io::ErrorKind::InvalidData, "expected JSON string"));
+ },
}
} else {
// result is plain text (e.g. getrawtransaction no verbose)
match self.0.as_str() {
Some(hex_tx) => hex_tx,
None => {
- return Err(io::Error::new(
- io::ErrorKind::InvalidData,
- "expected JSON string",
- ));
- }
+ return Err(io::Error::new(io::ErrorKind::InvalidData, "expected JSON string"));
+ },
}
};
match Vec::<u8>::from_hex(hex_tx) {
- Err(_) => {
- Err(io::Error::new(
- io::ErrorKind::InvalidData,
- "invalid hex data",
- ))
- }
+ Err(_) => Err(io::Error::new(io::ErrorKind::InvalidData, "invalid hex data")),
Ok(tx_data) => match encode::deserialize(&tx_data) {
- Err(_) => {
- Err(io::Error::new(
- io::ErrorKind::InvalidData,
- "invalid transaction",
- ))
- }
+ Err(_) => Err(io::Error::new(io::ErrorKind::InvalidData, "invalid transaction")),
Ok(tx) => Ok(tx),
},
}
fn try_into(self) -> io::Result<BlockHash> {
match self.0.as_str() {
None => Err(io::Error::new(io::ErrorKind::InvalidData, "expected JSON string")),
- Some(hex_data) if hex_data.len() != 64 =>
- Err(io::Error::new(io::ErrorKind::InvalidData, "invalid hash length")),
+ Some(hex_data) if hex_data.len() != 64 => {
+ Err(io::Error::new(io::ErrorKind::InvalidData, "invalid hash length"))
+ },
Some(hex_data) => BlockHash::from_str(hex_data)
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "invalid hex data")),
}
/// that.
#[cfg(feature = "rest-client")]
pub(crate) struct GetUtxosResponse {
- pub(crate) hit_bitmap_nonempty: bool
+ pub(crate) hit_bitmap_nonempty: bool,
}
#[cfg(feature = "rest-client")]
let obj_err = || io::Error::new(io::ErrorKind::InvalidData, "expected an object");
let bitmap_err = || io::Error::new(io::ErrorKind::InvalidData, "missing bitmap field");
let bitstr_err = || io::Error::new(io::ErrorKind::InvalidData, "bitmap should be an str");
- let bitmap_str =
- self.0.as_object().ok_or_else(obj_err)?
- .get("bitmap").ok_or_else(bitmap_err)?
- .as_str().ok_or_else(bitstr_err)?;
- let mut hit_bitmap_nonempty = false;
- for c in bitmap_str.chars() {
- if c < '0' || c > '9' {
- return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid byte"));
- }
- if c > '0' { hit_bitmap_nonempty = true; }
+ let bitmap_str = self
+ .0
+ .as_object()
+ .ok_or_else(obj_err)?
+ .get("bitmap")
+ .ok_or_else(bitmap_err)?
+ .as_str()
+ .ok_or_else(bitstr_err)?;
+ let mut hit_bitmap_nonempty = false;
+ for c in bitmap_str.chars() {
+ if c < '0' || c > '9' {
+ return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid byte"));
}
- Ok(GetUtxosResponse { hit_bitmap_nonempty })
+ if c > '0' {
+ hit_bitmap_nonempty = true;
+ }
+ }
+ Ok(GetUtxosResponse { hit_bitmap_nonempty })
}
}
#[test]
fn into_block_header_from_json_response_with_invalid_header_response() {
let block = genesis_block(Network::Bitcoin);
- let mut response = JsonResponse(BlockHeaderData {
- chainwork: block.header.work(),
- height: 0,
- header: block.header
- }.into());
+ let mut response = JsonResponse(
+ BlockHeaderData { chainwork: block.header.work(), height: 0, header: block.header }
+ .into(),
+ );
response.0["chainwork"].take();
match TryInto::<BlockHeaderData>::try_into(response) {
#[test]
fn into_block_header_from_json_response_with_invalid_header_data() {
let block = genesis_block(Network::Bitcoin);
- let mut response = JsonResponse(BlockHeaderData {
- chainwork: block.header.work(),
- height: 0,
- header: block.header
- }.into());
+ let mut response = JsonResponse(
+ BlockHeaderData { chainwork: block.header.work(), height: 0, header: block.header }
+ .into(),
+ );
response.0["chainwork"] = serde_json::json!("foobar");
match TryInto::<BlockHeaderData>::try_into(response) {
#[test]
fn into_block_header_from_json_response_with_valid_header() {
let block = genesis_block(Network::Bitcoin);
- let response = JsonResponse(BlockHeaderData {
- chainwork: block.header.work(),
- height: 0,
- header: block.header
- }.into());
+ let response = JsonResponse(
+ BlockHeaderData { chainwork: block.header.work(), height: 0, header: block.header }
+ .into(),
+ );
match TryInto::<BlockHeaderData>::try_into(response) {
Err(e) => panic!("Unexpected error: {:?}", e),
#[test]
fn into_block_header_from_json_response_with_valid_header_array() {
let genesis_block = genesis_block(Network::Bitcoin);
- let best_block_header = Header {
- prev_blockhash: genesis_block.block_hash(),
- ..genesis_block.header
- };
+ let best_block_header =
+ Header { prev_blockhash: genesis_block.block_hash(), ..genesis_block.header };
let chainwork = genesis_block.header.work() + best_block_header.work();
let response = JsonResponse(serde_json::json!([
- serde_json::Value::from(BlockHeaderData {
- chainwork, height: 1, header: best_block_header,
- }),
- serde_json::Value::from(BlockHeaderData {
- chainwork: genesis_block.header.work(), height: 0, header: genesis_block.header,
- }),
+ serde_json::Value::from(BlockHeaderData {
+ chainwork,
+ height: 1,
+ header: best_block_header,
+ }),
+ serde_json::Value::from(BlockHeaderData {
+ chainwork: genesis_block.header.work(),
+ height: 0,
+ header: genesis_block.header,
+ }),
]));
match TryInto::<BlockHeaderData>::try_into(response) {
#[test]
fn into_block_header_from_json_response_without_previous_block_hash() {
let block = genesis_block(Network::Bitcoin);
- let mut response = JsonResponse(BlockHeaderData {
- chainwork: block.header.work(),
- height: 0,
- header: block.header
- }.into());
+ let mut response = JsonResponse(
+ BlockHeaderData { chainwork: block.header.work(), height: 0, header: block.header }
+ .into(),
+ );
response.0.as_object_mut().unwrap().remove("previousblockhash");
match TryInto::<BlockHeaderData>::try_into(response) {
Err(e) => {
assert_eq!(e.kind(), io::ErrorKind::InvalidData);
assert_eq!(e.get_ref().unwrap().to_string(), "expected JSON string");
- }
+ },
Ok(_) => panic!("Expected error"),
}
}
match TryInto::<Txid>::try_into(response) {
Err(e) => {
assert_eq!(e.kind(), io::ErrorKind::InvalidData);
- assert_eq!(e.get_ref().unwrap().to_string(), "bad hex string length 6 (expected 64)");
- }
+ assert_eq!(
+ e.get_ref().unwrap().to_string(),
+ "bad hex string length 6 (expected 64)"
+ );
+ },
Ok(_) => panic!("Expected error"),
}
}
match TryInto::<Txid>::try_into(response) {
Err(e) => {
assert_eq!(e.kind(), io::ErrorKind::InvalidData);
- assert_eq!(e.get_ref().unwrap().to_string(), "bad hex string length 4 (expected 64)");
- }
+ assert_eq!(
+ e.get_ref().unwrap().to_string(),
+ "bad hex string length 4 (expected 64)"
+ );
+ },
Ok(_) => panic!("Expected error"),
}
}
#[test]
fn into_txid_from_bitcoind_rpc_json_response() {
let mut rpc_response = serde_json::json!(
- {"error": "", "id": "770", "result": "7934f775149929a8b742487129a7c3a535dfb612f0b726cc67bc10bc2628f906"}
+ {"error": "", "id": "770", "result": "7934f775149929a8b742487129a7c3a535dfb612f0b726cc67bc10bc2628f906"}
- );
- let r: io::Result<Txid> = JsonResponse(rpc_response.get_mut("result").unwrap().take())
- .try_into();
- assert_eq!(
- r.unwrap().to_string(),
- "7934f775149929a8b742487129a7c3a535dfb612f0b726cc67bc10bc2628f906"
- );
+ );
+ let r: io::Result<Txid> =
+ JsonResponse(rpc_response.get_mut("result").unwrap().take()).try_into();
+ assert_eq!(
+ r.unwrap().to_string(),
+ "7934f775149929a8b742487129a7c3a535dfb612f0b726cc67bc10bc2628f906"
+ );
}
// TryInto<Transaction> can be used in two ways, first with plain hex response where data is
Err(e) => {
assert_eq!(e.kind(), io::ErrorKind::InvalidData);
assert_eq!(e.get_ref().unwrap().to_string(), "invalid hex data");
- }
+ },
Ok(_) => panic!("Expected error"),
}
}
Err(e) => {
assert_eq!(e.kind(), io::ErrorKind::InvalidData);
assert_eq!(e.get_ref().unwrap().to_string(), "expected JSON string");
- }
+ },
Ok(_) => panic!("Expected error"),
}
}
Err(e) => {
assert_eq!(e.kind(), io::ErrorKind::InvalidData);
assert_eq!(e.get_ref().unwrap().to_string(), "invalid transaction");
- }
+ },
Ok(_) => panic!("Expected error"),
}
}
fn into_tx_from_json_response_with_valid_tx_data_hex_field() {
let genesis_block = genesis_block(Network::Bitcoin);
let target_tx = genesis_block.txdata.get(0).unwrap();
- let response = JsonResponse(serde_json::json!({"hex": encode::serialize_hex(&target_tx)}));
+ let response =
+ JsonResponse(serde_json::json!({ "hex": encode::serialize_hex(&target_tx) }));
match TryInto::<Transaction>::try_into(response) {
Err(e) => panic!("Unexpected error: {:?}", e),
Ok(tx) => assert_eq!(&tx, target_tx),
match TryInto::<Transaction>::try_into(response) {
Err(e) => {
assert_eq!(e.kind(), io::ErrorKind::InvalidData);
- assert_eq!(
- e.get_ref().unwrap().to_string(),
- "expected JSON string"
- );
- }
+ assert_eq!(e.get_ref().unwrap().to_string(), "expected JSON string");
+ },
Ok(_) => panic!("Expected error"),
}
}
match TryInto::<Transaction>::try_into(response) {
Err(e) => {
assert_eq!(e.kind(), io::ErrorKind::InvalidData);
- assert!(
- e.get_ref().unwrap().to_string().contains(
- "transaction couldn't be signed")
- );
- }
+ assert!(e
+ .get_ref()
+ .unwrap()
+ .to_string()
+ .contains("transaction couldn't be signed"));
+ },
Ok(_) => panic!("Expected error"),
}
}