zero 2 лет назад
Родитель
Сommit
564089646d

+ 2 - 6
bin/darkfid/src/rpc_blockchain.rs

@@ -18,7 +18,7 @@
 
 use std::{collections::HashMap, str::FromStr};
 
-use darkfi_sdk::crypto::ContractId;
+use darkfi_sdk::{crypto::ContractId, tx::TransactionHash};
 use darkfi_serial::{deserialize_async, serialize_async};
 use log::{debug, error};
 use tinyjson::JsonValue;
@@ -95,10 +95,7 @@ impl Darkfid {
         }
 
         let tx_hash = params[0].get::<String>().unwrap();
-        return JsonError::new(InvalidParams, None, id).into()
-        /*
-        // I'm fixing this rn (see next commit)
-        let tx_hash = match blake3::Hash::from_hex(tx_hash) {
+        let tx_hash = match TransactionHash::from_str(tx_hash) {
             Ok(v) => v,
             Err(_) => return JsonError::new(ParseError, None, id).into(),
         };
@@ -117,7 +114,6 @@ impl Darkfid {
 
         let tx_enc = base64::encode(&serialize_async(tx).await);
         JsonResponse::new(JsonValue::String(tx_enc), id).into()
-        */
     }
 
     // RPCAPI:

+ 2 - 1
src/net/session/refine_session.rs

