Fixes bug with incorrect conversion of JsonValue to Txid.
authorolegkubrakov <oleg@lightspark.com>
Fri, 15 Dec 2023 00:34:01 +0000 (16:34 -0800)
committerolegkubrakov <oleg@lightspark.com>
Fri, 15 Dec 2023 00:34:01 +0000 (16:34 -0800)
The bug happens when there is a call to a bitcoind that expects a transaction id as a response and
results in a corrupted Txid being returned.

lightning-block-sync/src/convert.rs

index 0f9ab8c43baadcc8cb72eec2375a063e9c4ffb37..62b0d6e47cbbd303e19fde760b57d22339423009 100644 (file)
@@ -162,25 +162,8 @@ impl TryInto<(BlockHash, Option<u32>)> for JsonResponse {
 impl TryInto<Txid> for JsonResponse {
        type Error = std::io::Error;
        fn try_into(self) -> std::io::Result<Txid> {
-               match self.0.as_str() {
-                       None => Err(std::io::Error::new(
-                               std::io::ErrorKind::InvalidData,
-                               "expected JSON string",
-                       )),
-                       Some(hex_data) => match Vec::<u8>::from_hex(hex_data) {
-                               Err(_) => Err(std::io::Error::new(
-                                       std::io::ErrorKind::InvalidData,
-                                       "invalid hex data",
-                               )),
-                               Ok(txid_data) => match encode::deserialize(&txid_data) {
-                                       Err(_) => Err(std::io::Error::new(
-                                               std::io::ErrorKind::InvalidData,
-                                               "invalid txid",
-                                       )),
-                                       Ok(txid) => Ok(txid),
-                               },
-                       },
-               }
+               let hex_data = self.0.as_str().ok_or(Self::Error::new(std::io::ErrorKind::InvalidData, "expected JSON string" ))?;
+               Txid::from_str(hex_data).map_err(|err|Self::Error::new(std::io::ErrorKind::InvalidData, err.to_string() ))
        }
 }
 
@@ -622,7 +605,7 @@ pub(crate) mod tests {
                match TryInto::<Txid>::try_into(response) {
                        Err(e) => {
                                assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
-                               assert_eq!(e.get_ref().unwrap().to_string(), "invalid hex data");
+                               assert_eq!(e.get_ref().unwrap().to_string(), "bad hex string length 6 (expected 64)");
                        }
                        Ok(_) => panic!("Expected error"),
                }
@@ -634,7 +617,7 @@ pub(crate) mod tests {
                match TryInto::<Txid>::try_into(response) {
                        Err(e) => {
                                assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
-                               assert_eq!(e.get_ref().unwrap().to_string(), "invalid txid");
+                               assert_eq!(e.get_ref().unwrap().to_string(), "bad hex string length 4 (expected 64)");
                        }
                        Ok(_) => panic!("Expected error"),
                }
@@ -650,6 +633,20 @@ pub(crate) mod tests {
                }
        }
 
+       #[test]
+       fn into_txid_from_bitcoind_rpc_json_response() {
+               let mut rpc_response = serde_json::json!(
+            {"error": "", "id": "770", "result": "7934f775149929a8b742487129a7c3a535dfb612f0b726cc67bc10bc2628f906"}
+
+        );
+        let r: std::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
        // the hex encoded transaction (e.g. as a result of getrawtransaction) or as a JSON object
        // where the hex encoded transaction can be found in the hex field of the object (if present)