From 02e950bf5665a32d13862bd2f70705dca3142536 Mon Sep 17 00:00:00 2001
From: "hinto.janai" <hinto.janai@protonmail.com>
Date: Thu, 10 Oct 2024 17:37:28 -0400
Subject: [PATCH] small fixes, hardfork changes

---
 Cargo.lock                          | 23 +++++++++
 Cargo.toml                          |  1 +
 binaries/cuprated/src/rpc.rs        |  2 +-
 binaries/cuprated/src/rpc/helper.rs | 22 ++++-----
 binaries/cuprated/src/rpc/json.rs   | 26 +++++-----
 rpc/types/src/json.rs               | 17 +++++--
 test-utils/src/rpc/data/json.rs     |  5 +-
 types/Cargo.toml                    |  1 +
 types/src/hard_fork.rs              | 73 ++++++++++++++++++++---------
 9 files changed, 120 insertions(+), 50 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index e45f7e42..089236a2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -933,6 +933,7 @@ dependencies = [
  "proptest-derive",
  "serde",
  "serde_json",
+ "strum",
  "thiserror",
 ]
 
@@ -2674,6 +2675,28 @@ dependencies = [
  "spin",
 ]
 
+[[package]]
+name = "strum"
+version = "0.26.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
+dependencies = [
+ "strum_macros",
+]
+
+[[package]]
+name = "strum_macros"
+version = "0.26.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "rustversion",
+ "syn 2.0.77",
+]
+
 [[package]]
 name = "subtle"
 version = "2.6.1"
diff --git a/Cargo.toml b/Cargo.toml
index fa348ccd..6c322fbd 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -78,6 +78,7 @@ rayon                 = { version = "1.10.0", default-features = false }
 serde_bytes           = { version = "0.11.15", default-features = false }
 serde_json            = { version = "1.0.128", default-features = false }
 serde                 = { version = "1.0.210", default-features = false }
+strum                 = { version = "0.26.3", default-features = false }
 thiserror             = { version = "1.0.63", default-features = false }
 thread_local          = { version = "1.1.8", default-features = false }
 tokio-util            = { version = "0.7.12", default-features = false }
diff --git a/binaries/cuprated/src/rpc.rs b/binaries/cuprated/src/rpc.rs
index a52fc98c..9d12c1b5 100644
--- a/binaries/cuprated/src/rpc.rs
+++ b/binaries/cuprated/src/rpc.rs
@@ -4,9 +4,9 @@
 
 mod bin;
 mod handler;
+mod helper;
 mod json;
 mod other;
 mod request;
-mod helper;
 
 pub use handler::CupratedRpcHandler;
diff --git a/binaries/cuprated/src/rpc/helper.rs b/binaries/cuprated/src/rpc/helper.rs
index 7c95b1b3..5d6477c5 100644
--- a/binaries/cuprated/src/rpc/helper.rs
+++ b/binaries/cuprated/src/rpc/helper.rs
@@ -92,7 +92,7 @@ pub(super) async fn block_header_by_hash(
     let block = blockchain::block_by_hash(&mut state.blockchain_read, hash).await?;
     let header: ExtendedBlockHeader = todo!(); //blockchain::block_extended_header_by_hash(state.blockchain_read, hash).await?;
 
-    let block_header = into_block_header(header.height, top_height, fill_pow_hash, block, header);
+    let block_header = into_block_header(todo!(), top_height, fill_pow_hash, block, header);
 
     Ok(block_header)
 }
@@ -105,8 +105,7 @@ pub(super) async fn top_block_header(
     let block: Block = todo!();
     let header: ExtendedBlockHeader = todo!();
 
-    let block_header =
-        into_block_header(header.height, header.height, fill_pow_hash, block, header);
+    let block_header = into_block_header(todo!(), todo!(), fill_pow_hash, block, header);
 
     Ok(block_header)
 }