@@ -251,7 +251,8 @@ impl GreylistRefinery {
 
                     // Freeze the greylist in this state. Necessary since the greylist
                     // can be modified by `hosts::move_host()`.
-                    let mut greylist = hosts.container.hostlists[HostColor::Grey as usize].write().await;
+                    let mut greylist =
+                        hosts.container.hostlists[HostColor::Grey as usize].write().await;
 
                     if !self.session().handshake_node(url.clone(), self.p2p().clone()).await {
                         greylist.remove(position);

+ 3 - 7
src/sdk/src/crypto/util.rs

@@ -27,7 +27,7 @@ use subtle::CtOption;
 
 use crate::{
     error::{ContractError, GenericResult},
-    hex_from_iter,
+    hex::{decode_hex_arr, hex_from_iter},
 };
 
 #[inline]
@@ -104,12 +104,8 @@ pub trait FieldElemAsStr: PrimeField<Repr = [u8; 32]> {
 
         let hex = hex.strip_prefix("0x").ok_or(ContractError::HexFmtErr)?;
 
-        let mut bytes = [0u8; 32];
-        for i in 0..32 {
-            // Bytes are little endian but str repr is big endian
-            bytes[32 - i - 1] = u8::from_str_radix(&hex[2 * i..2 * i + 2], 16)
-                .map_err(|_| ContractError::HexFmtErr)?;
-        }
+        let mut bytes = decode_hex_arr(hex)?;
+        bytes.reverse();
 
         let value = Self::from_repr(bytes);
         if value.is_some().into() {

+ 97 - 0
src/sdk/src/hex.rs

@@ -0,0 +1,97 @@
+/* This file is part of DarkFi (https://dark.fi)
+ *
+ * Copyright (C) 2020-2024 Dyne.org foundation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+use crate::{ContractError, GenericResult};
+
+/// Creates a hex formatted string of the data
+#[inline]
+pub fn hex_from_iter<I: Iterator<Item = u8>>(iter: I) -> String {
+    let mut repr = String::new();
+    for b in iter {
+        repr += &format!("{:02x}", b);
+    }
+    repr
+}
+
+/// Decode hex string into bytes
+pub fn decode_hex(hex: &str) -> HexDecodeIter {
+    HexDecodeIter { hex, curr: 0 }
+}
+
+pub struct HexDecodeIter<'a> {
+    hex: &'a str,
+    curr: usize,
+}
+
+impl<'a> Iterator for HexDecodeIter<'a> {
+    type Item = GenericResult<u8>;
+
+    // FromIterator auto converts [Result<u8>, ...] into Result<[u8, ...]>
+    // https://stackoverflow.com/a/26370894
+    fn next(&mut self) -> Option<Self::Item> {
+        // Stop iteration
+        if self.curr == self.hex.len() {
+            return None
+        }
+
+        // End of next 2 chars is past the end of the hex string
+        if self.curr + 2 > self.hex.len() {
+            return Some(Err(ContractError::HexFmtErr))
+        }
+
+        // Decode the next 2 chars
+        let Ok(byte) = u8::from_str_radix(&self.hex[self.curr..self.curr + 2], 16) else {
+            return Some(Err(ContractError::HexFmtErr))
+        };
+
+        self.curr += 2;
+
+        Some(Ok(byte))
+    }
+}
+
+pub fn decode_hex_arr<const N: usize>(hex: &str) -> GenericResult<[u8; N]> {
+    let decoded = decode_hex(hex).collect::<GenericResult<Vec<_>>>()?;
+    let bytes: [u8; N] = decoded.try_into().map_err(|_| ContractError::HexFmtErr)?;
+    Ok(bytes)
+}
+
+pub trait AsHex {
+    fn hex(&self) -> String;
+}
+
+impl<T: AsRef<[u8]>> AsHex for T {
+    /// Creates a hex formatted string of the data (big endian)
+    fn hex(&self) -> String {
+        hex_from_iter(self.as_ref().iter().cloned())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_hex_encode_decode() {
+        let decoded = decode_hex("0a00").collect::<GenericResult<Vec<_>>>().unwrap();
+        assert_eq!(decoded, vec![10, 0]);
+        assert!(decode_hex("0x").collect::<GenericResult<Vec<_>>>().is_err());
+        assert!(decode_hex("0a1").collect::<GenericResult<Vec<_>>>().is_err());
+        assert_eq!(hex_from_iter([10u8, 0].into_iter()), "0a00");
+    }
+}

+ 5 - 43
src/sdk/src/lib.rs

@@ -35,6 +35,11 @@ pub mod entrypoint;
 
 /// Error handling
 pub mod error;
+pub use error::{ContractError, GenericResult};
+
+/// Hex encoding/decoding from bytes
+pub mod hex;
+pub use hex::AsHex;
 
 /// Logging infrastructure
 pub mod log;
@@ -54,46 +59,3 @@ pub mod util;
 
 /// DarkTree structures
 pub mod dark_tree;
-
-/// Creates a hex formatted string of the data
-#[inline]
-pub fn hex_from_iter<I: Iterator<Item = u8>>(iter: I) -> String {
-    let mut repr = String::new();
-    for b in iter {
-        repr += &format!("{:02x}", b);
-    }
-    repr
-}
-
-/*
-/// Decode hex string into bytes
-pub fn decode_hex(hex: &str) -> Iterator<Item = u8> {
-    HexDecodeIter {
-        hex,
-        curr: 0
-    }
-}
-
-struct HexDecodeIter<'a> {
-    hex: &'a str,
-    curr: usize,
-}
-
-impl<'a> Iterator for HexDecodeIter<'a> {
-    type Item = u8;
-
-    fn next(&mut self) -> Option<Self::Item> {
-    }
-}
-*/
-
-pub trait AsHex {
-    fn hex(&self) -> String;
-}
-
-impl<T: AsRef<[u8]>> AsHex for T {
-    /// Creates a hex formatted string of the data (big endian)
-    fn hex(&self) -> String {
-        hex_from_iter(self.as_ref().iter().cloned())
-    }
-}

+ 17 - 2
src/sdk/src/tx.rs

@@ -16,13 +16,20 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-use std::fmt::{self, Debug};
+use std::{
+    fmt::{self, Debug},
+    str::FromStr,
+};
 
 #[cfg(feature = "async")]
 use darkfi_serial::async_trait;
 use darkfi_serial::{SerialDecodable, SerialEncodable};
 
-use super::{crypto::ContractId, AsHex};
+use super::{
+    crypto::ContractId,
+    hex::{decode_hex_arr, AsHex},
+    ContractError, GenericResult,
+};
 
 #[derive(Clone, Debug, Eq, Hash, PartialEq, SerialEncodable, SerialDecodable)]
 // We have to introduce a type rather than using an alias so we can implement Display
@@ -43,6 +50,14 @@ impl TransactionHash {
     }
 }
 
+impl FromStr for TransactionHash {
+    type Err = ContractError;
+
+    fn from_str(tx_hash_str: &str) -> GenericResult<Self> {
+        Ok(Self(decode_hex_arr(tx_hash_str)?))
+    }
+}
+
 impl fmt::Display for TransactionHash {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "{}", self.0.hex())