From 88b646c5a3c65e1dce2e65d1a84554afc14b4d7a Mon Sep 17 00:00:00 2001
From: Boog900 <54e72d8a-345f-4599-bd90-c6b9bc7d0ec5@aleeas.com>
Date: Thu, 5 Oct 2023 14:24:42 +0100
Subject: [PATCH] add back monero-epee-bin-serde I am now a maintainer of
 monero-rs, so I can keep this maintained and not using serde was annoying.

---
 consensus/src/verifier.rs                     | 112 ++++++++++++++++++
 net/monero-wire/Cargo.toml                    |   2 +
 net/monero-wire/src/messages/common.rs        |   4 +-
 .../src/messages/common/serde_helpers.rs      | 106 +++++++++++++++++
 4 files changed, 223 insertions(+), 1 deletion(-)
 create mode 100644 consensus/src/verifier.rs
 create mode 100644 net/monero-wire/src/messages/common/serde_helpers.rs

diff --git a/consensus/src/verifier.rs b/consensus/src/verifier.rs
new file mode 100644
index 00000000..f96d1b3f
--- /dev/null
+++ b/consensus/src/verifier.rs
@@ -0,0 +1,112 @@
+use futures::join;
+use monero_serai::{block::Block, transaction::Transaction};
+use tower::ServiceExt;
+use tracing::instrument;
+
+use crate::{
+    block::{pow::difficulty::DifficultyCache, weight::BlockWeightsCache},
+    hardforks::{HardForkConfig, HardForkState},
+    ConsensusError, Database, DatabaseRequest, DatabaseResponse,
+};
+
+pub struct Config {
+    hard_fork_cfg: HardForkConfig,
+}
+
+impl Config {
+    pub fn main_net() -> Config {
+        Config {
+            hard_fork_cfg: HardForkConfig::main_net(),
+        }
+    }
+}
+
+#[derive(Clone)]
+struct State {
+    block_weight: BlockWeightsCache,
+    difficulty: DifficultyCache,
+    hard_fork: HardForkState,
+    chain_height: u64,
+    top_hash: [u8; 32],
+}
+
+impl State {
+    pub async fn init<D: Database + Clone>(
+        config: Config,
+        mut database: D,
+    ) -> Result<State, ConsensusError> {
+        let DatabaseResponse::ChainHeight(chain_height) = database
+            .ready()
+            .await?
+            .call(DatabaseRequest::ChainHeight)
+            .await?
+        else {
+            panic!("Database sent incorrect response")
+        };
+
+        Self::init_at_chain_height(config, chain_height, database).await
+    }
+
+    #[instrument(name = "init_state", skip_all)]
+    pub async fn init_at_chain_height<D: Database + Clone>(
+        config: Config,
+        chain_height: u64,
+        mut database: D,
+    ) -> Result<State, ConsensusError> {
+        let DatabaseResponse::BlockHash(top_hash) = database
+            .ready()
+            .await?
+            .call(DatabaseRequest::BlockHash(chain_height - 1))
+            .await?
+        else {
+            panic!("Database sent incorrect response")
+        };
+
+        let (block_weight, difficulty, hard_fork) = join!(
+            BlockWeightsCache::init_from_chain_height(chain_height, database.clone()),
+            DifficultyCache::init_from_chain_height(chain_height, database.clone()),
+            HardForkState::init_from_chain_height(config.hard_fork_cfg, chain_height, database)
+        );
+
+        Ok(State {
+            block_weight: block_weight?,
+            difficulty: difficulty?,
+            hard_fork: hard_fork?,
+            chain_height,
+            top_hash,
+        })
+    }
+}
+
+pub struct Verifier {
+    state: State,
+}
+
+impl Verifier {
+    pub async fn init<D: Database + Clone>(
+        config: Config,
+        mut database: D,
+    ) -> Result<Verifier, ConsensusError> {
+        let DatabaseResponse::ChainHeight(chain_height) = database
+            .ready()
+            .await?
+            .call(DatabaseRequest::ChainHeight)
+            .await?
+        else {
+            panic!("Database sent incorrect response")
+        };
+
+        Self::init_at_chain_height(config, chain_height, database).await
+    }
+
+    #[instrument(name = "init_verifier", skip_all)]
+    pub async fn init_at_chain_height<D: Database + Clone>(
+        config: Config,
+        chain_height: u64,
+        database: D,
+    ) -> Result<Verifier, ConsensusError> {
+        Ok(Verifier {
+            state: State::init_at_chain_height(config, chain_height, database).await?,
+        })
+    }
+}
diff --git a/net/monero-wire/Cargo.toml b/net/monero-wire/Cargo.toml
index 3d3aee5c..cf927503 100644
--- a/net/monero-wire/Cargo.toml
+++ b/net/monero-wire/Cargo.toml
@@ -10,6 +10,8 @@ repository = "https://github.com/SyntheticBird45/cuprate/tree/main/net/monero-wi
 [dependencies]
 levin-cuprate = {path="../levin"}
 epee-encoding = { git = "https://github.com/boog900/epee-encoding"}
