X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning-block-sync%2Fsrc%2Fconvert.rs;h=bf9e9577619a3fd0a1a7fecc3d79cd070bd706e1;hb=d795e247b76f6b0d70a2529c2a05995a909b1134;hp=d6294e1d2a79518c05a674cae5ea86d41fc1faf7;hpb=a5ecb851716bc0819586894232653ec4b5e2c67f;p=rust-lightning diff --git a/lightning-block-sync/src/convert.rs b/lightning-block-sync/src/convert.rs index d6294e1d..bf9e9577 100644 --- a/lightning-block-sync/src/convert.rs +++ b/lightning-block-sync/src/convert.rs @@ -13,8 +13,14 @@ use serde_json; use std::convert::From; use std::convert::TryFrom; use std::convert::TryInto; +use std::str::FromStr; use bitcoin::hashes::Hash; +impl TryInto for JsonResponse { + type Error = std::io::Error; + fn try_into(self) -> Result { Ok(self.0) } +} + /// Conversion from `std::io::Error` into `BlockSourceError`. impl From for BlockSourceError { fn from(e: std::io::Error) -> BlockSourceError { @@ -38,6 +44,17 @@ impl TryInto for BinaryResponse { } } +/// Parses binary data as a block hash. +impl TryInto for BinaryResponse { + type Error = std::io::Error; + + fn try_into(self) -> std::io::Result { + BlockHash::from_slice(&self.0).map_err(|_| + std::io::Error::new(std::io::ErrorKind::InvalidData, "bad block hash length") + ) + } +} + /// Converts a JSON value into block header data. The JSON value may be an object representing a /// block header or an array of such objects. In the latter case, the first object is converted. impl TryInto for JsonResponse { @@ -226,6 +243,46 @@ impl TryInto for JsonResponse { } } +impl TryInto for JsonResponse { + type Error = std::io::Error; + + fn try_into(self) -> std::io::Result { + match self.0.as_str() { + None => Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "expected JSON string")), + Some(hex_data) if hex_data.len() != 64 => + Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid hash length")), + Some(hex_data) => BlockHash::from_str(hex_data) + .map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid hex data")), + } + } +} + +/// The REST `getutxos` endpoint retuns a whole pile of data we don't care about and one bit we do +/// - whether the `hit bitmap` field had any entries. Thus we condense the result down into only +/// that. +pub(crate) struct GetUtxosResponse { + pub(crate) hit_bitmap_nonempty: bool +} + +impl TryInto for JsonResponse { + type Error = std::io::Error; + + fn try_into(self) -> std::io::Result { + let bitmap_str = + self.0.as_object().ok_or(std::io::Error::new(std::io::ErrorKind::InvalidData, "expected an object"))? + .get("bitmap").ok_or(std::io::Error::new(std::io::ErrorKind::InvalidData, "missing bitmap field"))? + .as_str().ok_or(std::io::Error::new(std::io::ErrorKind::InvalidData, "bitmap should be an str"))?; + let mut hit_bitmap_nonempty = false; + for c in bitmap_str.chars() { + if c < '0' || c > '9' { + return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid byte")); + } + if c > '0' { hit_bitmap_nonempty = true; } + } + Ok(GetUtxosResponse { hit_bitmap_nonempty }) + } +} + #[cfg(test)] pub(crate) mod tests { use super::*;