diff --git a/Cargo.lock b/Cargo.lock index 61c4725..864d4b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -29,6 +29,15 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "android-tzdata" version = "0.1.1" @@ -44,6 +53,12 @@ dependencies = [ "libc", ] +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + [[package]] name = "anstyle" version = "1.0.8" @@ -68,6 +83,16 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "assert-json-diff" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "async-stream" version = "0.3.5" @@ -337,6 +362,12 @@ dependencies = [ "serde", ] +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + [[package]] name = "cc" version = "1.1.21" @@ -370,6 +401,33 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + [[package]] name = "clap" version = "4.5.17" @@ -388,6 +446,7 @@ checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73" dependencies = [ "anstyle", "clap_lex", + "terminal_size", ] [[package]] @@ -468,6 +527,42 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "criterion" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "is-terminal", + "itertools", + "num-traits", + "once_cell", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools", +] + [[package]] name = "crossbeam" version = "0.8.4" @@ -524,6 +619,12 @@ version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "crypto-bigint" version = "0.5.5" @@ -573,12 +674,37 @@ dependencies = [ "tokio", ] +[[package]] +name = "cuprate-benchmark" +version = "0.0.0" +dependencies = [ + "cfg-if", + "cuprate-benchmark-example", + "cuprate-benchmark-lib", + "serde", + "serde_json", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "cuprate-benchmark-example" +version = "0.0.0" +dependencies = [ + "cuprate-benchmark-lib", +] + +[[package]] +name = "cuprate-benchmark-lib" +version = "0.0.0" + [[package]] name = "cuprate-blockchain" version = "0.0.0" dependencies = [ "bitflags 2.6.0", "bytemuck", + "bytes", "cuprate-constants", "cuprate-database", "cuprate-database-service", @@ -675,6 +801,25 @@ dependencies = [ name = "cuprate-constants" version = "0.1.0" +[[package]] +name = "cuprate-criterion-example" +version = "0.0.0" +dependencies = [ + "criterion", + "function_name", + "serde_json", +] + +[[package]] +name = "cuprate-criterion-json-rpc" +version = "0.0.0" +dependencies = [ + "criterion", + "cuprate-json-rpc", + "function_name", + "serde_json", +] + [[package]] name = "cuprate-cryptonight" version = "0.1.0" @@ -790,6 +935,7 @@ dependencies = [ "libc", "monero-serai", "rayon", + "serde", "tokio", "windows", ] @@ -837,7 +983,6 @@ dependencies = [ "cuprate-test-utils", "cuprate-types", "cuprate-wire", - "dashmap", "futures", "indexmap", "monero-serai", @@ -1013,6 +1158,17 @@ dependencies = [ "thiserror", ] +[[package]] +name = "cuprate-zmq-types" +version = "0.1.0" +dependencies = [ + "assert-json-diff", + "cuprate-types", + "hex", + "serde", + "serde_json", +] + [[package]] name = "cuprated" version = "0.0.1" @@ -1078,6 +1234,7 @@ dependencies = [ "tokio", "tokio-stream", "tokio-util", + "toml", "tower 0.5.1", "tracing", "tracing-subscriber", @@ -1285,6 +1442,21 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "function_name" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1ab577a896d09940b5fe12ec5ae71f9d8211fff62c919c03a3750a9901e98a7" +dependencies = [ + "function_name-proc-macro", +] + +[[package]] +name = "function_name-proc-macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673464e1e314dd67a0fd9544abc99e8eb28d0c7e3b69b033bcff9b2d00b87333" + [[package]] name = "funty" version = "2.0.0" @@ -1434,6 +1606,16 @@ dependencies = [ "tracing", ] +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + [[package]] name = "hashbrown" version = "0.14.5" @@ -1493,6 +1675,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "hex" version = "0.4.3" @@ -1656,6 +1844,26 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "is-terminal" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +dependencies = [ + "hermit-abi 0.4.0", + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.11" @@ -1752,6 +1960,15 @@ version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "matchit" version = "0.7.3" @@ -1807,7 +2024,7 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", "wasi", "windows-sys 0.52.0", @@ -2007,6 +2224,12 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "oorandom" +version = "11.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" + [[package]] name = "openssl-probe" version = "0.1.5" @@ -2144,6 +2367,34 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + +[[package]] +name = "plotters-svg" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +dependencies = [ + "plotters-backend", +] + [[package]] name = "ppv-lite86" version = "0.2.20" @@ -2218,7 +2469,7 @@ dependencies = [ "rand", "rand_chacha", "rand_xorshift", - "regex-syntax", + "regex-syntax 0.8.4", "rusty-fork", "tempfile", "unarray", @@ -2384,6 +2635,44 @@ dependencies = [ "syn", ] +[[package]] +name = "regex" +version = "1.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.4", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "regex-syntax" version = "0.8.4" @@ -2512,6 +2801,15 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schannel" version = "0.1.24" @@ -2613,6 +2911,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -2830,6 +3137,16 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "terminal_size" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +dependencies = [ + "rustix", + "windows-sys 0.48.0", +] + [[package]] name = "thiserror" version = "1.0.63" @@ -2866,6 +3183,16 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a693d0c8cf16973fac5a93fbe47b8c6452e7097d4fcac49f3d7a18e39c76e62e" +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "tinyvec" version = "1.8.0" @@ -2961,11 +3288,26 @@ dependencies = [ "tracing", ] +[[package]] +name = "toml" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + [[package]] name = "toml_datetime" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] [[package]] name = "toml_edit" @@ -2974,6 +3316,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b072cee73c449a636ffd6f32bd8de3a9f7119139aff882f44943ce2986dc5cf" dependencies = [ "indexmap", + "serde", + "serde_spanned", "toml_datetime", "winnow", ] @@ -3082,10 +3426,14 @@ version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ + "matchers", "nu-ansi-term", + "once_cell", + "regex", "sharded-slab", "smallvec", "thread_local", + "tracing", "tracing-core", "tracing-log", ] @@ -3191,6 +3539,16 @@ dependencies = [ "libc", ] +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" @@ -3261,6 +3619,16 @@ version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +[[package]] +name = "web-sys" +version = "0.3.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "webpki-roots" version = "0.26.5" @@ -3286,6 +3654,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/binaries/cuprated/Cargo.toml b/binaries/cuprated/Cargo.toml index 52c7c6d..70a5c50 100644 --- a/binaries/cuprated/Cargo.toml +++ b/binaries/cuprated/Cargo.toml @@ -15,7 +15,7 @@ cuprate-consensus-context = { workspace = true } cuprate-consensus-rules = { workspace = true } cuprate-constants = { workspace = true, features = ["build", "rpc"] } cuprate-cryptonight = { workspace = true } -cuprate-helper = { workspace = true, features = ["serde"] } +cuprate-helper = { workspace = true, features = ["serde", "time"] } cuprate-epee-encoding = { workspace = true } cuprate-fixed-bytes = { workspace = true } cuprate-levin = { workspace = true } diff --git a/binaries/cuprated/src/rpc/bin.rs b/binaries/cuprated/src/rpc/bin.rs index 70d8c63..87b4a53 100644 --- a/binaries/cuprated/src/rpc/bin.rs +++ b/binaries/cuprated/src/rpc/bin.rs @@ -1,8 +1,11 @@ //! RPC request handler functions (binary endpoints). -use anyhow::Error; +use anyhow::{anyhow, Error}; +use cuprate_constants::rpc::{RESTRICTED_BLOCK_COUNT, RESTRICTED_TRANSACTIONS_COUNT}; +use cuprate_rpc_interface::RpcHandler; use cuprate_rpc_types::{ + base::{AccessResponseBase, ResponseBase}, bin::{ BinRequest, BinResponse, GetBlocksByHeightRequest, GetBlocksByHeightResponse, GetBlocksRequest, GetBlocksResponse, GetHashesRequest, GetHashesResponse, @@ -10,9 +13,11 @@ use cuprate_rpc_types::{ GetTransactionPoolHashesRequest, GetTransactionPoolHashesResponse, }, json::{GetOutputDistributionRequest, GetOutputDistributionResponse}, + misc::RequestedInfo, }; +use cuprate_types::BlockCompleteEntry; -use crate::rpc::CupratedRpcHandler; +use crate::rpc::{helper, request::blockchain, CupratedRpcHandler}; /// Map a [`BinRequest`] to the function that will lead to a [`BinResponse`]. pub(super) async fn map_request( @@ -37,51 +42,155 @@ pub(super) async fn map_request( }) } +/// async fn get_blocks( state: CupratedRpcHandler, request: GetBlocksRequest, ) -> Result { - todo!() + // Time should be set early: + // + let daemon_time = cuprate_helper::time::current_unix_timestamp(); + + let Some(requested_info) = RequestedInfo::from_u8(request.requested_info) else { + return Err(anyhow!("Failed, wrong requested info")); + }; + + let (get_blocks, get_pool) = match requested_info { + RequestedInfo::BlocksOnly => (true, false), + RequestedInfo::BlocksAndPool => (true, true), + RequestedInfo::PoolOnly => (false, true), + }; + + if get_pool { + let max_tx_count = if state.is_restricted() { + RESTRICTED_TRANSACTIONS_COUNT + } else { + usize::MAX + }; + + todo!(); + } + + if get_blocks { + if !request.block_ids.is_empty() { + todo!(); + } + + todo!(); + } + + // Ok(GetBlocksResponse { + // base: ResponseBase::OK, + // ..todo!() + // }) + Ok(todo!()) } +/// async fn get_blocks_by_height( state: CupratedRpcHandler, request: GetBlocksByHeightRequest, ) -> Result { - todo!() + if state.is_restricted() && request.heights.len() > RESTRICTED_BLOCK_COUNT { + return Err(anyhow!("Too many blocks requested in restricted mode")); + } + + let blocks = request + .heights + .into_iter() + .map(|height| Ok(todo!())) + .collect::, Error>>()?; + + Ok(GetBlocksByHeightResponse { + base: AccessResponseBase::OK, + blocks, + }) } +/// async fn get_hashes( - state: CupratedRpcHandler, + mut state: CupratedRpcHandler, request: GetHashesRequest, ) -> Result { - todo!() + // FIXME: impl `last()` + let last = { + let len = request.block_ids.len(); + + if len == 0 { + return Err(anyhow!("block_ids empty")); + } + + request.block_ids[len - 1] + }; + + const GENESIS_BLOCK_HASH: [u8; 32] = [0; 32]; // TODO + if last != GENESIS_BLOCK_HASH { + return Err(anyhow!( + "genesis block mismatch, found: {last:?}, expected: {GENESIS_BLOCK_HASH:?}" + )); + } + + let mut bytes = request.block_ids; + let hashes: Vec<[u8; 32]> = (&bytes).into(); + + let (current_height, _) = helper::top_height(&mut state).await?; + + let Some((index, start_height)) = + blockchain::find_first_unknown(&mut state.blockchain_read, hashes).await? + else { + return Err(anyhow!("Failed")); + }; + + let m_blocks_ids = bytes.split_off(index); + + Ok(GetHashesResponse { + base: AccessResponseBase::OK, + m_blocks_ids, + start_height, + current_height, + }) } +/// async fn get_output_indexes( state: CupratedRpcHandler, request: GetOutputIndexesRequest, ) -> Result { - todo!() + Ok(GetOutputIndexesResponse { + base: AccessResponseBase::OK, + ..todo!() + }) } +/// async fn get_outs( state: CupratedRpcHandler, request: GetOutsRequest, ) -> Result { - todo!() + Ok(GetOutsResponse { + base: AccessResponseBase::OK, + ..todo!() + }) } +/// async fn get_transaction_pool_hashes( state: CupratedRpcHandler, request: GetTransactionPoolHashesRequest, ) -> Result { - todo!() + Ok(GetTransactionPoolHashesResponse { + base: AccessResponseBase::OK, + ..todo!() + }) } +/// async fn get_output_distribution( state: CupratedRpcHandler, request: GetOutputDistributionRequest, ) -> Result { - todo!() + Ok(GetOutputDistributionResponse { + base: AccessResponseBase::OK, + ..todo!() + }) } diff --git a/binaries/cuprated/src/rpc/json.rs b/binaries/cuprated/src/rpc/json.rs index 7e4e59e..54dac12 100644 --- a/binaries/cuprated/src/rpc/json.rs +++ b/binaries/cuprated/src/rpc/json.rs @@ -411,7 +411,7 @@ async fn get_info( let (database_size, free_space) = if restricted { // const fn round_up(value: u64, quantum: u64) -> u64 { - (value + quantum - 1) / quantum * quantum + value.div_ceil(quantum) } let database_size = round_up(database_size, 5 * 1024 * 1024 * 1024); (database_size, u64::MAX) diff --git a/binaries/cuprated/src/rpc/other.rs b/binaries/cuprated/src/rpc/other.rs index a67774f..00ee0c7 100644 --- a/binaries/cuprated/src/rpc/other.rs +++ b/binaries/cuprated/src/rpc/other.rs @@ -1,25 +1,42 @@ //! RPC request handler functions (other JSON endpoints). -use anyhow::Error; +use std::collections::{HashMap, HashSet}; -use cuprate_rpc_types::other::{ - GetAltBlocksHashesRequest, GetAltBlocksHashesResponse, GetHeightRequest, GetHeightResponse, - GetLimitRequest, GetLimitResponse, GetNetStatsRequest, GetNetStatsResponse, GetOutsRequest, - GetOutsResponse, GetPeerListRequest, GetPeerListResponse, GetPublicNodesRequest, - GetPublicNodesResponse, GetTransactionPoolHashesRequest, GetTransactionPoolHashesResponse, - GetTransactionPoolRequest, GetTransactionPoolResponse, GetTransactionPoolStatsRequest, - GetTransactionPoolStatsResponse, GetTransactionsRequest, GetTransactionsResponse, - InPeersRequest, InPeersResponse, IsKeyImageSpentRequest, IsKeyImageSpentResponse, - MiningStatusRequest, MiningStatusResponse, OtherRequest, OtherResponse, OutPeersRequest, - OutPeersResponse, PopBlocksRequest, PopBlocksResponse, SaveBcRequest, SaveBcResponse, - SendRawTransactionRequest, SendRawTransactionResponse, SetBootstrapDaemonRequest, - SetBootstrapDaemonResponse, SetLimitRequest, SetLimitResponse, SetLogCategoriesRequest, - SetLogCategoriesResponse, SetLogHashRateRequest, SetLogHashRateResponse, SetLogLevelRequest, - SetLogLevelResponse, StartMiningRequest, StartMiningResponse, StopDaemonRequest, - StopDaemonResponse, StopMiningRequest, StopMiningResponse, UpdateRequest, UpdateResponse, +use anyhow::{anyhow, Error}; + +use cuprate_constants::rpc::{ + MAX_RESTRICTED_GLOBAL_FAKE_OUTS_COUNT, RESTRICTED_SPENT_KEY_IMAGES_COUNT, +}; +use cuprate_helper::cast::usize_to_u64; +use cuprate_rpc_interface::RpcHandler; +use cuprate_rpc_types::{ + base::{AccessResponseBase, ResponseBase}, + misc::{KeyImageSpentStatus, OutKey, Status}, + other::{ + GetAltBlocksHashesRequest, GetAltBlocksHashesResponse, GetHeightRequest, GetHeightResponse, + GetLimitRequest, GetLimitResponse, GetNetStatsRequest, GetNetStatsResponse, GetOutsRequest, + GetOutsResponse, GetPeerListRequest, GetPeerListResponse, GetPublicNodesRequest, + GetPublicNodesResponse, GetTransactionPoolHashesRequest, GetTransactionPoolHashesResponse, + GetTransactionPoolRequest, GetTransactionPoolResponse, GetTransactionPoolStatsRequest, + GetTransactionPoolStatsResponse, GetTransactionsRequest, GetTransactionsResponse, + InPeersRequest, InPeersResponse, IsKeyImageSpentRequest, IsKeyImageSpentResponse, + MiningStatusRequest, MiningStatusResponse, OtherRequest, OtherResponse, OutPeersRequest, + OutPeersResponse, PopBlocksRequest, PopBlocksResponse, SaveBcRequest, SaveBcResponse, + SendRawTransactionRequest, SendRawTransactionResponse, SetBootstrapDaemonRequest, + SetBootstrapDaemonResponse, SetLimitRequest, SetLimitResponse, SetLogCategoriesRequest, + SetLogCategoriesResponse, SetLogHashRateRequest, SetLogHashRateResponse, + SetLogLevelRequest, SetLogLevelResponse, StartMiningRequest, StartMiningResponse, + StopDaemonRequest, StopDaemonResponse, StopMiningRequest, StopMiningResponse, + UpdateRequest, UpdateResponse, + }, }; -use crate::rpc::CupratedRpcHandler; +use crate::{ + rpc::CupratedRpcHandler, + rpc::{helper, request::blockchain}, +}; + +use super::request::blockchain_manager; /// Map a [`OtherRequest`] to the function that will lead to a [`OtherResponse`]. pub(super) async fn map_request( @@ -39,12 +56,8 @@ pub(super) async fn map_request( Req::SendRawTransaction(r) => { Resp::SendRawTransaction(send_raw_transaction(state, r).await?) } - Req::StartMining(r) => Resp::StartMining(start_mining(state, r).await?), - Req::StopMining(r) => Resp::StopMining(stop_mining(state, r).await?), - Req::MiningStatus(r) => Resp::MiningStatus(mining_status(state, r).await?), Req::SaveBc(r) => Resp::SaveBc(save_bc(state, r).await?), Req::GetPeerList(r) => Resp::GetPeerList(get_peer_list(state, r).await?), - Req::SetLogHashRate(r) => Resp::SetLogHashRate(set_log_hash_rate(state, r).await?), Req::SetLogLevel(r) => Resp::SetLogLevel(set_log_level(state, r).await?), Req::SetLogCategories(r) => Resp::SetLogCategories(set_log_categories(state, r).await?), Req::SetBootstrapDaemon(r) => { @@ -69,194 +82,356 @@ pub(super) async fn map_request( Resp::GetTransactionPoolHashes(get_transaction_pool_hashes(state, r).await?) } Req::GetPublicNodes(r) => Resp::GetPublicNodes(get_public_nodes(state, r).await?), + + // Unsupported requests. + Req::StartMining(_) + | Req::StopMining(_) + | Req::MiningStatus(_) + | Req::SetLogHashRate(_) => { + return Err(anyhow!("Mining RPC calls are not supported by Cuprate")) + } }) } +/// async fn get_height( - state: CupratedRpcHandler, + mut state: CupratedRpcHandler, request: GetHeightRequest, ) -> Result { - todo!() + let (height, hash) = helper::top_height(&mut state).await?; + let hash = hex::encode(hash); + + Ok(GetHeightResponse { + base: ResponseBase::OK, + height, + hash, + }) } +/// async fn get_transactions( state: CupratedRpcHandler, request: GetTransactionsRequest, ) -> Result { - todo!() + Ok(GetTransactionsResponse { + base: AccessResponseBase::OK, + ..todo!() + }) } +/// async fn get_alt_blocks_hashes( state: CupratedRpcHandler, request: GetAltBlocksHashesRequest, ) -> Result { - todo!() + Ok(GetAltBlocksHashesResponse { + base: AccessResponseBase::OK, + ..todo!() + }) } +/// async fn is_key_image_spent( - state: CupratedRpcHandler, + mut state: CupratedRpcHandler, request: IsKeyImageSpentRequest, ) -> Result { - todo!() + if state.is_restricted() && request.key_images.len() > RESTRICTED_SPENT_KEY_IMAGES_COUNT { + return Err(anyhow!("Too many key images queried in restricted mode")); + } + + let mut spent_status = Vec::with_capacity(request.key_images.len()); + + for hex in request.key_images { + let key_image = helper::hex_to_hash(hex)?; + let status = helper::key_image_spent(&mut state, key_image).await?; + spent_status.push(status.to_u8()); + } + + Ok(IsKeyImageSpentResponse { + base: AccessResponseBase::OK, + spent_status, + }) } +/// async fn send_raw_transaction( state: CupratedRpcHandler, request: SendRawTransactionRequest, ) -> Result { - todo!() + Ok(SendRawTransactionResponse { + base: AccessResponseBase::OK, + ..todo!() + }) } +/// async fn start_mining( state: CupratedRpcHandler, request: StartMiningRequest, ) -> Result { - todo!() + unreachable!(); + Ok(StartMiningResponse { + base: ResponseBase::OK, + }) } +/// async fn stop_mining( state: CupratedRpcHandler, request: StopMiningRequest, ) -> Result { - todo!() + unreachable!(); + Ok(StopMiningResponse { + base: ResponseBase::OK, + }) } +/// async fn mining_status( state: CupratedRpcHandler, request: MiningStatusRequest, ) -> Result { - todo!() + unreachable!(); + Ok(MiningStatusResponse { + base: ResponseBase::OK, + ..todo!() + }) } +/// async fn save_bc( state: CupratedRpcHandler, request: SaveBcRequest, ) -> Result { - todo!() + todo!(); + Ok(SaveBcResponse { + base: ResponseBase::OK, + }) } +/// async fn get_peer_list( state: CupratedRpcHandler, request: GetPeerListRequest, ) -> Result { - todo!() + Ok(GetPeerListResponse { + base: ResponseBase::OK, + ..todo!() + }) } +/// async fn set_log_hash_rate( state: CupratedRpcHandler, request: SetLogHashRateRequest, ) -> Result { - todo!() + unreachable!(); + Ok(SetLogHashRateResponse { + base: ResponseBase::OK, + }) } +/// async fn set_log_level( state: CupratedRpcHandler, request: SetLogLevelRequest, ) -> Result { - todo!() + todo!(); + Ok(SetLogLevelResponse { + base: ResponseBase::OK, + }) } +/// async fn set_log_categories( state: CupratedRpcHandler, request: SetLogCategoriesRequest, ) -> Result { - todo!() + Ok(SetLogCategoriesResponse { + base: ResponseBase::OK, + ..todo!() + }) } +/// async fn set_bootstrap_daemon( state: CupratedRpcHandler, request: SetBootstrapDaemonRequest, ) -> Result { - todo!() + todo!(); + Ok(SetBootstrapDaemonResponse { status: Status::Ok }) } +/// async fn get_transaction_pool( state: CupratedRpcHandler, request: GetTransactionPoolRequest, ) -> Result { - todo!() + Ok(GetTransactionPoolResponse { + base: AccessResponseBase::OK, + ..todo!() + }) } +/// async fn get_transaction_pool_stats( state: CupratedRpcHandler, request: GetTransactionPoolStatsRequest, ) -> Result { - todo!() + Ok(GetTransactionPoolStatsResponse { + base: AccessResponseBase::OK, + ..todo!() + }) } +/// async fn stop_daemon( state: CupratedRpcHandler, request: StopDaemonRequest, ) -> Result { - todo!() + todo!(); + Ok(StopDaemonResponse { status: Status::Ok }) } +/// async fn get_limit( state: CupratedRpcHandler, request: GetLimitRequest, ) -> Result { - todo!() + Ok(GetLimitResponse { + base: ResponseBase::OK, + ..todo!() + }) } +/// async fn set_limit( state: CupratedRpcHandler, request: SetLimitRequest, ) -> Result { - todo!() + Ok(SetLimitResponse { + base: ResponseBase::OK, + ..todo!() + }) } +/// async fn out_peers( state: CupratedRpcHandler, request: OutPeersRequest, ) -> Result { - todo!() + Ok(OutPeersResponse { + base: ResponseBase::OK, + ..todo!() + }) } +/// async fn in_peers( state: CupratedRpcHandler, request: InPeersRequest, ) -> Result { - todo!() + Ok(InPeersResponse { + base: ResponseBase::OK, + ..todo!() + }) } +/// async fn get_net_stats( state: CupratedRpcHandler, request: GetNetStatsRequest, ) -> Result { - todo!() + Ok(GetNetStatsResponse { + base: ResponseBase::OK, + ..todo!() + }) } +/// async fn get_outs( - state: CupratedRpcHandler, + mut state: CupratedRpcHandler, request: GetOutsRequest, ) -> Result { - todo!() + if state.is_restricted() && request.outputs.len() > MAX_RESTRICTED_GLOBAL_FAKE_OUTS_COUNT { + return Err(anyhow!("Too many outs requested")); + } + + let mut outputs = HashMap::>::with_capacity(request.outputs.len()); + for out in request.outputs { + outputs + .entry(out.amount) + .and_modify(|set| { + set.insert(out.index); + }) + .or_insert_with(|| HashSet::from([out.index])); + } + + let outs = blockchain::outputs(&mut state.blockchain_read, outputs) + .await? + .into_iter() + .flat_map(|(amount, index_map)| { + index_map.into_iter().map(|(index, out)| OutKey { + key: todo!(), + mask: todo!(), + unlocked: todo!(), + height: usize_to_u64(out.height), + txid: todo!(), + }) + }) + .collect::>(); + + // TODO: check txpool + + Ok(GetOutsResponse { + base: ResponseBase::OK, + outs, + }) } +/// async fn update( state: CupratedRpcHandler, request: UpdateRequest, ) -> Result { - todo!() + Ok(UpdateResponse { + base: ResponseBase::OK, + ..todo!() + }) } +/// async fn pop_blocks( - state: CupratedRpcHandler, + mut state: CupratedRpcHandler, request: PopBlocksRequest, ) -> Result { - todo!() + let height = + blockchain_manager::pop_blocks(&mut state.blockchain_manager, request.nblocks).await?; + + Ok(PopBlocksResponse { + base: ResponseBase::OK, + height, + }) } +/// async fn get_transaction_pool_hashes( state: CupratedRpcHandler, request: GetTransactionPoolHashesRequest, ) -> Result { - todo!() + Ok(GetTransactionPoolHashesResponse { + base: ResponseBase::OK, + ..todo!() + }) } +/// async fn get_public_nodes( state: CupratedRpcHandler, request: GetPublicNodesRequest, ) -> Result { - todo!() + Ok(GetPublicNodesResponse { + base: ResponseBase::OK, + ..todo!() + }) } diff --git a/rpc/types/src/misc/mod.rs b/rpc/types/src/misc/mod.rs index 4976756..026e9ae 100644 --- a/rpc/types/src/misc/mod.rs +++ b/rpc/types/src/misc/mod.rs @@ -19,6 +19,7 @@ mod key_image_spent_status; mod misc; mod pool_info; mod pool_info_extent; +mod requested_info; mod status; mod tx_entry; @@ -33,5 +34,6 @@ pub use misc::{ }; pub use pool_info::PoolInfo; pub use pool_info_extent::PoolInfoExtent; +pub use requested_info::RequestedInfo; pub use status::Status; pub use tx_entry::TxEntry; diff --git a/rpc/types/src/misc/requested_info.rs b/rpc/types/src/misc/requested_info.rs new file mode 100644 index 0000000..e594ced --- /dev/null +++ b/rpc/types/src/misc/requested_info.rs @@ -0,0 +1,86 @@ +//! TODO + +//---------------------------------------------------------------------------------------------------- Use +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +#[cfg(feature = "epee")] +use cuprate_epee_encoding::{ + error, + macros::bytes::{Buf, BufMut}, + EpeeValue, Marker, +}; + +//---------------------------------------------------------------------------------------------------- RequestedInfo +#[doc = crate::macros::monero_definition_link!( + cc73fe71162d564ffda8e549b79a350bca53c454, + "rpc/core_rpc_server_commands_defs.h", + 178..=183 +)] +/// Used in [`crate::bin::GetBlocksRequest`]. +#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[repr(u8)] +pub enum RequestedInfo { + #[default] + BlocksOnly = 0, + BlocksAndPool = 1, + PoolOnly = 2, +} + +impl RequestedInfo { + /// Convert [`Self`] to a [`u8`]. + /// + /// ```rust + /// use cuprate_rpc_types::misc::RequestedInfo as R; + /// + /// assert_eq!(R::BlocksOnly.to_u8(), 0); + /// assert_eq!(R::BlocksAndPool.to_u8(), 1); + /// assert_eq!(R::PoolOnly.to_u8(), 2); + /// ``` + pub const fn to_u8(self) -> u8 { + match self { + Self::BlocksOnly => 0, + Self::BlocksAndPool => 1, + Self::PoolOnly => 2, + } + } + + /// Convert a [`u8`] to a [`Self`]. + /// + /// # Errors + /// This returns [`None`] if `u > 2`. + /// + /// ```rust + /// use cuprate_rpc_types::misc::RequestedInfo as R; + /// + /// assert_eq!(R::from_u8(0), Some(R::BlocksOnly)); + /// assert_eq!(R::from_u8(1), Some(R::BlocksAndPool)); + /// assert_eq!(R::from_u8(2), Some(R::PoolOnly)); + /// assert_eq!(R::from_u8(3), None); + /// ``` + pub const fn from_u8(u: u8) -> Option { + Some(match u { + 0 => Self::BlocksOnly, + 1 => Self::BlocksAndPool, + 2 => Self::PoolOnly, + _ => return None, + }) + } +} + +#[cfg(feature = "epee")] +impl EpeeValue for RequestedInfo { + const MARKER: Marker = u8::MARKER; + + fn read(r: &mut B, marker: &Marker) -> error::Result { + let u = u8::read(r, marker)?; + Self::from_u8(u).ok_or(error::Error::Format("u8 was greater than 2")) + } + + fn write(self, w: &mut B) -> error::Result<()> { + let u = self.to_u8(); + u8::write(u, w)?; + Ok(()) + } +}