+monero-epee-bin-serde = {git = "https://github.com/monero-rs/monero-epee-bin-serde.git"}
+serde = {version = "1", features = ["derive"]}
 
 [dev-dependencies]
 hex = "0.4.3"
diff --git a/net/monero-wire/src/messages/common.rs b/net/monero-wire/src/messages/common.rs
index 1775091a..5228fb73 100644
--- a/net/monero-wire/src/messages/common.rs
+++ b/net/monero-wire/src/messages/common.rs
@@ -16,10 +16,12 @@
 //! Common types that are used across multiple messages.
 //
 use epee_encoding::EpeeObject;
+use serde::{Deserialize, Serialize};
 
 use crate::NetworkAddress;
 
 mod builders;
+mod serde_helpers;
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
 pub struct PeerSupportFlags(u32);
@@ -195,7 +197,7 @@ impl TransactionBlobs {
 }
 
 /// A Block that can contain transactions
-#[derive(Clone, Debug, EpeeObject, PartialEq, Eq)]
+#[derive(Clone, Debug, EpeeObject, Serialize, Deserialize, PartialEq, Eq)]
 pub struct BlockCompleteEntry {
     /// True if tx data is pruned
     #[epee_default(false)]
diff --git a/net/monero-wire/src/messages/common/serde_helpers.rs b/net/monero-wire/src/messages/common/serde_helpers.rs
new file mode 100644
index 00000000..88a9ffad
--- /dev/null
+++ b/net/monero-wire/src/messages/common/serde_helpers.rs
@@ -0,0 +1,106 @@
+use serde::de::{Error, SeqAccess};
+use serde::ser::SerializeSeq;
+use serde::{
+    de::{Deserialize, Visitor},
+    Deserializer, Serialize, Serializer,
+};
+use std::fmt::Formatter;
+
+use super::TransactionBlobs;
+
+impl<'de> Deserialize<'de> for TransactionBlobs {
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        struct TBVisitor;
+
+        impl<'de> Visitor<'de> for TBVisitor {
+            type Value = TransactionBlobs;
+
+            fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
+                write!(formatter, "A sequence of transactions blob")
+            }
+
+            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
+            where
+                A: SeqAccess<'de>,
+            {
+                let mut normal = Vec::new();
+                //let pruned = Vec::new();
+
+                while let Some(val) = seq.next_element::<SingleBlob>()? {
+                    match val {
+                        SingleBlob::Pruned(tx) => normal.push(tx),
+                    }
+                }
+
+                Ok(TransactionBlobs::Normal(normal))
+            }
+        }
+
+        deserializer.deserialize_any(TBVisitor)
+    }
+}
+
+impl Serialize for TransactionBlobs {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: Serializer,
+    {
+        match self {
+            TransactionBlobs::Pruned(_) => todo!(),
+            TransactionBlobs::Normal(txs) => {
+                let mut seq_ser = serializer.serialize_seq(Some(txs.len()))?;
+                for tx in txs {
+                    seq_ser.serialize_element(tx)?;
+                }
+                seq_ser.end()
+            }
+        }
+    }
+}
+
+enum SingleBlob {
+    Pruned(Vec<u8>),
+}
+
+impl<'de> Deserialize<'de> for SingleBlob {
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        struct TBDSVisitor;
+
+        impl<'de> Visitor<'de> for TBDSVisitor {
+            type Value = SingleBlob;
+
+            fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
+                write!(formatter, "A single transaction blob")
+            }
+
+            fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
+            where
+                E: Error,
+            {
+                Ok(SingleBlob::Pruned(v.into()))
+            }
+
+            fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
+            where
+                E: Error,
+            {
+                Ok(SingleBlob::Pruned(v))
+            }
+
+            fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+            where
+                D: Deserializer<'de>,
+            {
+                todo!("Pruned blobs")
+            }
+        }
+
+        deserializer.deserialize_any(TBDSVisitor)
+    }
+}