@@ -148,7 +147,7 @@ pub(super) fn hex_to_hash(hex: String) -> Result<[u8; 32], Error> {
 
 /// [`BlockchainResponse::ChainHeight`] minus 1.
 pub(super) async fn top_height(state: &mut CupratedRpcHandler) -> Result<(u64, [u8; 32]), Error> {
-    let (chain_height, hash) = blockchain::chain_height(state).await?;
+    let (chain_height, hash) = blockchain::chain_height(&mut state.blockchain_read).await?;
     let height = chain_height.saturating_sub(1);
     Ok((height, hash))
 }
@@ -158,11 +157,12 @@ pub(super) async fn key_image_spent(
     state: &mut CupratedRpcHandler,
     key_image: [u8; 32],
 ) -> Result<KeyImageSpentStatus, Error> {
-    if blockchain::key_image_spent(state, key_image).await? {
-        Ok(KeyImageSpentStatus::SpentInBlockchain)
-    } else if todo!("key image is spent in tx pool") {
-        Ok(KeyImageSpentStatus::SpentInPool)
-    } else {
-        Ok(KeyImageSpentStatus::Unspent)
-    }
+    todo!("impl key image vec check responding KeyImageSpentStatus")
+    // if blockchain::key_image_spent(state, key_image).await? {
+    //     Ok(KeyImageSpentStatus::SpentInBlockchain)
+    // } else if todo!("key image is spent in tx pool") {
+    //     Ok(KeyImageSpentStatus::SpentInPool)
+    // } else {
+    //     Ok(KeyImageSpentStatus::Unspent)
+    // }
 }
diff --git a/binaries/cuprated/src/rpc/json.rs b/binaries/cuprated/src/rpc/json.rs
index 2ba6796b..604ed91e 100644
--- a/binaries/cuprated/src/rpc/json.rs
+++ b/binaries/cuprated/src/rpc/json.rs
@@ -8,9 +8,10 @@ use tower::{Service, ServiceExt};
 use cuprate_consensus::{BlockchainReadRequest, BlockchainResponse};
 use cuprate_constants::{
     build::RELEASE,
-    rpc::{BLOCK_SIZE_SANITY_LEEWAY, RESTRICTED_BLOCK_COUNT, RESTRICTED_BLOCK_HEADER_RANGE},
+    rpc::{RESTRICTED_BLOCK_COUNT, RESTRICTED_BLOCK_HEADER_RANGE},
 };
 use cuprate_helper::cast::u64_to_usize;
+use cuprate_rpc_interface::RpcHandler;
 use cuprate_rpc_types::{
     base::{AccessResponseBase, ResponseBase},
     json::{
@@ -114,7 +115,7 @@ async fn on_get_block_hash(
     request: OnGetBlockHashRequest,
 ) -> Result<OnGetBlockHashResponse, Error> {
     let [height] = request.block_height;
-    let hash = blockchain::block_hash(&mut state, height).await?;
+    let hash = blockchain::block_hash(&mut state.blockchain_read, height, todo!()).await?;
     let block_hash = hex::encode(hash);
 
     Ok(OnGetBlockHashResponse { block_hash })
@@ -127,11 +128,11 @@ async fn submit_block(
 ) -> Result<SubmitBlockResponse, Error> {
     let [blob] = request.block_blob;
 
-    let limit = blockchain::cumulative_block_weight_limit(&mut state).await?;
+    let limit = todo!(); //blockchain::cumulative_block_weight_limit(&mut state.blockchain_read).await?;
 
-    if blob.len() > limit + BLOCK_SIZE_SANITY_LEEWAY {
-        return Err(anyhow!("Block size is too big, rejecting block"));
-    }
+    // if blob.len() > limit + BLOCK_SIZE_SANITY_LEEWAY {
+    //     return Err(anyhow!("Block size is too big, rejecting block"));
+    // }
 
     let bytes = hex::decode(blob)?;
     let block = Block::read(&mut bytes.as_slice())?;
@@ -173,12 +174,12 @@ async fn get_last_block_header(
     })
 }
 
-/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L2468-L2498>
+/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L2500-L2567>
 async fn get_block_header_by_hash(
     mut state: CupratedRpcHandler,
     request: GetBlockHeaderByHashRequest,
 ) -> Result<GetBlockHeaderByHashResponse, Error> {
-    if state.restricted && request.hashes.len() > RESTRICTED_BLOCK_COUNT {
+    if state.restricted() && request.hashes.len() > RESTRICTED_BLOCK_COUNT {
         return Err(anyhow!(
             "Too many block headers requested in restricted mode"
         ));
@@ -239,7 +240,7 @@ async fn get_block_headers_range(
         return Err(anyhow!("Invalid start/end heights"));
     }
 
-    if state.restricted
+    if state.restricted()
         && request.end_height.saturating_sub(request.start_height) + 1
             > RESTRICTED_BLOCK_HEADER_RANGE
     {
@@ -280,10 +281,10 @@ async fn get_block(
 ) -> Result<GetBlockResponse, Error> {
     let block = if request.hash.is_empty() {
         helper::check_height(&mut state, request.height).await?;
-        blockchain::block(&mut state, request.height).await?
+        blockchain::block(&mut state.blockchain_read, request.height).await?
     } else {
         let hash = helper::hex_to_hash(request.hash)?;
-        blockchain::block_by_hash(&mut state, hash).await?
+        blockchain::block_by_hash(&mut state.blockchain_read, hash).await?
     };
 
     Ok(todo!())
@@ -375,7 +376,8 @@ async fn hard_fork_info(
     let hard_fork = if request.version > 0 {
         HardFork::from_version(request.version)?
     } else {
-        blockchain::current_hard_fork(&mut state).await?
+        // blockchain::current_hard_fork(&mut state).await?
+        todo!()
     };
 
     Ok(HardForkInfoResponse {
diff --git a/rpc/types/src/json.rs b/rpc/types/src/json.rs
index d3426b46..c28a47f1 100644
--- a/rpc/types/src/json.rs
+++ b/rpc/types/src/json.rs
@@ -817,8 +817,17 @@ define_request_and_response! {
     hard_fork_info,
     cc73fe71162d564ffda8e549b79a350bca53c454 =>
     core_rpc_server_commands_defs.h => 1958..=1995,
-    HardForkInfo (empty),
-    Request {},
+    HardForkInfo,
+
+    #[doc = serde_doc_test!(
+        HARD_FORK_INFO => HardForkInfo {
+            version: 16,
+        }
+    )]
+    #[derive(Copy)]
+    Request {
+        version: u8,
+    },
 
     #[doc = serde_doc_test!(
         HARD_FORK_INFO_RESPONSE => HardForkInfoResponse {
@@ -827,9 +836,9 @@ define_request_and_response! {
             enabled: true,
             state: 0,
             threshold: 0,
-            version: 16,
+            version: 3,
             votes: 10080,
-            voting: 16,
+            voting: 3,
             window: 10080
         }
     )]
diff --git a/test-utils/src/rpc/data/json.rs b/test-utils/src/rpc/data/json.rs
index a05af670..3d463062 100644
--- a/test-utils/src/rpc/data/json.rs
+++ b/test-utils/src/rpc/data/json.rs
@@ -608,7 +608,10 @@ define_request_and_response! {
 r#"{
   "jsonrpc": "2.0",
   "id": "0",
-  "method": "hard_fork_info"
+  "method": "hard_fork_info",
+  "params": {
+    "version": 16
+  }
 }"#;
     Response =
 r#"{
diff --git a/types/Cargo.toml b/types/Cargo.toml
index 1c762902..8ac6b25f 100644
--- a/types/Cargo.toml
+++ b/types/Cargo.toml
@@ -27,6 +27,7 @@ curve25519-dalek = { workspace = true }
 monero-serai     = { workspace = true }
 hex              = { workspace = true, features = ["serde", "alloc"], optional = true }
 serde            = { workspace = true, features = ["derive"], optional = true }
+strum            = { workspace = true, features = ["derive"] }
 thiserror        = { workspace = true }
 
 proptest = { workspace = true, optional = true }
diff --git a/types/src/hard_fork.rs b/types/src/hard_fork.rs
index 8b2cd78c..92dfb5b7 100644
--- a/types/src/hard_fork.rs
+++ b/types/src/hard_fork.rs
@@ -1,6 +1,10 @@
 //! The [`HardFork`] type.
 use std::time::Duration;
 
+use strum::{
+    AsRefStr, Display, EnumCount, EnumIs, EnumString, FromRepr, IntoStaticStr, VariantArray,
+};
+
 use monero_serai::block::BlockHeader;
 
 /// Target block time for hf 1.
@@ -27,7 +31,25 @@ pub enum HardForkError {
 }
 
 /// An identifier for every hard-fork Monero has had.
-#[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)]
+#[derive(
+    Default,
+    Debug,
+    PartialEq,
+    Eq,
+    PartialOrd,
+    Ord,
+    Copy,
+    Clone,
+    Hash,
+    EnumCount,
+    Display,
+    AsRefStr,
+    EnumIs,
+    EnumString,
+    FromRepr,
+    IntoStaticStr,
+    VariantArray,
+)]
 #[cfg_attr(any(feature = "proptest"), derive(proptest_derive::Arbitrary))]
 #[repr(u8)]
 pub enum HardFork {
@@ -52,6 +74,14 @@ pub enum HardFork {
 }
 
 impl HardFork {
+    /// TODO
+    ///
+    /// ```rust
+    /// # use crate::hard_fork::HardFork;
+    /// assert_eq!(HardFork::CURRENT, HardFork::V16);
+    /// ```
+    pub const CURRENT: Self = Self::VARIANTS[Self::COUNT - 1];
+
     /// Returns the hard-fork for a blocks [`BlockHeader::hardfork_version`] field.
     ///
     /// ref: <https://monero-book.cuprate.org/consensus_rules/hardforks.html#blocks-version-and-vote>
@@ -61,25 +91,21 @@ impl HardFork {
     /// Will return [`Err`] if the version is not a valid [`HardFork`].
     #[inline]
     pub const fn from_version(version: u8) -> Result<Self, HardForkError> {
-        Ok(match version {
-            1 => Self::V1,
-            2 => Self::V2,
-            3 => Self::V3,
-            4 => Self::V4,
-            5 => Self::V5,
-            6 => Self::V6,
-            7 => Self::V7,
-            8 => Self::V8,
-            9 => Self::V9,
-            10 => Self::V10,
-            11 => Self::V11,
-            12 => Self::V12,
-            13 => Self::V13,
-            14 => Self::V14,
-            15 => Self::V15,
-            16 => Self::V16,
-            _ => return Err(HardForkError::HardForkUnknown),
-        })
+        #[expect(
+            clippy::cast_possible_truncation,
+            reason = "we check that `HardFork::COUNT` fits into a `u8`."
+        )]
+        const COUNT_AS_U8: u8 = {
+            const COUNT: usize = HardFork::COUNT;
+            assert!(COUNT <= u8::MAX as usize);
+            COUNT as u8
+        };
+
+        if version != 0 && version <= COUNT_AS_U8 {
+            Ok(Self::VARIANTS[(version - 1) as usize])
+        } else {
+            Err(HardForkError::HardForkUnknown)
+        }
     }
 
     /// Returns the hard-fork for a blocks [`BlockHeader::hardfork_signal`] (vote) field.
@@ -92,7 +118,7 @@ impl HardFork {
             return Self::V1;
         }
         // This must default to the latest hard-fork!
-        Self::from_version(vote).unwrap_or(Self::V16)
+        Self::from_version(vote).unwrap_or(Self::CURRENT)
     }
 
     /// Returns the [`HardFork`] version and vote from this block header.
@@ -127,4 +153,9 @@ impl HardFork {
             _ => BLOCK_TIME_V2,
         }
     }
+
+    /// TODO
+    pub const fn is_current(self) -> bool {
+        matches!(self, Self::CURRENT)
+    }
 }