Compare commits

...

6 commits

Author SHA1 Message Date
hinto.janai
cb2f2f81fb
Merge branch 'main' into cast
Some checks are pending
Deny / audit (push) Waiting to run
2024-11-12 17:04:14 -05:00
5a5f88cb13
types: fix pruned BlockCompleteEntry (#338)
Some checks failed
Architecture mdBook / build (push) Has been cancelled
CI / fmt (push) Has been cancelled
CI / typo (push) Has been cancelled
CI / ci (macos-latest, stable, bash) (push) Has been cancelled
CI / ci (ubuntu-latest, stable, bash) (push) Has been cancelled
CI / ci (windows-latest, stable-x86_64-pc-windows-gnu, msys2 {0}) (push) Has been cancelled
Deny / audit (push) Has been cancelled
Doc / build (push) Has been cancelled
Doc / deploy (push) Has been cancelled
fix pruned `BlockCompleteEntry`
2024-11-11 23:16:08 +00:00
525e20e841
Fix ci and loosen version requirements (#335)
* add deny exception + loosen version requirements

* add a comment

* remove `expect`
2024-11-04 15:22:43 +00:00
SyntheticBird
b6c4adc83a
p2p: Implement P2P Bucket data structure (#329)
Implements P2P Bucket data structure

This commit implements a "Bucket" data structure that is a collection
of data that discriminates its items into "buckets" (vector of size N)
following a defined function.

- Implements Bucket data structure and Bucketable trait
- Implements Bucketable for Ipv4Addr
- Added the crate to the workspace dependencies
- Added arrayvec as a dependency
2024-11-02 00:45:56 +00:00
hinto-janai
372cab24d7
cuprated: internal signatures required for RPC pt. 2 (#320)
Some checks failed
CI / ci (macos-latest, stable, bash) (push) Has been cancelled
Audit / audit (push) Has been cancelled
CI / fmt (push) Has been cancelled
CI / typo (push) Has been cancelled
CI / ci (ubuntu-latest, stable, bash) (push) Has been cancelled
CI / ci (windows-latest, stable-x86_64-pc-windows-gnu, msys2 {0}) (push) Has been cancelled
Deny / audit (push) Has been cancelled
Doc / build (push) Has been cancelled
Doc / deploy (push) Has been cancelled
* apply diffs

* clippy

* fix tests

* rpc: fix tests

* remove `BlockchainManagerRequest::Overview`

* cuprated/p2p: fix `ConnectionInfo`

* move `CalculatePow`

* remove `AddAuxPow`

* move `Spans` and `NextNeededPruningSeed`

* factor types into `cuprate-types`

* scope cargo features

* fix/doc type serde

* Update binaries/cuprated/src/rpc/request/address_book.rs

Co-authored-by: Boog900 <boog900@tutanota.com>

* Update binaries/cuprated/src/rpc/request/blockchain_context.rs

Co-authored-by: Boog900 <boog900@tutanota.com>

* Update binaries/cuprated/src/rpc/request/blockchain_manager.rs

Co-authored-by: Boog900 <boog900@tutanota.com>

* fmt

* txpool: collapse `TxEntry`

* `ConnectionId`

* fix import

* fix bin

---------

Co-authored-by: Boog900 <boog900@tutanota.com>
2024-11-01 22:25:55 +00:00
44981f2b24
CI: add cargo hack (#170)
* add workflow

* fix errors

* fix workflow

* install dependencies

* fix more errors

* Update CONTRIBUTING.md

* Update CONTRIBUTING.md

Co-authored-by: hinto-janai <hinto.janai@protonmail.com>

* fix hack + enable it for cuprate-database

* move hack to main CI

* fix docs

* fix ci formatting

* fix txpool tests

* fix CONTRIBUTING.md formatting

* service -> tower::Service

* review fixes

* review fixes

* fix CI

---------

Co-authored-by: hinto-janai <hinto.janai@protonmail.com>
2024-11-01 20:22:14 +00:00
87 changed files with 1547 additions and 970 deletions

View file

@ -1,34 +0,0 @@
# This runs `cargo audit` on all dependencies (only if Cargo deps changed)
name: Audit
on:
push:
paths:
- '**/Cargo.toml'
- '**/Cargo.lock'
workflow_dispatch:
env:
CARGO_TERM_COLOR: always
jobs:
audit:
runs-on: ubuntu-latest
steps:
- name: Cache
uses: actions/cache@v4
with:
path: |
~/.cargo
target
key: audit
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install dependencies
run: cargo install cargo-audit --locked
- name: Audit
run: cargo audit

View file

@ -133,7 +133,12 @@ jobs:
- name: Test - name: Test
run: | run: |
cargo test --all-features --workspace cargo test --all-features --workspace
cargo test --package cuprate-blockchain --no-default-features --features redb --features service cargo test --package cuprate-blockchain --no-default-features --features redb
- name: Hack Check
run: |
cargo install cargo-hack --locked
cargo hack --workspace check --feature-powerset --no-dev-deps
# TODO: upload binaries with `actions/upload-artifact@v3` # TODO: upload binaries with `actions/upload-artifact@v3`
- name: Build - name: Build

View file

@ -121,11 +121,14 @@ Before pushing your code, please run the following at the root of the repository
After that, ensure all other CI passes by running: After that, ensure all other CI passes by running:
| Command | Does what | | Command | Does what |
|------------------------------------------------------------------------|-----------| |------------------------------------------------------------------------|-------------------------------------------------------------------------|
| `RUSTDOCFLAGS='-D warnings' cargo doc --workspace --all-features` | Checks documentation is OK | `RUSTDOCFLAGS='-D warnings' cargo doc --workspace --all-features` | Checks documentation is OK |
| `cargo clippy --workspace --all-features --all-targets -- -D warnings` | Checks clippy lints are satisfied | `cargo clippy --workspace --all-features --all-targets -- -D warnings` | Checks clippy lints are satisfied |
| `cargo test --all-features --workspace` | Runs all tests | `cargo test --all-features --workspace` | Runs all tests |
| `cargo build --all-features --all-targets --workspace` | Builds all code | `cargo build --all-features --all-targets --workspace` | Builds all code |
| `cargo hack --workspace check --feature-powerset --no-dev-deps` | Uses `cargo hack` to check our crates build with different features set |
`cargo hack` can be installed with `cargo` from: https://github.com/taiki-e/cargo-hack.
**Note: in order for some tests to work, you will need to place a [`monerod`](https://www.getmonero.org/downloads/) binary at the root of the repository.** **Note: in order for some tests to work, you will need to place a [`monerod`](https://www.getmonero.org/downloads/) binary at the root of the repository.**

587
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -16,6 +16,7 @@ members = [
"net/wire", "net/wire",
"p2p/p2p", "p2p/p2p",
"p2p/p2p-core", "p2p/p2p-core",
"p2p/bucket",
"p2p/dandelion-tower", "p2p/dandelion-tower",
"p2p/async-buffer", "p2p/async-buffer",
"p2p/address-book", "p2p/address-book",
@ -64,6 +65,7 @@ cuprate-levin = { path = "net/levin" ,default-feature
cuprate-wire = { path = "net/wire" ,default-features = false} cuprate-wire = { path = "net/wire" ,default-features = false}
cuprate-p2p = { path = "p2p/p2p" ,default-features = false} cuprate-p2p = { path = "p2p/p2p" ,default-features = false}
cuprate-p2p-core = { path = "p2p/p2p-core" ,default-features = false} cuprate-p2p-core = { path = "p2p/p2p-core" ,default-features = false}
cuprate-p2p-bucket = { path = "p2p/p2p-bucket" ,default-features = false}
cuprate-dandelion-tower = { path = "p2p/dandelion-tower" ,default-features = false} cuprate-dandelion-tower = { path = "p2p/dandelion-tower" ,default-features = false}
cuprate-async-buffer = { path = "p2p/async-buffer" ,default-features = false} cuprate-async-buffer = { path = "p2p/async-buffer" ,default-features = false}
cuprate-address-book = { path = "p2p/address-book" ,default-features = false} cuprate-address-book = { path = "p2p/address-book" ,default-features = false}
@ -79,54 +81,55 @@ cuprate-rpc-types = { path = "rpc/types" ,default-feature
cuprate-rpc-interface = { path = "rpc/interface" ,default-features = false} cuprate-rpc-interface = { path = "rpc/interface" ,default-features = false}
# External dependencies # External dependencies
anyhow = { version = "1.0.89", default-features = false } anyhow = { version = "1", default-features = false }
async-trait = { version = "0.1.82", default-features = false } arrayvec = { version = "0.7", default-features = false }
bitflags = { version = "2.6.0", default-features = false } async-trait = { version = "0.1", default-features = false }
bitflags = { version = "2", default-features = false }
blake3 = { version = "1", default-features = false } blake3 = { version = "1", default-features = false }
borsh = { version = "1.5.1", default-features = false } borsh = { version = "1", default-features = false }
bytemuck = { version = "1.18.0", default-features = false } bytemuck = { version = "1", default-features = false }
bytes = { version = "1.7.2", default-features = false } bytes = { version = "1", default-features = false }
cfg-if = { version = "1.0.0", default-features = false } cfg-if = { version = "1", default-features = false }
clap = { version = "4.5.17", default-features = false } clap = { version = "4", default-features = false }
chrono = { version = "0.4.38", default-features = false } chrono = { version = "0.4", default-features = false }
crypto-bigint = { version = "0.5.5", default-features = false } crypto-bigint = { version = "0.5", default-features = false }
crossbeam = { version = "0.8.4", default-features = false } crossbeam = { version = "0.8", default-features = false }
const_format = { version = "0.2.33", default-features = false } const_format = { version = "0.2", default-features = false }
curve25519-dalek = { version = "4.1.3", default-features = false } curve25519-dalek = { version = "4", default-features = false }
dashmap = { version = "5.5.3", default-features = false } dashmap = { version = "6", default-features = false }
dirs = { version = "5.0.1", default-features = false } dirs = { version = "5", default-features = false }
futures = { version = "0.3.30", default-features = false } futures = { version = "0.3", default-features = false }
hex = { version = "0.4.3", default-features = false } hex = { version = "0.4", default-features = false }
hex-literal = { version = "0.4", default-features = false } hex-literal = { version = "0.4", default-features = false }
indexmap = { version = "2.5.0", default-features = false } indexmap = { version = "2", default-features = false }
monero-serai = { git = "https://github.com/Cuprate/serai.git", rev = "d5205ce", default-features = false } monero-serai = { git = "https://github.com/Cuprate/serai.git", rev = "d5205ce", default-features = false }
paste = { version = "1.0.15", default-features = false } paste = { version = "1", default-features = false }
pin-project = { version = "1.1.5", default-features = false } pin-project = { version = "1", default-features = false }
randomx-rs = { git = "https://github.com/Cuprate/randomx-rs.git", rev = "0028464", default-features = false } randomx-rs = { git = "https://github.com/Cuprate/randomx-rs.git", rev = "0028464", default-features = false }
rand = { version = "0.8.5", default-features = false } rand = { version = "0.8", default-features = false }
rand_distr = { version = "0.4.3", default-features = false } rand_distr = { version = "0.4", default-features = false }
rayon = { version = "1.10.0", default-features = false } rayon = { version = "1", default-features = false }
serde_bytes = { version = "0.11.15", default-features = false } serde_bytes = { version = "0.11", default-features = false }
serde_json = { version = "1.0.128", default-features = false } serde_json = { version = "1", default-features = false }
serde = { version = "1.0.210", default-features = false } serde = { version = "1", default-features = false }
strum = { version = "0.26.3", default-features = false } strum = { version = "0.26", default-features = false }
thiserror = { version = "1.0.63", default-features = false } thiserror = { version = "1", default-features = false }
thread_local = { version = "1.1.8", default-features = false } thread_local = { version = "1", default-features = false }
tokio-util = { version = "0.7.12", default-features = false } tokio-util = { version = "0.7", default-features = false }
tokio-stream = { version = "0.1.16", default-features = false } tokio-stream = { version = "0.1", default-features = false }
tokio = { version = "1.40.0", default-features = false } tokio = { version = "1", default-features = false }
tower = { git = "https://github.com/Cuprate/tower.git", rev = "6c7faf0", default-features = false } # <https://github.com/tower-rs/tower/pull/796> tower = { git = "https://github.com/Cuprate/tower.git", rev = "6c7faf0", default-features = false } # <https://github.com/tower-rs/tower/pull/796>
tracing-subscriber = { version = "0.3.18", default-features = false } tracing-subscriber = { version = "0.3", default-features = false }
tracing = { version = "0.1.40", default-features = false } tracing = { version = "0.1", default-features = false }
## workspace.dev-dependencies ## workspace.dev-dependencies
monero-rpc = { git = "https://github.com/Cuprate/serai.git", rev = "d5205ce" } monero-rpc = { git = "https://github.com/Cuprate/serai.git", rev = "d5205ce" }
monero-simple-request-rpc = { git = "https://github.com/Cuprate/serai.git", rev = "d5205ce" } monero-simple-request-rpc = { git = "https://github.com/Cuprate/serai.git", rev = "d5205ce" }
tempfile = { version = "3" } tempfile = { version = "3" }
pretty_assertions = { version = "1.4.1" } pretty_assertions = { version = "1" }
proptest = { version = "1" } proptest = { version = "1" }
proptest-derive = { version = "0.4.0" } proptest-derive = { version = "0.5" }
tokio-test = { version = "0.4.4" } tokio-test = { version = "0.4" }
## TODO: ## TODO:
## Potential dependencies. ## Potential dependencies.

View file

@ -13,6 +13,7 @@ cuprate-consensus = { workspace = true }
cuprate-fast-sync = { workspace = true } cuprate-fast-sync = { workspace = true }
cuprate-consensus-context = { workspace = true } cuprate-consensus-context = { workspace = true }
cuprate-consensus-rules = { workspace = true } cuprate-consensus-rules = { workspace = true }
cuprate-constants = { workspace = true }
cuprate-cryptonight = { workspace = true } cuprate-cryptonight = { workspace = true }
cuprate-helper = { workspace = true } cuprate-helper = { workspace = true }
cuprate-epee-encoding = { workspace = true } cuprate-epee-encoding = { workspace = true }
@ -24,7 +25,7 @@ cuprate-p2p-core = { workspace = true }
cuprate-dandelion-tower = { workspace = true, features = ["txpool"] } cuprate-dandelion-tower = { workspace = true, features = ["txpool"] }
cuprate-async-buffer = { workspace = true } cuprate-async-buffer = { workspace = true }
cuprate-address-book = { workspace = true } cuprate-address-book = { workspace = true }
cuprate-blockchain = { workspace = true, features = ["service"] } cuprate-blockchain = { workspace = true }
cuprate-database-service = { workspace = true } cuprate-database-service = { workspace = true }
cuprate-txpool = { workspace = true } cuprate-txpool = { workspace = true }
cuprate-database = { workspace = true } cuprate-database = { workspace = true }

View file

@ -9,6 +9,10 @@
unused_variables, unused_variables,
clippy::needless_pass_by_value, clippy::needless_pass_by_value,
clippy::unused_async, clippy::unused_async,
clippy::diverging_sub_expression,
unused_mut,
clippy::let_unit_value,
clippy::needless_pass_by_ref_mut,
reason = "TODO: remove after v1.0.0" reason = "TODO: remove after v1.0.0"
)] )]

View file

@ -3,6 +3,7 @@
//! Will contain the code to initiate the RPC and a request handler. //! Will contain the code to initiate the RPC and a request handler.
mod bin; mod bin;
mod constants;
mod handler; mod handler;
mod json; mod json;
mod other; mod other;

View file

@ -0,0 +1,5 @@
//! Constants used within RPC.
/// The string message used in RPC response fields for when
/// `cuprated` does not support a field that `monerod` has.
pub(super) const FIELD_NOT_SUPPORTED: &str = "`cuprated` does not support this field.";

View file

@ -8,6 +8,8 @@ use monero_serai::block::Block;
use tower::Service; use tower::Service;
use cuprate_blockchain::service::{BlockchainReadHandle, BlockchainWriteHandle}; use cuprate_blockchain::service::{BlockchainReadHandle, BlockchainWriteHandle};
use cuprate_consensus::BlockChainContextService;
use cuprate_pruning::PruningSeed;
use cuprate_rpc_interface::RpcHandler; use cuprate_rpc_interface::RpcHandler;
use cuprate_rpc_types::{ use cuprate_rpc_types::{
bin::{BinRequest, BinResponse}, bin::{BinRequest, BinResponse},
@ -15,6 +17,7 @@ use cuprate_rpc_types::{
other::{OtherRequest, OtherResponse}, other::{OtherRequest, OtherResponse},
}; };
use cuprate_txpool::service::{TxpoolReadHandle, TxpoolWriteHandle}; use cuprate_txpool::service::{TxpoolReadHandle, TxpoolWriteHandle};
use cuprate_types::{AddAuxPow, AuxPow, HardFork};
use crate::rpc::{bin, json, other}; use crate::rpc::{bin, json, other};
@ -54,6 +57,32 @@ pub enum BlockchainManagerRequest {
/// The height of the next block in the chain. /// The height of the next block in the chain.
TargetHeight, TargetHeight,
/// Generate new blocks.
///
/// This request is only for regtest, see RPC's `generateblocks`.
GenerateBlocks {
/// Number of the blocks to be generated.
amount_of_blocks: u64,
/// The previous block's hash.
prev_block: [u8; 32],
/// The starting value for the nonce.
starting_nonce: u32,
/// The address that will receive the coinbase reward.
wallet_address: String,
},
// // TODO: the below requests actually belong to the block downloader/syncer:
// // <https://github.com/Cuprate/cuprate/pull/320#discussion_r1811089758>
// /// Get [`Span`] data.
// ///
// /// This is data that describes an active downloading process,
// /// if we are fully synced, this will return an empty [`Vec`].
// Spans,
//
/// Get the next [`PruningSeed`] needed for a pruned sync.
NextNeededPruningSeed,
} }
/// TODO: use real type when public. /// TODO: use real type when public.
@ -69,6 +98,9 @@ pub enum BlockchainManagerResponse {
/// Response to [`BlockchainManagerRequest::PopBlocks`] /// Response to [`BlockchainManagerRequest::PopBlocks`]
PopBlocks { new_height: usize }, PopBlocks { new_height: usize },
/// Response to [`BlockchainManagerRequest::Prune`]
Prune(PruningSeed),
/// Response to [`BlockchainManagerRequest::Pruned`] /// Response to [`BlockchainManagerRequest::Pruned`]
Pruned(bool), Pruned(bool),
@ -83,6 +115,19 @@ pub enum BlockchainManagerResponse {
/// Response to [`BlockchainManagerRequest::TargetHeight`] /// Response to [`BlockchainManagerRequest::TargetHeight`]
TargetHeight { height: usize }, TargetHeight { height: usize },
/// Response to [`BlockchainManagerRequest::GenerateBlocks`]
GenerateBlocks {
/// Hashes of the blocks generated.
blocks: Vec<[u8; 32]>,
/// The new top height. (TODO: is this correct?)
height: usize,
},
// /// Response to [`BlockchainManagerRequest::Spans`].
// Spans(Vec<Span<Z::Addr>>),
/// Response to [`BlockchainManagerRequest::NextNeededPruningSeed`].
NextNeededPruningSeed(PruningSeed),
} }
/// TODO: use real type when public. /// TODO: use real type when public.
@ -102,6 +147,9 @@ pub struct CupratedRpcHandler {
/// Read handle to the blockchain database. /// Read handle to the blockchain database.
pub blockchain_read: BlockchainReadHandle, pub blockchain_read: BlockchainReadHandle,
/// Handle to the blockchain context service.
pub blockchain_context: BlockChainContextService,
/// Handle to the blockchain manager. /// Handle to the blockchain manager.
pub blockchain_manager: BlockchainManagerHandle, pub blockchain_manager: BlockchainManagerHandle,
@ -117,6 +165,7 @@ impl CupratedRpcHandler {
pub const fn new( pub const fn new(
restricted: bool, restricted: bool,
blockchain_read: BlockchainReadHandle, blockchain_read: BlockchainReadHandle,
blockchain_context: BlockChainContextService,
blockchain_manager: BlockchainManagerHandle, blockchain_manager: BlockchainManagerHandle,
txpool_read: TxpoolReadHandle, txpool_read: TxpoolReadHandle,
txpool_manager: std::convert::Infallible, txpool_manager: std::convert::Infallible,
@ -124,6 +173,7 @@ impl CupratedRpcHandler {
Self { Self {
restricted, restricted,
blockchain_read, blockchain_read,
blockchain_context,
blockchain_manager, blockchain_manager,
txpool_read, txpool_read,
txpool_manager, txpool_manager,

View file

@ -2,26 +2,33 @@
use std::convert::Infallible; use std::convert::Infallible;
use anyhow::Error; use anyhow::{anyhow, Error};
use tower::ServiceExt; use tower::ServiceExt;
use cuprate_helper::cast::usize_to_u64; use cuprate_helper::cast::usize_to_u64;
use cuprate_p2p_core::{ use cuprate_p2p_core::{
services::{AddressBookRequest, AddressBookResponse}, services::{AddressBookRequest, AddressBookResponse},
types::{BanState, ConnectionId},
AddressBook, NetworkZone, AddressBook, NetworkZone,
}; };
use cuprate_pruning::PruningSeed;
use cuprate_rpc_types::misc::{ConnectionInfo, Span};
use crate::rpc::constants::FIELD_NOT_SUPPORTED;
// FIXME: use `anyhow::Error` over `tower::BoxError` in address book.
/// [`AddressBookRequest::PeerlistSize`] /// [`AddressBookRequest::PeerlistSize`]
pub(super) async fn peerlist_size<Z: NetworkZone>( pub(crate) async fn peerlist_size<Z: NetworkZone>(
address_book: &mut impl AddressBook<Z>, address_book: &mut impl AddressBook<Z>,
) -> Result<(u64, u64), Error> { ) -> Result<(u64, u64), Error> {
let AddressBookResponse::PeerlistSize { white, grey } = address_book let AddressBookResponse::PeerlistSize { white, grey } = address_book
.ready() .ready()
.await .await
.expect("TODO") .map_err(|e| anyhow!(e))?
.call(AddressBookRequest::PeerlistSize) .call(AddressBookRequest::PeerlistSize)
.await .await
.expect("TODO") .map_err(|e| anyhow!(e))?
else { else {
unreachable!(); unreachable!();
}; };
@ -29,17 +36,74 @@ pub(super) async fn peerlist_size<Z: NetworkZone>(
Ok((usize_to_u64(white), usize_to_u64(grey))) Ok((usize_to_u64(white), usize_to_u64(grey)))
} }
/// [`AddressBookRequest::ConnectionInfo`]
pub(crate) async fn connection_info<Z: NetworkZone>(
address_book: &mut impl AddressBook<Z>,
) -> Result<Vec<ConnectionInfo>, Error> {
let AddressBookResponse::ConnectionInfo(vec) = address_book
.ready()
.await
.map_err(|e| anyhow!(e))?
.call(AddressBookRequest::ConnectionInfo)
.await
.map_err(|e| anyhow!(e))?
else {
unreachable!();
};
// FIXME: impl this map somewhere instead of inline.
let vec = vec
.into_iter()
.map(|info| {
let (ip, port) = match info.socket_addr {
Some(socket) => (socket.ip().to_string(), socket.port().to_string()),
None => (String::new(), String::new()),
};
ConnectionInfo {
address: info.address.to_string(),
address_type: info.address_type,
avg_download: info.avg_download,
avg_upload: info.avg_upload,
connection_id: String::from(ConnectionId::DEFAULT_STR),
current_download: info.current_download,
current_upload: info.current_upload,
height: info.height,
host: info.host,
incoming: info.incoming,
ip,
live_time: info.live_time,
localhost: info.localhost,
local_ip: info.local_ip,
peer_id: hex::encode(info.peer_id.to_ne_bytes()),
port,
pruning_seed: info.pruning_seed.compress(),
recv_count: info.recv_count,
recv_idle_time: info.recv_idle_time,
rpc_credits_per_hash: info.rpc_credits_per_hash,
rpc_port: info.rpc_port,
send_count: info.send_count,
send_idle_time: info.send_idle_time,
state: info.state,
support_flags: info.support_flags,
}
})
.collect();
Ok(vec)
}
/// [`AddressBookRequest::ConnectionCount`] /// [`AddressBookRequest::ConnectionCount`]
pub(super) async fn connection_count<Z: NetworkZone>( pub(crate) async fn connection_count<Z: NetworkZone>(
address_book: &mut impl AddressBook<Z>, address_book: &mut impl AddressBook<Z>,
) -> Result<(u64, u64), Error> { ) -> Result<(u64, u64), Error> {
let AddressBookResponse::ConnectionCount { incoming, outgoing } = address_book let AddressBookResponse::ConnectionCount { incoming, outgoing } = address_book
.ready() .ready()
.await .await
.expect("TODO") .map_err(|e| anyhow!(e))?
.call(AddressBookRequest::ConnectionCount) .call(AddressBookRequest::ConnectionCount)
.await .await
.expect("TODO") .map_err(|e| anyhow!(e))?
else { else {
unreachable!(); unreachable!();
}; };
@ -48,17 +112,17 @@ pub(super) async fn connection_count<Z: NetworkZone>(
} }
/// [`AddressBookRequest::SetBan`] /// [`AddressBookRequest::SetBan`]
pub(super) async fn set_ban<Z: NetworkZone>( pub(crate) async fn set_ban<Z: NetworkZone>(
address_book: &mut impl AddressBook<Z>, address_book: &mut impl AddressBook<Z>,
peer: cuprate_p2p_core::ban::SetBan<Z::Addr>, set_ban: cuprate_p2p_core::types::SetBan<Z::Addr>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let AddressBookResponse::Ok = address_book let AddressBookResponse::Ok = address_book
.ready() .ready()
.await .await
.expect("TODO") .map_err(|e| anyhow!(e))?
.call(AddressBookRequest::SetBan(peer)) .call(AddressBookRequest::SetBan(set_ban))
.await .await
.expect("TODO") .map_err(|e| anyhow!(e))?
else { else {
unreachable!(); unreachable!();
}; };
@ -67,17 +131,17 @@ pub(super) async fn set_ban<Z: NetworkZone>(
} }
/// [`AddressBookRequest::GetBan`] /// [`AddressBookRequest::GetBan`]
pub(super) async fn get_ban<Z: NetworkZone>( pub(crate) async fn get_ban<Z: NetworkZone>(
address_book: &mut impl AddressBook<Z>, address_book: &mut impl AddressBook<Z>,
peer: Z::Addr, peer: Z::Addr,
) -> Result<Option<std::time::Instant>, Error> { ) -> Result<Option<std::time::Instant>, Error> {
let AddressBookResponse::GetBan { unban_instant } = address_book let AddressBookResponse::GetBan { unban_instant } = address_book
.ready() .ready()
.await .await
.expect("TODO") .map_err(|e| anyhow!(e))?
.call(AddressBookRequest::GetBan(peer)) .call(AddressBookRequest::GetBan(peer))
.await .await
.expect("TODO") .map_err(|e| anyhow!(e))?
else { else {
unreachable!(); unreachable!();
}; };
@ -86,19 +150,19 @@ pub(super) async fn get_ban<Z: NetworkZone>(
} }
/// [`AddressBookRequest::GetBans`] /// [`AddressBookRequest::GetBans`]
pub(super) async fn get_bans<Z: NetworkZone>( pub(crate) async fn get_bans<Z: NetworkZone>(
address_book: &mut impl AddressBook<Z>, address_book: &mut impl AddressBook<Z>,
) -> Result<(), Error> { ) -> Result<Vec<BanState<Z::Addr>>, Error> {
let AddressBookResponse::GetBans(bans) = address_book let AddressBookResponse::GetBans(bans) = address_book
.ready() .ready()
.await .await
.expect("TODO") .map_err(|e| anyhow!(e))?
.call(AddressBookRequest::GetBans) .call(AddressBookRequest::GetBans)
.await .await
.expect("TODO") .map_err(|e| anyhow!(e))?
else { else {
unreachable!(); unreachable!();
}; };
Ok(todo!()) Ok(bans)
} }

View file

@ -1,24 +1,61 @@
//! Functions for [`BlockchainReadRequest`]. //! Functions for [`BlockchainReadRequest`].
use std::{ use std::{
collections::{HashMap, HashSet}, collections::{BTreeMap, HashMap, HashSet},
ops::Range, ops::Range,
}; };
use anyhow::Error; use anyhow::Error;
use cuprate_blockchain::service::BlockchainReadHandle; use monero_serai::block::Block;
use tower::{Service, ServiceExt}; use tower::{Service, ServiceExt};
use cuprate_blockchain::{service::BlockchainReadHandle, types::AltChainInfo};
use cuprate_helper::cast::{u64_to_usize, usize_to_u64}; use cuprate_helper::cast::{u64_to_usize, usize_to_u64};
use cuprate_types::{ use cuprate_types::{
blockchain::{BlockchainReadRequest, BlockchainResponse}, blockchain::{BlockchainReadRequest, BlockchainResponse},
Chain, CoinbaseTxSum, ExtendedBlockHeader, MinerData, OutputHistogramEntry, Chain, ChainInfo, CoinbaseTxSum, ExtendedBlockHeader, HardFork, MinerData,
OutputHistogramInput, OutputOnChain, OutputHistogramEntry, OutputHistogramInput, OutputOnChain,
}; };
/// [`BlockchainReadRequest::Block`].
pub(crate) async fn block(
blockchain_read: &mut BlockchainReadHandle,
height: u64,
) -> Result<Block, Error> {
let BlockchainResponse::Block(block) = blockchain_read
.ready()
.await?
.call(BlockchainReadRequest::Block {
height: u64_to_usize(height),
})
.await?
else {
unreachable!();
};
Ok(block)
}
/// [`BlockchainReadRequest::BlockByHash`].
pub(crate) async fn block_by_hash(
blockchain_read: &mut BlockchainReadHandle,
hash: [u8; 32],
) -> Result<Block, Error> {
let BlockchainResponse::Block(block) = blockchain_read
.ready()
.await?
.call(BlockchainReadRequest::BlockByHash(hash))
.await?
else {
unreachable!();
};
Ok(block)
}
/// [`BlockchainReadRequest::BlockExtendedHeader`]. /// [`BlockchainReadRequest::BlockExtendedHeader`].
pub(super) async fn block_extended_header( pub(crate) async fn block_extended_header(
mut blockchain_read: BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
height: u64, height: u64,
) -> Result<ExtendedBlockHeader, Error> { ) -> Result<ExtendedBlockHeader, Error> {
let BlockchainResponse::BlockExtendedHeader(header) = blockchain_read let BlockchainResponse::BlockExtendedHeader(header) = blockchain_read
@ -36,8 +73,8 @@ pub(super) async fn block_extended_header(
} }
/// [`BlockchainReadRequest::BlockHash`]. /// [`BlockchainReadRequest::BlockHash`].
pub(super) async fn block_hash( pub(crate) async fn block_hash(
mut blockchain_read: BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
height: u64, height: u64,
chain: Chain, chain: Chain,
) -> Result<[u8; 32], Error> { ) -> Result<[u8; 32], Error> {
@ -57,8 +94,8 @@ pub(super) async fn block_hash(
} }
/// [`BlockchainReadRequest::FindBlock`]. /// [`BlockchainReadRequest::FindBlock`].
pub(super) async fn find_block( pub(crate) async fn find_block(
mut blockchain_read: BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
block_hash: [u8; 32], block_hash: [u8; 32],
) -> Result<Option<(Chain, usize)>, Error> { ) -> Result<Option<(Chain, usize)>, Error> {
let BlockchainResponse::FindBlock(option) = blockchain_read let BlockchainResponse::FindBlock(option) = blockchain_read
@ -74,8 +111,8 @@ pub(super) async fn find_block(
} }
/// [`BlockchainReadRequest::FilterUnknownHashes`]. /// [`BlockchainReadRequest::FilterUnknownHashes`].
pub(super) async fn filter_unknown_hashes( pub(crate) async fn filter_unknown_hashes(
mut blockchain_read: BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
block_hashes: HashSet<[u8; 32]>, block_hashes: HashSet<[u8; 32]>,
) -> Result<HashSet<[u8; 32]>, Error> { ) -> Result<HashSet<[u8; 32]>, Error> {
let BlockchainResponse::FilterUnknownHashes(output) = blockchain_read let BlockchainResponse::FilterUnknownHashes(output) = blockchain_read
@ -91,8 +128,8 @@ pub(super) async fn filter_unknown_hashes(
} }
/// [`BlockchainReadRequest::BlockExtendedHeaderInRange`] /// [`BlockchainReadRequest::BlockExtendedHeaderInRange`]
pub(super) async fn block_extended_header_in_range( pub(crate) async fn block_extended_header_in_range(
mut blockchain_read: BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
range: Range<usize>, range: Range<usize>,
chain: Chain, chain: Chain,
) -> Result<Vec<ExtendedBlockHeader>, Error> { ) -> Result<Vec<ExtendedBlockHeader>, Error> {
@ -111,8 +148,8 @@ pub(super) async fn block_extended_header_in_range(
} }
/// [`BlockchainReadRequest::ChainHeight`]. /// [`BlockchainReadRequest::ChainHeight`].
pub(super) async fn chain_height( pub(crate) async fn chain_height(
mut blockchain_read: BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
) -> Result<(u64, [u8; 32]), Error> { ) -> Result<(u64, [u8; 32]), Error> {
let BlockchainResponse::ChainHeight(height, hash) = blockchain_read let BlockchainResponse::ChainHeight(height, hash) = blockchain_read
.ready() .ready()
@ -127,8 +164,8 @@ pub(super) async fn chain_height(
} }
/// [`BlockchainReadRequest::GeneratedCoins`]. /// [`BlockchainReadRequest::GeneratedCoins`].
pub(super) async fn generated_coins( pub(crate) async fn generated_coins(
mut blockchain_read: BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
block_height: u64, block_height: u64,
) -> Result<u64, Error> { ) -> Result<u64, Error> {
let BlockchainResponse::GeneratedCoins(generated_coins) = blockchain_read let BlockchainResponse::GeneratedCoins(generated_coins) = blockchain_read
@ -146,8 +183,8 @@ pub(super) async fn generated_coins(
} }
/// [`BlockchainReadRequest::Outputs`] /// [`BlockchainReadRequest::Outputs`]
pub(super) async fn outputs( pub(crate) async fn outputs(
mut blockchain_read: BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
outputs: HashMap<u64, HashSet<u64>>, outputs: HashMap<u64, HashSet<u64>>,
) -> Result<HashMap<u64, HashMap<u64, OutputOnChain>>, Error> { ) -> Result<HashMap<u64, HashMap<u64, OutputOnChain>>, Error> {
let BlockchainResponse::Outputs(outputs) = blockchain_read let BlockchainResponse::Outputs(outputs) = blockchain_read
@ -163,8 +200,8 @@ pub(super) async fn outputs(
} }
/// [`BlockchainReadRequest::NumberOutputsWithAmount`] /// [`BlockchainReadRequest::NumberOutputsWithAmount`]
pub(super) async fn number_outputs_with_amount( pub(crate) async fn number_outputs_with_amount(
mut blockchain_read: BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
output_amounts: Vec<u64>, output_amounts: Vec<u64>,
) -> Result<HashMap<u64, usize>, Error> { ) -> Result<HashMap<u64, usize>, Error> {
let BlockchainResponse::NumberOutputsWithAmount(map) = blockchain_read let BlockchainResponse::NumberOutputsWithAmount(map) = blockchain_read
@ -182,8 +219,8 @@ pub(super) async fn number_outputs_with_amount(
} }
/// [`BlockchainReadRequest::KeyImagesSpent`] /// [`BlockchainReadRequest::KeyImagesSpent`]
pub(super) async fn key_images_spent( pub(crate) async fn key_images_spent(
mut blockchain_read: BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
key_images: HashSet<[u8; 32]>, key_images: HashSet<[u8; 32]>,
) -> Result<bool, Error> { ) -> Result<bool, Error> {
let BlockchainResponse::KeyImagesSpent(is_spent) = blockchain_read let BlockchainResponse::KeyImagesSpent(is_spent) = blockchain_read
@ -199,8 +236,8 @@ pub(super) async fn key_images_spent(
} }
/// [`BlockchainReadRequest::CompactChainHistory`] /// [`BlockchainReadRequest::CompactChainHistory`]
pub(super) async fn compact_chain_history( pub(crate) async fn compact_chain_history(
mut blockchain_read: BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
) -> Result<(Vec<[u8; 32]>, u128), Error> { ) -> Result<(Vec<[u8; 32]>, u128), Error> {
let BlockchainResponse::CompactChainHistory { let BlockchainResponse::CompactChainHistory {
block_ids, block_ids,
@ -218,8 +255,8 @@ pub(super) async fn compact_chain_history(
} }
/// [`BlockchainReadRequest::FindFirstUnknown`] /// [`BlockchainReadRequest::FindFirstUnknown`]
pub(super) async fn find_first_unknown( pub(crate) async fn find_first_unknown(
mut blockchain_read: BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
hashes: Vec<[u8; 32]>, hashes: Vec<[u8; 32]>,
) -> Result<Option<(usize, u64)>, Error> { ) -> Result<Option<(usize, u64)>, Error> {
let BlockchainResponse::FindFirstUnknown(resp) = blockchain_read let BlockchainResponse::FindFirstUnknown(resp) = blockchain_read
@ -235,8 +272,8 @@ pub(super) async fn find_first_unknown(
} }
/// [`BlockchainReadRequest::TotalTxCount`] /// [`BlockchainReadRequest::TotalTxCount`]
pub(super) async fn total_tx_count( pub(crate) async fn total_tx_count(
mut blockchain_read: BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
) -> Result<u64, Error> { ) -> Result<u64, Error> {
let BlockchainResponse::TotalTxCount(tx_count) = blockchain_read let BlockchainResponse::TotalTxCount(tx_count) = blockchain_read
.ready() .ready()
@ -251,8 +288,8 @@ pub(super) async fn total_tx_count(
} }
/// [`BlockchainReadRequest::DatabaseSize`] /// [`BlockchainReadRequest::DatabaseSize`]
pub(super) async fn database_size( pub(crate) async fn database_size(
mut blockchain_read: BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
) -> Result<(u64, u64), Error> { ) -> Result<(u64, u64), Error> {
let BlockchainResponse::DatabaseSize { let BlockchainResponse::DatabaseSize {
database_size, database_size,
@ -270,8 +307,8 @@ pub(super) async fn database_size(
} }
/// [`BlockchainReadRequest::OutputHistogram`] /// [`BlockchainReadRequest::OutputHistogram`]
pub(super) async fn output_histogram( pub(crate) async fn output_histogram(
mut blockchain_read: BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
input: OutputHistogramInput, input: OutputHistogramInput,
) -> Result<Vec<OutputHistogramEntry>, Error> { ) -> Result<Vec<OutputHistogramEntry>, Error> {
let BlockchainResponse::OutputHistogram(histogram) = blockchain_read let BlockchainResponse::OutputHistogram(histogram) = blockchain_read
@ -287,8 +324,8 @@ pub(super) async fn output_histogram(
} }
/// [`BlockchainReadRequest::CoinbaseTxSum`] /// [`BlockchainReadRequest::CoinbaseTxSum`]
pub(super) async fn coinbase_tx_sum( pub(crate) async fn coinbase_tx_sum(
mut blockchain_read: BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
height: u64, height: u64,
count: u64, count: u64,
) -> Result<CoinbaseTxSum, Error> { ) -> Result<CoinbaseTxSum, Error> {
@ -306,3 +343,35 @@ pub(super) async fn coinbase_tx_sum(
Ok(sum) Ok(sum)
} }
/// [`BlockchainReadRequest::AltChains`]
pub(crate) async fn alt_chains(
blockchain_read: &mut BlockchainReadHandle,
) -> Result<Vec<ChainInfo>, Error> {
let BlockchainResponse::AltChains(vec) = blockchain_read
.ready()
.await?
.call(BlockchainReadRequest::AltChains)
.await?
else {
unreachable!();
};
Ok(vec)
}
/// [`BlockchainReadRequest::AltChainCount`]
pub(crate) async fn alt_chain_count(
blockchain_read: &mut BlockchainReadHandle,
) -> Result<u64, Error> {
let BlockchainResponse::AltChainCount(count) = blockchain_read
.ready()
.await?
.call(BlockchainReadRequest::AltChainCount)
.await?
else {
unreachable!();
};
Ok(usize_to_u64(count))
}

View file

@ -2,27 +2,30 @@
use std::convert::Infallible; use std::convert::Infallible;
use anyhow::Error; use anyhow::{anyhow, Error};
use monero_serai::block::Block;
use tower::{Service, ServiceExt}; use tower::{Service, ServiceExt};
use cuprate_consensus_context::{ use cuprate_consensus_context::{
BlockChainContext, BlockChainContextRequest, BlockChainContextResponse, BlockChainContext, BlockChainContextRequest, BlockChainContextResponse,
BlockChainContextService, BlockChainContextService,
}; };
use cuprate_helper::cast::u64_to_usize;
use cuprate_types::{FeeEstimate, HardFork, HardForkInfo}; use cuprate_types::{FeeEstimate, HardFork, HardForkInfo};
// FIXME: use `anyhow::Error` over `tower::BoxError` in blockchain context.
/// [`BlockChainContextRequest::Context`]. /// [`BlockChainContextRequest::Context`].
pub(super) async fn context( pub(crate) async fn context(
service: &mut BlockChainContextService, blockchain_context: &mut BlockChainContextService,
height: u64,
) -> Result<BlockChainContext, Error> { ) -> Result<BlockChainContext, Error> {
let BlockChainContextResponse::Context(context) = service let BlockChainContextResponse::Context(context) = blockchain_context
.ready() .ready()
.await .await
.expect("TODO") .map_err(|e| anyhow!(e))?
.call(BlockChainContextRequest::Context) .call(BlockChainContextRequest::Context)
.await .await
.expect("TODO") .map_err(|e| anyhow!(e))?
else { else {
unreachable!(); unreachable!();
}; };
@ -31,17 +34,17 @@ pub(super) async fn context(
} }
/// [`BlockChainContextRequest::HardForkInfo`]. /// [`BlockChainContextRequest::HardForkInfo`].
pub(super) async fn hard_fork_info( pub(crate) async fn hard_fork_info(
service: &mut BlockChainContextService, blockchain_context: &mut BlockChainContextService,
hard_fork: HardFork, hard_fork: HardFork,
) -> Result<HardForkInfo, Error> { ) -> Result<HardForkInfo, Error> {
let BlockChainContextResponse::HardForkInfo(hf_info) = service let BlockChainContextResponse::HardForkInfo(hf_info) = blockchain_context
.ready() .ready()
.await .await
.expect("TODO") .map_err(|e| anyhow!(e))?
.call(BlockChainContextRequest::HardForkInfo(hard_fork)) .call(BlockChainContextRequest::HardForkInfo(hard_fork))
.await .await
.expect("TODO") .map_err(|e| anyhow!(e))?
else { else {
unreachable!(); unreachable!();
}; };
@ -50,20 +53,47 @@ pub(super) async fn hard_fork_info(
} }
/// [`BlockChainContextRequest::FeeEstimate`]. /// [`BlockChainContextRequest::FeeEstimate`].
pub(super) async fn fee_estimate( pub(crate) async fn fee_estimate(
service: &mut BlockChainContextService, blockchain_context: &mut BlockChainContextService,
grace_blocks: u64, grace_blocks: u64,
) -> Result<FeeEstimate, Error> { ) -> Result<FeeEstimate, Error> {
let BlockChainContextResponse::FeeEstimate(fee) = service let BlockChainContextResponse::FeeEstimate(fee) = blockchain_context
.ready() .ready()
.await .await
.expect("TODO") .map_err(|e| anyhow!(e))?
.call(BlockChainContextRequest::FeeEstimate { grace_blocks }) .call(BlockChainContextRequest::FeeEstimate { grace_blocks })
.await .await
.expect("TODO") .map_err(|e| anyhow!(e))?
else { else {
unreachable!(); unreachable!();
}; };
Ok(fee) Ok(fee)
} }
/// [`BlockChainContextRequest::CalculatePow`]
pub(crate) async fn calculate_pow(
blockchain_context: &mut BlockChainContextService,
hardfork: HardFork,
height: u64,
block: Box<Block>,
seed_hash: [u8; 32],
) -> Result<[u8; 32], Error> {
let BlockChainContextResponse::CalculatePow(hash) = blockchain_context
.ready()
.await
.map_err(|e| anyhow!(e))?
.call(BlockChainContextRequest::CalculatePow {
hardfork,
height: u64_to_usize(height),
block,
seed_hash,
})
.await
.map_err(|e| anyhow!(e))?
else {
unreachable!();
};
Ok(hash)
}

View file

@ -5,13 +5,18 @@ use monero_serai::block::Block;
use tower::{Service, ServiceExt}; use tower::{Service, ServiceExt};
use cuprate_helper::cast::{u64_to_usize, usize_to_u64}; use cuprate_helper::cast::{u64_to_usize, usize_to_u64};
use cuprate_p2p_core::{types::ConnectionId, NetworkZone};
use cuprate_pruning::PruningSeed;
use cuprate_rpc_types::misc::Span;
use cuprate_types::{AddAuxPow, AuxPow, HardFork};
use crate::rpc::handler::{ use crate::rpc::{
BlockchainManagerHandle, BlockchainManagerRequest, BlockchainManagerResponse, constants::FIELD_NOT_SUPPORTED,
handler::{BlockchainManagerHandle, BlockchainManagerRequest, BlockchainManagerResponse},
}; };
/// [`BlockchainManagerRequest::PopBlocks`] /// [`BlockchainManagerRequest::PopBlocks`]
pub(super) async fn pop_blocks( pub(crate) async fn pop_blocks(
blockchain_manager: &mut BlockchainManagerHandle, blockchain_manager: &mut BlockchainManagerHandle,
amount: u64, amount: u64,
) -> Result<u64, Error> { ) -> Result<u64, Error> {
@ -30,8 +35,10 @@ pub(super) async fn pop_blocks(
} }
/// [`BlockchainManagerRequest::Prune`] /// [`BlockchainManagerRequest::Prune`]
pub(super) async fn prune(blockchain_manager: &mut BlockchainManagerHandle) -> Result<(), Error> { pub(crate) async fn prune(
let BlockchainManagerResponse::Ok = blockchain_manager blockchain_manager: &mut BlockchainManagerHandle,
) -> Result<PruningSeed, Error> {
let BlockchainManagerResponse::Prune(seed) = blockchain_manager
.ready() .ready()
.await? .await?
.call(BlockchainManagerRequest::Prune) .call(BlockchainManagerRequest::Prune)
@ -40,11 +47,11 @@ pub(super) async fn prune(blockchain_manager: &mut BlockchainManagerHandle) -> R
unreachable!(); unreachable!();
}; };
Ok(()) Ok(seed)
} }
/// [`BlockchainManagerRequest::Pruned`] /// [`BlockchainManagerRequest::Pruned`]
pub(super) async fn pruned( pub(crate) async fn pruned(
blockchain_manager: &mut BlockchainManagerHandle, blockchain_manager: &mut BlockchainManagerHandle,
) -> Result<bool, Error> { ) -> Result<bool, Error> {
let BlockchainManagerResponse::Pruned(pruned) = blockchain_manager let BlockchainManagerResponse::Pruned(pruned) = blockchain_manager
@ -60,7 +67,7 @@ pub(super) async fn pruned(
} }
/// [`BlockchainManagerRequest::RelayBlock`] /// [`BlockchainManagerRequest::RelayBlock`]
pub(super) async fn relay_block( pub(crate) async fn relay_block(
blockchain_manager: &mut BlockchainManagerHandle, blockchain_manager: &mut BlockchainManagerHandle,
block: Block, block: Block,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -77,7 +84,7 @@ pub(super) async fn relay_block(
} }
/// [`BlockchainManagerRequest::Syncing`] /// [`BlockchainManagerRequest::Syncing`]
pub(super) async fn syncing( pub(crate) async fn syncing(
blockchain_manager: &mut BlockchainManagerHandle, blockchain_manager: &mut BlockchainManagerHandle,
) -> Result<bool, Error> { ) -> Result<bool, Error> {
let BlockchainManagerResponse::Syncing(syncing) = blockchain_manager let BlockchainManagerResponse::Syncing(syncing) = blockchain_manager
@ -93,7 +100,7 @@ pub(super) async fn syncing(
} }
/// [`BlockchainManagerRequest::Synced`] /// [`BlockchainManagerRequest::Synced`]
pub(super) async fn synced( pub(crate) async fn synced(
blockchain_manager: &mut BlockchainManagerHandle, blockchain_manager: &mut BlockchainManagerHandle,
) -> Result<bool, Error> { ) -> Result<bool, Error> {
let BlockchainManagerResponse::Synced(syncing) = blockchain_manager let BlockchainManagerResponse::Synced(syncing) = blockchain_manager
@ -109,7 +116,7 @@ pub(super) async fn synced(
} }
/// [`BlockchainManagerRequest::Target`] /// [`BlockchainManagerRequest::Target`]
pub(super) async fn target( pub(crate) async fn target(
blockchain_manager: &mut BlockchainManagerHandle, blockchain_manager: &mut BlockchainManagerHandle,
) -> Result<std::time::Duration, Error> { ) -> Result<std::time::Duration, Error> {
let BlockchainManagerResponse::Target(target) = blockchain_manager let BlockchainManagerResponse::Target(target) = blockchain_manager
@ -125,7 +132,7 @@ pub(super) async fn target(
} }
/// [`BlockchainManagerRequest::TargetHeight`] /// [`BlockchainManagerRequest::TargetHeight`]
pub(super) async fn target_height( pub(crate) async fn target_height(
blockchain_manager: &mut BlockchainManagerHandle, blockchain_manager: &mut BlockchainManagerHandle,
) -> Result<u64, Error> { ) -> Result<u64, Error> {
let BlockchainManagerResponse::TargetHeight { height } = blockchain_manager let BlockchainManagerResponse::TargetHeight { height } = blockchain_manager
@ -139,3 +146,76 @@ pub(super) async fn target_height(
Ok(usize_to_u64(height)) Ok(usize_to_u64(height))
} }
/// [`BlockchainManagerRequest::GenerateBlocks`]
pub(crate) async fn generate_blocks(
blockchain_manager: &mut BlockchainManagerHandle,
amount_of_blocks: u64,
prev_block: [u8; 32],
starting_nonce: u32,
wallet_address: String,
) -> Result<(Vec<[u8; 32]>, u64), Error> {
let BlockchainManagerResponse::GenerateBlocks { blocks, height } = blockchain_manager
.ready()
.await?
.call(BlockchainManagerRequest::GenerateBlocks {
amount_of_blocks,
prev_block,
starting_nonce,
wallet_address,
})
.await?
else {
unreachable!();
};
Ok((blocks, usize_to_u64(height)))
}
// [`BlockchainManagerRequest::Spans`]
pub(crate) async fn spans<Z: NetworkZone>(
blockchain_manager: &mut BlockchainManagerHandle,
) -> Result<Vec<Span>, Error> {
// let BlockchainManagerResponse::Spans(vec) = blockchain_manager
// .ready()
// .await?
// .call(BlockchainManagerRequest::Spans)
// .await?
// else {
// unreachable!();
// };
let vec: Vec<cuprate_p2p_core::types::Span<Z::Addr>> = todo!();
// FIXME: impl this map somewhere instead of inline.
let vec = vec
.into_iter()
.map(|span| Span {
connection_id: String::from(ConnectionId::DEFAULT_STR),
nblocks: span.nblocks,
rate: span.rate,
remote_address: span.remote_address.to_string(),
size: span.size,
speed: span.speed,
start_block_height: span.start_block_height,
})
.collect();
Ok(vec)
}
/// [`BlockchainManagerRequest::NextNeededPruningSeed`]
pub(crate) async fn next_needed_pruning_seed(
blockchain_manager: &mut BlockchainManagerHandle,
) -> Result<PruningSeed, Error> {
let BlockchainManagerResponse::NextNeededPruningSeed(seed) = blockchain_manager
.ready()
.await?
.call(BlockchainManagerRequest::NextNeededPruningSeed)
.await?
else {
unreachable!();
};
Ok(seed)
}

View file

@ -2,7 +2,7 @@
use std::convert::Infallible; use std::convert::Infallible;
use anyhow::Error; use anyhow::{anyhow, Error};
use tower::{Service, ServiceExt}; use tower::{Service, ServiceExt};
use cuprate_helper::cast::usize_to_u64; use cuprate_helper::cast::usize_to_u64;
@ -14,15 +14,17 @@ use cuprate_txpool::{
TxEntry, TxEntry,
}; };
// FIXME: use `anyhow::Error` over `tower::BoxError` in txpool.
/// [`TxpoolReadRequest::Backlog`] /// [`TxpoolReadRequest::Backlog`]
pub(super) async fn backlog(txpool_read: &mut TxpoolReadHandle) -> Result<Vec<TxEntry>, Error> { pub(crate) async fn backlog(txpool_read: &mut TxpoolReadHandle) -> Result<Vec<TxEntry>, Error> {
let TxpoolReadResponse::Backlog(tx_entries) = txpool_read let TxpoolReadResponse::Backlog(tx_entries) = txpool_read
.ready() .ready()
.await .await
.expect("TODO") .map_err(|e| anyhow!(e))?
.call(TxpoolReadRequest::Backlog) .call(TxpoolReadRequest::Backlog)
.await .await
.expect("TODO") .map_err(|e| anyhow!(e))?
else { else {
unreachable!(); unreachable!();
}; };
@ -31,14 +33,19 @@ pub(super) async fn backlog(txpool_read: &mut TxpoolReadHandle) -> Result<Vec<Tx
} }
/// [`TxpoolReadRequest::Size`] /// [`TxpoolReadRequest::Size`]
pub(super) async fn size(txpool_read: &mut TxpoolReadHandle) -> Result<u64, Error> { pub(crate) async fn size(
txpool_read: &mut TxpoolReadHandle,
include_sensitive_txs: bool,
) -> Result<u64, Error> {
let TxpoolReadResponse::Size(size) = txpool_read let TxpoolReadResponse::Size(size) = txpool_read
.ready() .ready()
.await .await
.expect("TODO") .map_err(|e| anyhow!(e))?
.call(TxpoolReadRequest::Size) .call(TxpoolReadRequest::Size {
include_sensitive_txs,
})
.await .await
.expect("TODO") .map_err(|e| anyhow!(e))?
else { else {
unreachable!(); unreachable!();
}; };
@ -47,9 +54,17 @@ pub(super) async fn size(txpool_read: &mut TxpoolReadHandle) -> Result<u64, Erro
} }
/// TODO /// TODO
#[expect(clippy::needless_pass_by_ref_mut, reason = "TODO: remove after impl")] pub(crate) async fn flush(
pub(super) async fn flush( txpool_manager: &mut Infallible,
txpool_read: &mut TxpoolReadHandle, tx_hashes: Vec<[u8; 32]>,
) -> Result<(), Error> {
todo!();
Ok(())
}
/// TODO
pub(crate) async fn relay(
txpool_manager: &mut Infallible,
tx_hashes: Vec<[u8; 32]>, tx_hashes: Vec<[u8; 32]>,
) -> Result<(), Error> { ) -> Result<(), Error> {
todo!(); todo!();

View file

@ -35,6 +35,7 @@ cargo doc --open --package cuprate-blockchain
| [`cuprate-async-buffer`](https://doc.cuprate.org/cuprate_async_buffer) | [`p2p/async-buffer/`](https://github.com/Cuprate/cuprate/tree/main/p2p/async-buffer) | A bounded SPSC, FIFO, asynchronous buffer that supports arbitrary weights for values | [`cuprate-async-buffer`](https://doc.cuprate.org/cuprate_async_buffer) | [`p2p/async-buffer/`](https://github.com/Cuprate/cuprate/tree/main/p2p/async-buffer) | A bounded SPSC, FIFO, asynchronous buffer that supports arbitrary weights for values
| [`cuprate-dandelion-tower`](https://doc.cuprate.org/cuprate_dandelion_tower) | [`p2p/dandelion-tower/`](https://github.com/Cuprate/cuprate/tree/main/p2p/dandelion-tower) | TODO | [`cuprate-dandelion-tower`](https://doc.cuprate.org/cuprate_dandelion_tower) | [`p2p/dandelion-tower/`](https://github.com/Cuprate/cuprate/tree/main/p2p/dandelion-tower) | TODO
| [`cuprate-p2p`](https://doc.cuprate.org/cuprate_p2p) | [`p2p/p2p/`](https://github.com/Cuprate/cuprate/tree/main/p2p/p2p) | TODO | [`cuprate-p2p`](https://doc.cuprate.org/cuprate_p2p) | [`p2p/p2p/`](https://github.com/Cuprate/cuprate/tree/main/p2p/p2p) | TODO
| [`cuprate-p2p-bucket`](https://doc.cuprate.org/cuprate_p2p_bucket) | [`p2p/bucket/`](https://github.com/Cuprate/cuprate/tree/main/p2p/bucket) | A collection data structure discriminating its items into "buckets" of limited size.
| [`cuprate-p2p-core`](https://doc.cuprate.org/cuprate_p2p_core) | [`p2p/p2p-core/`](https://github.com/Cuprate/cuprate/tree/main/p2p/p2p-core) | TODO | [`cuprate-p2p-core`](https://doc.cuprate.org/cuprate_p2p_core) | [`p2p/p2p-core/`](https://github.com/Cuprate/cuprate/tree/main/p2p/p2p-core) | TODO
## Storage ## Storage

View file

@ -27,17 +27,5 @@ thread_local = { workspace = true }
hex = { workspace = true } hex = { workspace = true }
rand = { workspace = true } rand = { workspace = true }
[dev-dependencies]
cuprate-test-utils = { workspace = true }
cuprate-consensus-rules = { workspace = true, features = ["proptest"]}
hex-literal = { workspace = true }
curve25519-dalek = { workspace = true }
tokio = { workspace = true, features = ["rt-multi-thread", "macros"]}
tokio-test = { workspace = true }
proptest = { workspace = true }
proptest-derive = { workspace = true }
[lints] [lints]
workspace = true workspace = true

View file

@ -18,6 +18,7 @@ use std::{
}; };
use futures::{channel::oneshot, FutureExt}; use futures::{channel::oneshot, FutureExt};
use monero_serai::block::Block;
use tokio::sync::mpsc; use tokio::sync::mpsc;
use tokio_util::sync::PollSender; use tokio_util::sync::PollSender;
use tower::Service; use tower::Service;
@ -267,6 +268,21 @@ pub enum BlockChainContextRequest {
grace_blocks: u64, grace_blocks: u64,
}, },
/// Calculate proof-of-work for this block.
CalculatePow {
/// The hardfork of the protocol at this block height.
hardfork: HardFork,
/// The height of the block.
height: usize,
/// The block data.
///
/// This is boxed because [`Block`] causes this enum to be 1200 bytes,
/// where the 2nd variant is only 96 bytes.
block: Box<Block>,
/// The seed hash for the proof-of-work.
seed_hash: [u8; 32],
},
/// Clear the alt chain context caches. /// Clear the alt chain context caches.
ClearAltCache, ClearAltCache,
@ -364,6 +380,9 @@ pub enum BlockChainContextResponse {
/// Response to [`BlockChainContextRequest::FeeEstimate`] /// Response to [`BlockChainContextRequest::FeeEstimate`]
FeeEstimate(FeeEstimate), FeeEstimate(FeeEstimate),
/// Response to [`BlockChainContextRequest::CalculatePow`]
CalculatePow([u8; 32]),
/// Response to [`BlockChainContextRequest::AltChains`] /// Response to [`BlockChainContextRequest::AltChains`]
/// ///
/// If the inner [`Vec::is_empty`], there were no alternate chains. /// If the inner [`Vec::is_empty`], there were no alternate chains.

View file

@ -324,7 +324,8 @@ impl<D: Database + Clone + Send + 'static> ContextTask<D> {
} }
BlockChainContextRequest::HardForkInfo(_) BlockChainContextRequest::HardForkInfo(_)
| BlockChainContextRequest::FeeEstimate { .. } | BlockChainContextRequest::FeeEstimate { .. }
| BlockChainContextRequest::AltChains => { | BlockChainContextRequest::AltChains
| BlockChainContextRequest::CalculatePow { .. } => {
todo!("finish https://github.com/Cuprate/cuprate/pull/297") todo!("finish https://github.com/Cuprate/cuprate/pull/297")
} }
}) })

View file

@ -25,7 +25,5 @@ thiserror = { workspace = true }
tokio = { workspace = true, features = ["full"] } tokio = { workspace = true, features = ["full"] }
tower = { workspace = true } tower = { workspace = true }
[dev-dependencies]
[lints] [lints]
workspace = true workspace = true

View file

@ -31,10 +31,5 @@ thiserror = { workspace = true }
rayon = { workspace = true, optional = true } rayon = { workspace = true, optional = true }
[dev-dependencies]
proptest = { workspace = true }
proptest-derive = { workspace = true }
tokio = { version = "1.35.0", features = ["rt-multi-thread", "macros"] }
[lints] [lints]
workspace = true workspace = true

View file

@ -1,5 +1,3 @@
#![expect(non_local_definitions, reason = "proptest macro")]
use std::{ use std::{
future::Future, future::Future,
pin::Pin, pin::Pin,

View file

@ -16,7 +16,5 @@ rpc = []
[dependencies] [dependencies]
[dev-dependencies]
[lints] [lints]
workspace = true workspace = true

View file

@ -17,8 +17,5 @@ keccak = "0.1.5"
digest = "0.10.7" digest = "0.10.7"
seq-macro = "0.3.5" seq-macro = "0.3.5"
[dev-dependencies]
hex = { workspace = true, features = ["std"] }
[lints] [lints]
workspace = true workspace = true

View file

@ -81,6 +81,9 @@ ignore = [
#{ id = "RUSTSEC-0000-0000", reason = "you can specify a reason the advisory is ignored" }, #{ id = "RUSTSEC-0000-0000", reason = "you can specify a reason the advisory is ignored" },
#"a-crate-that-is-yanked@0.1.1", # you can also ignore yanked crate versions if you wish #"a-crate-that-is-yanked@0.1.1", # you can also ignore yanked crate versions if you wish
#{ crate = "a-crate-that-is-yanked@0.1.1", reason = "you can specify why you are ignoring the yanked crate" }, #{ crate = "a-crate-that-is-yanked@0.1.1", reason = "you can specify why you are ignoring the yanked crate" },
# TODO: check this is sorted before a beta release.
{ id = "RUSTSEC-2024-0370", reason = "unmaintained crate, not necessarily vulnerable yet." }
] ]
# If this is true, then cargo deny will use the git executable to fetch advisory database. # If this is true, then cargo deny will use the git executable to fetch advisory database.
# If this is false, then it uses a built-in git library. # If this is false, then it uses a built-in git library.
@ -110,6 +113,7 @@ allow = [
"Apache-2.0", # https://tldrlegal.com/license/apache-license-2.0-(apache-2.0) "Apache-2.0", # https://tldrlegal.com/license/apache-license-2.0-(apache-2.0)
"MPL-2.0", # https://www.mozilla.org/en-US/MPL/2.0/FAQ/ "MPL-2.0", # https://www.mozilla.org/en-US/MPL/2.0/FAQ/
"BSL-1.0", # https://tldrlegal.com/license/boost-software-license-1.0-explained "BSL-1.0", # https://tldrlegal.com/license/boost-software-license-1.0-explained
"Zlib", # https://spdx.org/licenses/Zlib.html
# OpenSSL 3.0+ uses Apache-2.0 # OpenSSL 3.0+ uses Apache-2.0
# OpenSSL 1.x.x uses https://www.openssl.org/source/license-openssl-ssleay.txt # OpenSSL 1.x.x uses https://www.openssl.org/source/license-openssl-ssleay.txt

View file

@ -17,7 +17,7 @@ asynch = ["dep:futures", "dep:rayon"]
cast = [] cast = []
constants = [] constants = []
crypto = ["dep:curve25519-dalek", "dep:monero-serai", "std"] crypto = ["dep:curve25519-dalek", "dep:monero-serai", "std"]
fs = ["dep:dirs"] fs = ["dep:dirs", "std"]
num = [] num = []
map = ["cast", "dep:monero-serai", "dep:cuprate-constants"] map = ["cast", "dep:monero-serai", "dep:cuprate-constants"]
time = ["dep:chrono", "std"] time = ["dep:chrono", "std"]
@ -43,9 +43,5 @@ target_os_lib = { package = "windows", version = ">=0.51", features = ["Win32_Sy
[target.'cfg(unix)'.dependencies] [target.'cfg(unix)'.dependencies]
target_os_lib = { package = "libc", version = "0.2.158", optional = true } target_os_lib = { package = "libc", version = "0.2.158", optional = true }
[dev-dependencies]
tokio = { workspace = true, features = ["full"] }
curve25519-dalek = { workspace = true }
[lints] [lints]
workspace = true workspace = true

View file

@ -18,7 +18,6 @@
// // // //
//============================ SAFETY: DO NOT REMOVE ===========================// //============================ SAFETY: DO NOT REMOVE ===========================//
//---------------------------------------------------------------------------------------------------- Free functions
/// Cast [`u64`] to [`usize`]. /// Cast [`u64`] to [`usize`].
#[inline(always)] #[inline(always)]
pub const fn u64_to_usize(u: u64) -> usize { pub const fn u64_to_usize(u: u64) -> usize {

View file

@ -11,7 +11,7 @@ pub mod atomic;
#[cfg(feature = "cast")] #[cfg(feature = "cast")]
pub mod cast; pub mod cast;
#[cfg(feature = "fs")] #[cfg(all(feature = "fs", feature = "std"))]
pub mod fs; pub mod fs;
pub mod network; pub mod network;

View file

@ -23,8 +23,5 @@ ref-cast = "1.0.23"
bytes = { workspace = true } bytes = { workspace = true }
thiserror = { workspace = true, optional = true} thiserror = { workspace = true, optional = true}
[dev-dependencies]
hex = { workspace = true, features = ["default"] }
[lints] [lints]
workspace = true workspace = true

View file

@ -1,3 +1,5 @@
use alloc::{string::ToString, vec, vec::Vec};
use bytes::{Buf, BufMut, Bytes, BytesMut}; use bytes::{Buf, BufMut, Bytes, BytesMut};
use ref_cast::RefCast; use ref_cast::RefCast;

View file

@ -1,3 +1,4 @@
use alloc::string::{String, ToString};
use core::{ use core::{
fmt::{Debug, Formatter}, fmt::{Debug, Formatter},
num::TryFromIntError, num::TryFromIntError,

View file

@ -64,6 +64,7 @@ use hex as _;
extern crate alloc; extern crate alloc;
use alloc::string::ToString;
use core::str::from_utf8 as str_from_utf8; use core::str::from_utf8 as str_from_utf8;
use bytes::{Buf, BufMut, Bytes, BytesMut}; use bytes::{Buf, BufMut, Bytes, BytesMut};

View file

@ -1,7 +1,7 @@
//! This module contains a [`EpeeValue`] trait and //! This module contains a [`EpeeValue`] trait and
//! impls for some possible base epee values. //! impls for some possible base epee values.
use alloc::{string::String, vec::Vec}; use alloc::{string::String, vec, vec::Vec};
use core::fmt::Debug; use core::fmt::Debug;
use bytes::{Buf, BufMut, Bytes, BytesMut}; use bytes::{Buf, BufMut, Bytes, BytesMut};

View file

@ -15,8 +15,5 @@ thiserror = { workspace = true, optional = true }
bytes = { workspace = true } bytes = { workspace = true }
serde = { workspace = true, features = ["derive"], optional = true } serde = { workspace = true, features = ["derive"], optional = true }
[dev-dependencies]
serde_json = { workspace = true, features = ["std"] }
[lints] [lints]
workspace = true workspace = true

View file

@ -22,12 +22,5 @@ tokio-util = { workspace = true, features = ["codec"]}
tracing = { workspace = true, features = ["std"], optional = true } tracing = { workspace = true, features = ["std"], optional = true }
[dev-dependencies]
proptest = { workspace = true }
rand = { workspace = true, features = ["std", "std_rng"] }
tokio-util = { workspace = true, features = ["io-util"]}
tokio = { workspace = true, features = ["full"] }
futures = { workspace = true, features = ["std"] }
[lints] [lints]
workspace = true workspace = true

View file

@ -21,8 +21,5 @@ bitflags = { workspace = true, features = ["std"] }
bytes = { workspace = true, features = ["std"] } bytes = { workspace = true, features = ["std"] }
thiserror = { workspace = true } thiserror = { workspace = true }
[dev-dependencies]
hex = { workspace = true, features = ["std"]}
[lints] [lints]
workspace = true workspace = true

View file

@ -9,7 +9,7 @@ authors = ["Boog900"]
[dependencies] [dependencies]
cuprate-constants = { workspace = true } cuprate-constants = { workspace = true }
cuprate-pruning = { workspace = true } cuprate-pruning = { workspace = true }
cuprate-p2p-core = { workspace = true } cuprate-p2p-core = { workspace = true, features = ["borsh"] }
tower = { workspace = true, features = ["util"] } tower = { workspace = true, features = ["util"] }
tokio = { workspace = true, features = ["time", "fs", "rt"]} tokio = { workspace = true, features = ["time", "fs", "rt"]}
@ -25,10 +25,5 @@ rand = { workspace = true, features = ["std", "std_rng"] }
borsh = { workspace = true, features = ["derive", "std"]} borsh = { workspace = true, features = ["derive", "std"]}
[dev-dependencies]
cuprate-test-utils = { workspace = true }
tokio = { workspace = true, features = ["rt-multi-thread", "macros"]}
[lints] [lints]
workspace = true workspace = true

View file

@ -423,7 +423,8 @@ impl<Z: BorshNetworkZone> Service<AddressBookRequest<Z>> for AddressBook<Z> {
AddressBookRequest::PeerlistSize AddressBookRequest::PeerlistSize
| AddressBookRequest::ConnectionCount | AddressBookRequest::ConnectionCount
| AddressBookRequest::SetBan(_) | AddressBookRequest::SetBan(_)
| AddressBookRequest::GetBans => { | AddressBookRequest::GetBans
| AddressBookRequest::ConnectionInfo => {
todo!("finish https://github.com/Cuprate/cuprate/pull/297") todo!("finish https://github.com/Cuprate/cuprate/pull/297")
} }
}; };

View file

@ -9,6 +9,3 @@ authors = ["Boog900"]
thiserror = { workspace = true } thiserror = { workspace = true }
futures = { workspace = true, features = ["std"] } futures = { workspace = true, features = ["std"] }
pin-project = { workspace = true } pin-project = { workspace = true }
[dev-dependencies]
tokio = { workspace = true, features = ["full"] }

13
p2p/bucket/Cargo.toml Normal file
View file

@ -0,0 +1,13 @@
[package]
name = "cuprate-p2p-bucket"
version = "0.1.0"
edition = "2021"
license = "MIT"
authors = ["SyntheticBird"]
[dependencies]
arrayvec = { workspace = true }
rand = { workspace = true, features = ["std", "std_rng"]}
[lints]
workspace = true

172
p2p/bucket/src/lib.rs Normal file
View file

@ -0,0 +1,172 @@
//! Bucket data structure
//!
//! A collection data structure that discriminates its unique items and place them into "buckets".
//!
//! The item must implement the [`Bucketable`] trait that defines how to create the discriminant
//! from the item type. The data structure will internally contain any item into "buckets" or vectors
//! of sized capacity `N` that regroup all the stored items with this specific discriminant.
//!
//! A practical example of this data structure is for storing `N` amount of IP discriminated by their subnets.
//! You can store in each "buckets" corresponding to a `/16` subnet up to `N` IPs of that subnet.
//!
//! # Example
//!
//! ```
//! use cuprate_p2p_bucket::Bucket;
//! use std::net::Ipv4Addr;
//!
//! // Create a new bucket that can store at most 2 IPs in a particular `/16` subnet.
//! let mut bucket = Bucket::<2,Ipv4Addr>::new();
//!
//! // Fulfill the `96.96.0.0/16` bucket.
//! bucket.push("96.96.0.1".parse().unwrap());
//! bucket.push("96.96.0.2".parse().unwrap());
//! assert_eq!(2, bucket.len());
//! assert_eq!(2, bucket.len_bucket(&[96_u8,96_u8]).unwrap());
//!
//! // Push a new IP from another subnet
//! bucket.push("127.0.0.1".parse().unwrap());
//! assert_eq!(3, bucket.len());
//! assert_eq!(2, bucket.len_bucket(&[96_u8,96_u8]).unwrap());
//! assert_eq!(1, bucket.len_bucket(&[127_u8,0_u8]).unwrap());
//!
//! // Attempting to push a new IP within `96.96.0.0/16` bucket will return the IP back
//! // as this subnet is already full.
//! let pushed = bucket.push("96.96.0.3".parse().unwrap());
//! assert!(pushed.is_some());
//! assert_eq!(2, bucket.len_bucket(&[96_u8,96_u8]).unwrap());
//!
//! ```
use arrayvec::{ArrayVec, CapacityError};
use rand::random;
use std::{collections::BTreeMap, net::Ipv4Addr};
/// A discriminant that can be computed from the type.
pub trait Bucketable: Sized + Eq + Clone {
/// The type of the discriminant being used in the Binary tree.
type Discriminant: Ord + AsRef<[u8]>;
/// Method that can compute the discriminant from the item.
fn discriminant(&self) -> Self::Discriminant;
}
/// A collection data structure discriminating its unique items
/// with a specified method. Limiting the amount of items stored
/// with that discriminant to the const `N`.
pub struct Bucket<const N: usize, I: Bucketable> {
/// The storage of the bucket
storage: BTreeMap<I::Discriminant, ArrayVec<I, N>>,
}
impl<const N: usize, I: Bucketable> Bucket<N, I> {
/// Create a new Bucket
pub const fn new() -> Self {
Self {
storage: BTreeMap::new(),
}
}
/// Push a new element into the Bucket
///
/// Will internally create a new vector for each new discriminant being
/// generated from an item.
///
/// This function WILL NOT push the element if it already exists.
///
/// Return `None` if the item has been pushed or ignored. `Some(I)` if
/// the vector is full.
///
/// # Example
///
/// ```
/// use cuprate_p2p_bucket::Bucket;
/// use std::net::Ipv4Addr;
///
/// let mut bucket = Bucket::<8,Ipv4Addr>::new();
///
/// // Push a first IP address.
/// bucket.push("127.0.0.1".parse().unwrap());
/// assert_eq!(1, bucket.len());
///
/// // Push the same IP address a second time.
/// bucket.push("127.0.0.1".parse().unwrap());
/// assert_eq!(1, bucket.len());
/// ```
pub fn push(&mut self, item: I) -> Option<I> {
let discriminant = item.discriminant();
if let Some(vec) = self.storage.get_mut(&discriminant) {
// Push the item if it doesn't exist.
if !vec.contains(&item) {
return vec.try_push(item).err().map(CapacityError::element);
}
} else {
// Initialize the vector if not found.
let mut vec = ArrayVec::<I, N>::new();
vec.push(item);
self.storage.insert(discriminant, vec);
}
None
}
/// Will attempt to remove an item from the bucket.
pub fn remove(&mut self, item: &I) -> Option<I> {
self.storage.get_mut(&item.discriminant()).and_then(|vec| {
vec.iter()
.enumerate()
.find_map(|(i, v)| (item == v).then_some(i))
.map(|index| vec.swap_remove(index))
})
}
/// Return the number of item stored within the storage
pub fn len(&self) -> usize {
self.storage.values().map(ArrayVec::len).sum()
}
/// Return the number of item stored with a specific discriminant.
///
/// This method returns None if the bucket with this discriminant
/// doesn't exist.
pub fn len_bucket(&self, discriminant: &I::Discriminant) -> Option<usize> {
self.storage.get(discriminant).map(ArrayVec::len)
}
/// Return `true` if the storage contains no items
pub fn is_empty(&self) -> bool {
self.len() == 0
}
/// Return a reference to an item chosen at random.
///
/// Repeated use of this function will provide a normal distribution of
/// items based on their discriminants.
pub fn get_random(&mut self) -> Option<&I> {
// Get the total amount of discriminants to explore.
let len = self.storage.len();
// Get a random bucket.
let (_, vec) = self.storage.iter().nth(random::<usize>() / len).unwrap();
// Return a reference chose at random.
vec.get(random::<usize>() / vec.len())
}
}
impl<const N: usize, I: Bucketable> Default for Bucket<N, I> {
fn default() -> Self {
Self::new()
}
}
impl Bucketable for Ipv4Addr {
/// We are discriminating by `/16` subnets.
type Discriminant = [u8; 2];
fn discriminant(&self) -> Self::Discriminant {
[self.octets()[0], self.octets()[1]]
}
}

View file

@ -22,9 +22,5 @@ rand_distr = { workspace = true, features = ["std"], optional = true }
thiserror = { workspace = true } thiserror = { workspace = true }
[dev-dependencies]
tokio = { workspace = true, features = ["rt-multi-thread", "macros", "sync"] }
proptest = { workspace = true, features = ["default"] }
[lints] [lints]
workspace = true workspace = true

View file

@ -13,6 +13,7 @@ borsh = ["dep:borsh", "cuprate-pruning/borsh"]
cuprate-helper = { workspace = true, features = ["asynch"], default-features = false } cuprate-helper = { workspace = true, features = ["asynch"], default-features = false }
cuprate-wire = { workspace = true, features = ["tracing"] } cuprate-wire = { workspace = true, features = ["tracing"] }
cuprate-pruning = { workspace = true } cuprate-pruning = { workspace = true }
cuprate-types = { workspace = true }
tokio = { workspace = true, features = ["net", "sync", "macros", "time", "rt", "rt-multi-thread"]} tokio = { workspace = true, features = ["net", "sync", "macros", "time", "rt", "rt-multi-thread"]}
tokio-util = { workspace = true, features = ["codec"] } tokio-util = { workspace = true, features = ["codec"] }
@ -28,11 +29,5 @@ hex-literal = { workspace = true }
borsh = { workspace = true, features = ["derive", "std"], optional = true } borsh = { workspace = true, features = ["derive", "std"], optional = true }
[dev-dependencies]
cuprate-test-utils = { workspace = true }
hex = { workspace = true, features = ["std"] }
tokio-test = { workspace = true }
[lints] [lints]
workspace = true workspace = true

View file

@ -1,23 +0,0 @@
//! Data structures related to bans.
use std::time::{Duration, Instant};
use crate::NetZoneAddress;
/// Data within [`crate::services::AddressBookRequest::SetBan`].
pub struct SetBan<A: NetZoneAddress> {
/// Address of the peer.
pub address: A,
/// - If [`Some`], how long this peer should be banned for
/// - If [`None`], the peer will be unbanned
pub ban: Option<Duration>,
}
/// Data within [`crate::services::AddressBookResponse::GetBans`].
pub struct BanState<A: NetZoneAddress> {
/// Address of the peer.
pub address: A,
/// - If [`Some`], the peer is banned until this [`Instant`]
/// - If [`None`], the peer is not currently banned
pub unban_instant: Option<Instant>,
}

View file

@ -111,7 +111,8 @@ impl<N: NetworkZone> Service<AddressBookRequest<N>> for DummyAddressBook {
AddressBookRequest::PeerlistSize AddressBookRequest::PeerlistSize
| AddressBookRequest::ConnectionCount | AddressBookRequest::ConnectionCount
| AddressBookRequest::SetBan(_) | AddressBookRequest::SetBan(_)
| AddressBookRequest::GetBans => { | AddressBookRequest::GetBans
| AddressBookRequest::ConnectionInfo => {
todo!("finish https://github.com/Cuprate/cuprate/pull/297") todo!("finish https://github.com/Cuprate/cuprate/pull/297")
} }
})) }))

View file

@ -75,7 +75,6 @@ use cuprate_wire::{
NetworkAddress, NetworkAddress,
}; };
pub mod ban;
pub mod client; pub mod client;
mod constants; mod constants;
pub mod error; pub mod error;
@ -83,6 +82,7 @@ pub mod handles;
mod network_zones; mod network_zones;
pub mod protocol; pub mod protocol;
pub mod services; pub mod services;
pub mod types;
pub use error::*; pub use error::*;
pub use network_zones::{ClearNet, ClearNetServerCfg}; pub use network_zones::{ClearNet, ClearNetServerCfg};

View file

@ -4,9 +4,9 @@ use cuprate_pruning::{PruningError, PruningSeed};
use cuprate_wire::{CoreSyncData, PeerListEntryBase}; use cuprate_wire::{CoreSyncData, PeerListEntryBase};
use crate::{ use crate::{
ban::{BanState, SetBan},
client::InternalPeerID, client::InternalPeerID,
handles::ConnectionHandle, handles::ConnectionHandle,
types::{BanState, ConnectionInfo, SetBan},
NetZoneAddress, NetworkAddressIncorrectZone, NetworkZone, NetZoneAddress, NetworkAddressIncorrectZone, NetworkZone,
}; };
@ -118,6 +118,9 @@ pub enum AddressBookRequest<Z: NetworkZone> {
/// Get the amount of white & grey peers. /// Get the amount of white & grey peers.
PeerlistSize, PeerlistSize,
/// Get information on all connections.
ConnectionInfo,
/// Get the amount of incoming & outgoing connections. /// Get the amount of incoming & outgoing connections.
ConnectionCount, ConnectionCount,
@ -152,6 +155,9 @@ pub enum AddressBookResponse<Z: NetworkZone> {
/// Response to [`AddressBookRequest::PeerlistSize`]. /// Response to [`AddressBookRequest::PeerlistSize`].
PeerlistSize { white: usize, grey: usize }, PeerlistSize { white: usize, grey: usize },
/// Response to [`AddressBookRequest::ConnectionInfo`].
ConnectionInfo(Vec<ConnectionInfo<Z::Addr>>),
/// Response to [`AddressBookRequest::ConnectionCount`]. /// Response to [`AddressBookRequest::ConnectionCount`].
ConnectionCount { incoming: usize, outgoing: usize }, ConnectionCount { incoming: usize, outgoing: usize },

96
p2p/p2p-core/src/types.rs Normal file
View file

@ -0,0 +1,96 @@
//! General data structures.
use std::time::{Duration, Instant};
use cuprate_pruning::PruningSeed;
use cuprate_types::{AddressType, ConnectionState};
use crate::NetZoneAddress;
/// Data within [`crate::services::AddressBookRequest::SetBan`].
pub struct SetBan<A: NetZoneAddress> {
/// Address of the peer.
pub address: A,
/// - If [`Some`], how long this peer should be banned for
/// - If [`None`], the peer will be unbanned
pub ban: Option<Duration>,
}
/// Data within [`crate::services::AddressBookResponse::GetBans`].
pub struct BanState<A: NetZoneAddress> {
/// Address of the peer.
pub address: A,
/// - If [`Some`], the peer is banned until this [`Instant`]
/// - If [`None`], the peer is not currently banned
pub unban_instant: Option<Instant>,
}
/// Data within [`crate::services::AddressBookResponse::ConnectionInfo`].
pub struct ConnectionInfo<A: NetZoneAddress> {
// The following fields are mostly the same as `monerod`.
pub address: A,
pub address_type: AddressType,
pub avg_download: u64,
pub avg_upload: u64,
pub current_download: u64,
pub current_upload: u64,
pub height: u64,
/// Either a domain or an IP without the port.
pub host: String,
pub incoming: bool,
pub live_time: u64,
pub localhost: bool,
pub local_ip: bool,
pub peer_id: u64,
pub pruning_seed: PruningSeed,
pub recv_count: u64,
pub recv_idle_time: u64,
pub rpc_credits_per_hash: u32,
pub rpc_port: u16,
pub send_count: u64,
pub send_idle_time: u64,
pub state: ConnectionState,
pub support_flags: u32,
// The following fields are slightly different than `monerod`.
//
/// [`None`] if Tor/i2p or unknown.
pub socket_addr: Option<std::net::SocketAddr>,
/// This field does not exist for `cuprated`'s RPC, this is just a marker type:
/// - <https://github.com/Cuprate/cuprate/pull/320#discussion_r1811335020>
/// - <https://github.com/Cuprate/cuprate/pull/320#discussion_r1819826080>
///
/// [`ConnectionId::DEFAULT_STR`] is used when mapping to the RPC type.
pub connection_id: ConnectionId,
}
/// Marker type for `monerod`'s connection ID.
///
/// `connection_id` is a 128-bit `uuid` in `monerod`.
/// `cuprated` does not support this field so it returns
/// the default value in the RPC interface, an all 0-bit UUID.
///
/// This default value in string form is [`ConnectionId::DEFAULT_STR`].
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ConnectionId;
impl ConnectionId {
/// [`str`] representation of a default connection ID.
pub const DEFAULT_STR: &str = "00000000000000000000000000000000";
}
/// Used in RPC's `sync_info`.
///
// TODO: fix docs after <https://github.com/Cuprate/cuprate/pull/320#discussion_r1811089758>
// Data within [`crate::services::AddressBookResponse::Spans`].
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Span<A: NetZoneAddress> {
pub nblocks: u64,
pub rate: u32,
pub remote_address: A,
pub size: u64,
pub speed: u32,
pub start_block_height: u64,
}

View file

@ -34,11 +34,5 @@ rand_distr = { workspace = true, features = ["std"] }
tracing = { workspace = true, features = ["std", "attributes"] } tracing = { workspace = true, features = ["std", "attributes"] }
borsh = { workspace = true, features = ["derive", "std"] } borsh = { workspace = true, features = ["derive", "std"] }
[dev-dependencies]
cuprate-test-utils = { workspace = true }
indexmap = { workspace = true }
proptest = { workspace = true }
tokio-test = { workspace = true }
[lints] [lints]
workspace = true workspace = true

View file

@ -10,7 +10,7 @@ default = []
borsh = ["dep:borsh"] borsh = ["dep:borsh"]
[dependencies] [dependencies]
cuprate-constants = { workspace = true } cuprate-constants = { workspace = true, features = ["block"] }
cuprate-helper = { workspace = true, features = ["cast"] } cuprate-helper = { workspace = true, features = ["cast"] }
thiserror = { workspace = true } thiserror = { workspace = true }

View file

@ -10,28 +10,20 @@ keywords = ["cuprate", "rpc", "interface"]
[features] [features]
default = ["dummy", "serde"] default = ["dummy", "serde"]
dummy = [] dummy = ["dep:cuprate-helper", "dep:futures"]
[dependencies] [dependencies]
cuprate-epee-encoding = { workspace = true, default-features = false } cuprate-epee-encoding = { workspace = true, default-features = false }
cuprate-json-rpc = { workspace = true, default-features = false } cuprate-json-rpc = { workspace = true, default-features = false }
cuprate-rpc-types = { workspace = true, features = ["serde", "epee"], default-features = false } cuprate-rpc-types = { workspace = true, features = ["serde", "epee"], default-features = false }
cuprate-helper = { workspace = true, features = ["asynch"], default-features = false } cuprate-helper = { workspace = true, features = ["asynch"], default-features = false, optional = true }
anyhow = { workspace = true } anyhow = { workspace = true }
axum = { version = "0.7.5", features = ["json"], default-features = false } axum = { version = "0.7.5", features = ["json"], default-features = false }
serde = { workspace = true, optional = true } serde = { workspace = true, optional = true }
tower = { workspace = true } tower = { workspace = true, features = ["util"] }
paste = { workspace = true } paste = { workspace = true }
futures = { workspace = true } futures = { workspace = true, optional = true }
[dev-dependencies]
cuprate-test-utils = { workspace = true }
axum = { version = "0.7.5", features = ["json", "tokio", "http2"] }
serde_json = { workspace = true, features = ["std"] }
tokio = { workspace = true, features = ["full"] }
ureq = { version = "2.10.1", features = ["json"] }
[lints] [lints]
workspace = true workspace = true

View file

@ -16,8 +16,5 @@ serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true, features = ["std"] } serde_json = { workspace = true, features = ["std"] }
thiserror = { workspace = true } thiserror = { workspace = true }
[dev-dependencies]
pretty_assertions = { workspace = true }
[lints] [lints]
workspace = true workspace = true

View file

@ -10,22 +10,16 @@ keywords = ["cuprate", "rpc", "types", "monero"]
[features] [features]
default = ["serde", "epee"] default = ["serde", "epee"]
serde = ["dep:serde", "cuprate-fixed-bytes/serde"] serde = ["dep:serde", "cuprate-fixed-bytes/serde", "cuprate-types/serde"]
epee = ["dep:cuprate-epee-encoding"] epee = ["dep:cuprate-epee-encoding", "cuprate-types/epee"]
[dependencies] [dependencies]
cuprate-epee-encoding = { workspace = true, optional = true } cuprate-epee-encoding = { workspace = true, optional = true }
cuprate-fixed-bytes = { workspace = true } cuprate-fixed-bytes = { workspace = true }
cuprate-types = { workspace = true, default-features = false, features = ["epee", "serde"] } cuprate-types = { workspace = true, default-features = false }
paste = { workspace = true } paste = { workspace = true }
serde = { workspace = true, optional = true } serde = { workspace = true, optional = true }
[dev-dependencies]
cuprate-test-utils = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
[lints] [lints]
workspace = true workspace = true

View file

@ -58,61 +58,37 @@ pub struct ResponseBase {
} }
impl ResponseBase { impl ResponseBase {
/// `const` version of [`Default::default`]. /// [`Status::Ok`] and trusted [`Self`].
///
/// ```rust
/// use cuprate_rpc_types::{misc::*, base::*};
///
/// let new = ResponseBase::new();
/// assert_eq!(new, ResponseBase {
/// status: Status::Ok,
/// untrusted: false,
/// });
/// ```
pub const fn new() -> Self {
Self {
status: Status::Ok,
untrusted: false,
}
}
/// Returns OK and trusted [`Self`].
/// ///
/// This is the most common version of [`Self`]. /// This is the most common version of [`Self`].
/// ///
/// ```rust /// ```rust
/// use cuprate_rpc_types::{misc::*, base::*}; /// use cuprate_rpc_types::{misc::*, base::*};
/// ///
/// let ok = ResponseBase::ok(); /// assert_eq!(ResponseBase::OK, ResponseBase {
/// assert_eq!(ok, ResponseBase {
/// status: Status::Ok, /// status: Status::Ok,
/// untrusted: false, /// untrusted: false,
/// }); /// });
/// ``` /// ```
pub const fn ok() -> Self { pub const OK: Self = Self {
Self {
status: Status::Ok, status: Status::Ok,
untrusted: false, untrusted: false,
} };
}
/// Same as [`Self::ok`] but with [`Self::untrusted`] set to `true`. /// Same as [`Self::OK`] but with [`Self::untrusted`] set to `true`.
/// ///
/// ```rust /// ```rust
/// use cuprate_rpc_types::{misc::*, base::*}; /// use cuprate_rpc_types::{misc::*, base::*};
/// ///
/// let ok_untrusted = ResponseBase::ok_untrusted(); /// assert_eq!(ResponseBase::OK_UNTRUSTED, ResponseBase {
/// assert_eq!(ok_untrusted, ResponseBase {
/// status: Status::Ok, /// status: Status::Ok,
/// untrusted: true, /// untrusted: true,
/// }); /// });
/// ``` /// ```
pub const fn ok_untrusted() -> Self { pub const OK_UNTRUSTED: Self = Self {
Self {
status: Status::Ok, status: Status::Ok,
untrusted: true, untrusted: true,
} };
}
} }
#[cfg(feature = "epee")] #[cfg(feature = "epee")]
@ -148,9 +124,9 @@ impl AccessResponseBase {
/// ```rust /// ```rust
/// use cuprate_rpc_types::{misc::*, base::*}; /// use cuprate_rpc_types::{misc::*, base::*};
/// ///
/// let new = AccessResponseBase::new(ResponseBase::ok()); /// let new = AccessResponseBase::new(ResponseBase::OK);
/// assert_eq!(new, AccessResponseBase { /// assert_eq!(new, AccessResponseBase {
/// response_base: ResponseBase::ok(), /// response_base: ResponseBase::OK,
/// credits: 0, /// credits: 0,
/// top_hash: "".into(), /// top_hash: "".into(),
/// }); /// });
@ -163,47 +139,41 @@ impl AccessResponseBase {
} }
} }
/// Returns OK and trusted [`Self`]. /// [`Status::Ok`] and trusted [`Self`].
/// ///
/// This is the most common version of [`Self`]. /// This is the most common version of [`Self`].
/// ///
/// ```rust /// ```rust
/// use cuprate_rpc_types::{misc::*, base::*}; /// use cuprate_rpc_types::{misc::*, base::*};
/// ///
/// let ok = AccessResponseBase::ok(); /// assert_eq!(AccessResponseBase::OK, AccessResponseBase {
/// assert_eq!(ok, AccessResponseBase { /// response_base: ResponseBase::OK,
/// response_base: ResponseBase::ok(),
/// credits: 0, /// credits: 0,
/// top_hash: "".into(), /// top_hash: "".into(),
/// }); /// });
/// ``` /// ```
pub const fn ok() -> Self { pub const OK: Self = Self {
Self { response_base: ResponseBase::OK,
response_base: ResponseBase::ok(),
credits: 0, credits: 0,
top_hash: String::new(), top_hash: String::new(),
} };
}
/// Same as [`Self::ok`] but with `untrusted` set to `true`. /// Same as [`Self::OK`] but with `untrusted` set to `true`.
/// ///
/// ```rust /// ```rust
/// use cuprate_rpc_types::{misc::*, base::*}; /// use cuprate_rpc_types::{misc::*, base::*};
/// ///
/// let ok_untrusted = AccessResponseBase::ok_untrusted(); /// assert_eq!(AccessResponseBase::OK_UNTRUSTED, AccessResponseBase {
/// assert_eq!(ok_untrusted, AccessResponseBase { /// response_base: ResponseBase::OK_UNTRUSTED,
/// response_base: ResponseBase::ok_untrusted(),
/// credits: 0, /// credits: 0,
/// top_hash: "".into(), /// top_hash: "".into(),
/// }); /// });
/// ``` /// ```
pub const fn ok_untrusted() -> Self { pub const OK_UNTRUSTED: Self = Self {
Self { response_base: ResponseBase::OK_UNTRUSTED,
response_base: ResponseBase::ok_untrusted(),
credits: 0, credits: 0,
top_hash: String::new(), top_hash: String::new(),
} };
}
} }
#[cfg(feature = "epee")] #[cfg(feature = "epee")]

View file

@ -20,12 +20,16 @@ use cuprate_types::BlockCompleteEntry;
use crate::{ use crate::{
base::AccessResponseBase, base::AccessResponseBase,
defaults::{default_false, default_zero},
macros::{define_request, define_request_and_response, define_request_and_response_doc}, macros::{define_request, define_request_and_response, define_request_and_response_doc},
misc::{BlockOutputIndices, GetOutputsOut, OutKeyBin, PoolInfoExtent, PoolTxInfo, Status}, misc::{BlockOutputIndices, GetOutputsOut, OutKeyBin, PoolTxInfo, Status},
rpc_call::RpcCallValue, rpc_call::RpcCallValue,
}; };
#[cfg(any(feature = "epee", feature = "serde"))]
use crate::defaults::{default_false, default_zero};
#[cfg(feature = "epee")]
use crate::misc::PoolInfoExtent;
//---------------------------------------------------------------------------------------------------- Definitions //---------------------------------------------------------------------------------------------------- Definitions
define_request_and_response! { define_request_and_response! {
get_blocks_by_heightbin, get_blocks_by_heightbin,

View file

@ -8,10 +8,6 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
base::{AccessResponseBase, ResponseBase}, base::{AccessResponseBase, ResponseBase},
defaults::{
default_false, default_height, default_one, default_string, default_true, default_vec,
default_zero,
},
macros::define_request_and_response, macros::define_request_and_response,
misc::{ misc::{
AuxPow, BlockHeader, ChainInfo, ConnectionInfo, Distribution, GetBan, AuxPow, BlockHeader, ChainInfo, ConnectionInfo, Distribution, GetBan,
@ -21,6 +17,12 @@ use crate::{
rpc_call::RpcCallValue, rpc_call::RpcCallValue,
}; };
#[cfg(any(feature = "epee", feature = "serde"))]
use crate::defaults::{
default_false, default_height, default_one, default_string, default_true, default_vec,
default_zero,
};
//---------------------------------------------------------------------------------------------------- Macro //---------------------------------------------------------------------------------------------------- Macro
/// Adds a (de)serialization doc-test to a type in `json.rs`. /// Adds a (de)serialization doc-test to a type in `json.rs`.
/// ///
@ -184,7 +186,7 @@ define_request_and_response! {
// <https://serde.rs/field-attrs.html#flatten>. // <https://serde.rs/field-attrs.html#flatten>.
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
GET_BLOCK_TEMPLATE_RESPONSE => GetBlockTemplateResponse { GET_BLOCK_TEMPLATE_RESPONSE => GetBlockTemplateResponse {
base: ResponseBase::ok(), base: ResponseBase::OK,
blockhashing_blob: "1010f4bae0b4069d648e741d85ca0e7acb4501f051b27e9b107d3cd7a3f03aa7f776089117c81a00000000e0c20372be23d356347091025c5b5e8f2abf83ab618378565cce2b703491523401".into(), blockhashing_blob: "1010f4bae0b4069d648e741d85ca0e7acb4501f051b27e9b107d3cd7a3f03aa7f776089117c81a00000000e0c20372be23d356347091025c5b5e8f2abf83ab618378565cce2b703491523401".into(),
blocktemplate_blob: "1010f4bae0b4069d648e741d85ca0e7acb4501f051b27e9b107d3cd7a3f03aa7f776089117c81a0000000002c681c30101ff8a81c3010180e0a596bb11033b7eedf47baf878f3490cb20b696079c34bd017fe59b0d070e74d73ffabc4bb0e05f011decb630f3148d0163b3bd39690dde4078e4cfb69fecf020d6278a27bad10c58023c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".into(), blocktemplate_blob: "1010f4bae0b4069d648e741d85ca0e7acb4501f051b27e9b107d3cd7a3f03aa7f776089117c81a0000000002c681c30101ff8a81c3010180e0a596bb11033b7eedf47baf878f3490cb20b696079c34bd017fe59b0d070e74d73ffabc4bb0e05f011decb630f3148d0163b3bd39690dde4078e4cfb69fecf020d6278a27bad10c58023c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".into(),
difficulty_top64: 0, difficulty_top64: 0,
@ -240,7 +242,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
GET_BLOCK_COUNT_RESPONSE => GetBlockCountResponse { GET_BLOCK_COUNT_RESPONSE => GetBlockCountResponse {
base: ResponseBase::ok(), base: ResponseBase::OK,
count: 3195019, count: 3195019,
} }
)] )]
@ -332,7 +334,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
GENERATE_BLOCKS_RESPONSE => GenerateBlocksResponse { GENERATE_BLOCKS_RESPONSE => GenerateBlocksResponse {
base: ResponseBase::ok(), base: ResponseBase::OK,
blocks: vec!["49b712db7760e3728586f8434ee8bc8d7b3d410dac6bb6e98bf5845c83b917e4".into()], blocks: vec!["49b712db7760e3728586f8434ee8bc8d7b3d410dac6bb6e98bf5845c83b917e4".into()],
height: 9783, height: 9783,
} }
@ -357,7 +359,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
GET_LAST_BLOCK_HEADER_RESPONSE => GetLastBlockHeaderResponse { GET_LAST_BLOCK_HEADER_RESPONSE => GetLastBlockHeaderResponse {
base: AccessResponseBase::ok(), base: AccessResponseBase::OK,
block_header: BlockHeader { block_header: BlockHeader {
block_size: 200419, block_size: 200419,
block_weight: 200419, block_weight: 200419,
@ -409,7 +411,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
GET_BLOCK_HEADER_BY_HASH_RESPONSE => GetBlockHeaderByHashResponse { GET_BLOCK_HEADER_BY_HASH_RESPONSE => GetBlockHeaderByHashResponse {
base: AccessResponseBase::ok(), base: AccessResponseBase::OK,
block_headers: vec![], block_headers: vec![],
block_header: BlockHeader { block_header: BlockHeader {
block_size: 210, block_size: 210,
@ -464,7 +466,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
GET_BLOCK_HEADER_BY_HEIGHT_RESPONSE => GetBlockHeaderByHeightResponse { GET_BLOCK_HEADER_BY_HEIGHT_RESPONSE => GetBlockHeaderByHeightResponse {
base: AccessResponseBase::ok(), base: AccessResponseBase::OK,
block_header: BlockHeader { block_header: BlockHeader {
block_size: 210, block_size: 210,
block_weight: 210, block_weight: 210,
@ -519,7 +521,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
GET_BLOCK_HEADERS_RANGE_RESPONSE => GetBlockHeadersRangeResponse { GET_BLOCK_HEADERS_RANGE_RESPONSE => GetBlockHeadersRangeResponse {
base: AccessResponseBase::ok(), base: AccessResponseBase::OK,
headers: vec![ headers: vec![
BlockHeader { BlockHeader {
block_size: 301413, block_size: 301413,
@ -601,7 +603,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
GET_BLOCK_RESPONSE => GetBlockResponse { GET_BLOCK_RESPONSE => GetBlockResponse {
base: AccessResponseBase::ok(), base: AccessResponseBase::OK,
blob: "1010c58bab9b06b27bdecfc6cd0a46172d136c08831cf67660377ba992332363228b1b722781e7807e07f502cef8a70101ff92f8a7010180e0a596bb1103d7cbf826b665d7a532c316982dc8dbc24f285cbc18bbcc27c7164cd9b3277a85d034019f629d8b36bd16a2bfce3ea80c31dc4d8762c67165aec21845494e32b7582fe00211000000297a787a000000000000000000000000".into(), blob: "1010c58bab9b06b27bdecfc6cd0a46172d136c08831cf67660377ba992332363228b1b722781e7807e07f502cef8a70101ff92f8a7010180e0a596bb1103d7cbf826b665d7a532c316982dc8dbc24f285cbc18bbcc27c7164cd9b3277a85d034019f629d8b36bd16a2bfce3ea80c31dc4d8762c67165aec21845494e32b7582fe00211000000297a787a000000000000000000000000".into(),
block_header: BlockHeader { block_header: BlockHeader {
block_size: 106, block_size: 106,
@ -654,11 +656,11 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
GET_CONNECTIONS_RESPONSE => GetConnectionsResponse { GET_CONNECTIONS_RESPONSE => GetConnectionsResponse {
base: ResponseBase::ok(), base: ResponseBase::OK,
connections: vec![ connections: vec![
ConnectionInfo { ConnectionInfo {
address: "3evk3kezfjg44ma6tvesy7rbxwwpgpympj45xar5fo4qajrsmkoaqdqd.onion:18083".into(), address: "3evk3kezfjg44ma6tvesy7rbxwwpgpympj45xar5fo4qajrsmkoaqdqd.onion:18083".into(),
address_type: 4, address_type: cuprate_types::AddressType::Tor,
avg_download: 0, avg_download: 0,
avg_upload: 0, avg_upload: 0,
connection_id: "22ef856d0f1d44cc95e84fecfd065fe2".into(), connection_id: "22ef856d0f1d44cc95e84fecfd065fe2".into(),
@ -680,12 +682,12 @@ define_request_and_response! {
rpc_port: 0, rpc_port: 0,
send_count: 3406572, send_count: 3406572,
send_idle_time: 30, send_idle_time: 30,
state: "normal".into(), state: cuprate_types::ConnectionState::Normal,
support_flags: 0 support_flags: 0
}, },
ConnectionInfo { ConnectionInfo {
address: "4iykytmumafy5kjahdqc7uzgcs34s2vwsadfjpk4znvsa5vmcxeup2qd.onion:18083".into(), address: "4iykytmumafy5kjahdqc7uzgcs34s2vwsadfjpk4znvsa5vmcxeup2qd.onion:18083".into(),
address_type: 4, address_type: cuprate_types::AddressType::Tor,
avg_download: 0, avg_download: 0,
avg_upload: 0, avg_upload: 0,
connection_id: "c7734e15936f485a86d2b0534f87e499".into(), connection_id: "c7734e15936f485a86d2b0534f87e499".into(),
@ -707,7 +709,7 @@ define_request_and_response! {
rpc_port: 0, rpc_port: 0,
send_count: 3370566, send_count: 3370566,
send_idle_time: 120, send_idle_time: 120,
state: "normal".into(), state: cuprate_types::ConnectionState::Normal,
support_flags: 0 support_flags: 0
} }
], ],
@ -728,7 +730,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
GET_INFO_RESPONSE => GetInfoResponse { GET_INFO_RESPONSE => GetInfoResponse {
base: AccessResponseBase::ok(), base: AccessResponseBase::OK,
adjusted_time: 1721245289, adjusted_time: 1721245289,
alt_blocks_count: 16, alt_blocks_count: 16,
block_size_limit: 600000, block_size_limit: 600000,
@ -831,7 +833,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
HARD_FORK_INFO_RESPONSE => HardForkInfoResponse { HARD_FORK_INFO_RESPONSE => HardForkInfoResponse {
base: AccessResponseBase::ok(), base: AccessResponseBase::OK,
earliest_height: 2689608, earliest_height: 2689608,
enabled: true, enabled: true,
state: 0, state: 0,
@ -877,7 +879,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
SET_BANS_RESPONSE => SetBansResponse { SET_BANS_RESPONSE => SetBansResponse {
base: ResponseBase::ok(), base: ResponseBase::OK,
} }
)] )]
ResponseBase {} ResponseBase {}
@ -892,7 +894,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
GET_BANS_RESPONSE => GetBansResponse { GET_BANS_RESPONSE => GetBansResponse {
base: ResponseBase::ok(), base: ResponseBase::OK,
bans: vec![ bans: vec![
GetBan { GetBan {
host: "104.248.206.131".into(), host: "104.248.206.131".into(),
@ -994,7 +996,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
GET_OUTPUT_HISTOGRAM_RESPONSE => GetOutputHistogramResponse { GET_OUTPUT_HISTOGRAM_RESPONSE => GetOutputHistogramResponse {
base: AccessResponseBase::ok(), base: AccessResponseBase::OK,
histogram: vec![HistogramEntry { histogram: vec![HistogramEntry {
amount: 20000000000, amount: 20000000000,
recent_instances: 0, recent_instances: 0,
@ -1028,7 +1030,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
GET_COINBASE_TX_SUM_RESPONSE => GetCoinbaseTxSumResponse { GET_COINBASE_TX_SUM_RESPONSE => GetCoinbaseTxSumResponse {
base: AccessResponseBase::ok(), base: AccessResponseBase::OK,
emission_amount: 9387854817320, emission_amount: 9387854817320,
emission_amount_top64: 0, emission_amount_top64: 0,
fee_amount: 83981380000, fee_amount: 83981380000,
@ -1057,7 +1059,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
GET_VERSION_RESPONSE => GetVersionResponse { GET_VERSION_RESPONSE => GetVersionResponse {
base: ResponseBase::ok(), base: ResponseBase::OK,
current_height: 3195051, current_height: 3195051,
hard_forks: vec![ hard_forks: vec![
HardforkEntry { HardforkEntry {
@ -1143,12 +1145,16 @@ define_request_and_response! {
get_fee_estimate, get_fee_estimate,
cc73fe71162d564ffda8e549b79a350bca53c454 => cc73fe71162d564ffda8e549b79a350bca53c454 =>
core_rpc_server_commands_defs.h => 2250..=2277, core_rpc_server_commands_defs.h => 2250..=2277,
GetFeeEstimate (empty),
Request {}, GetFeeEstimate,
Request {
grace_blocks: u64 = default_zero::<u64>(), "default_zero",
},
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
GET_FEE_ESTIMATE_RESPONSE => GetFeeEstimateResponse { GET_FEE_ESTIMATE_RESPONSE => GetFeeEstimateResponse {
base: AccessResponseBase::ok(), base: AccessResponseBase::OK,
fee: 20000, fee: 20000,
fees: vec![20000,80000,320000,4000000], fees: vec![20000,80000,320000,4000000],
quantization_mask: 10000, quantization_mask: 10000,
@ -1170,7 +1176,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
GET_ALTERNATE_CHAINS_RESPONSE => GetAlternateChainsResponse { GET_ALTERNATE_CHAINS_RESPONSE => GetAlternateChainsResponse {
base: ResponseBase::ok(), base: ResponseBase::OK,
chains: vec![ chains: vec![
ChainInfo { ChainInfo {
block_hash: "4826c7d45d7cf4f02985b5c405b0e5d7f92c8d25e015492ce19aa3b209295dce".into(), block_hash: "4826c7d45d7cf4f02985b5c405b0e5d7f92c8d25e015492ce19aa3b209295dce".into(),
@ -1238,7 +1244,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
SYNC_INFO_RESPONSE => SyncInfoResponse { SYNC_INFO_RESPONSE => SyncInfoResponse {
base: AccessResponseBase::ok(), base: AccessResponseBase::OK,
height: 3195157, height: 3195157,
next_needed_pruning_seed: 0, next_needed_pruning_seed: 0,
overview: "[]".into(), overview: "[]".into(),
@ -1247,7 +1253,7 @@ define_request_and_response! {
SyncInfoPeer { SyncInfoPeer {
info: ConnectionInfo { info: ConnectionInfo {
address: "142.93.128.65:44986".into(), address: "142.93.128.65:44986".into(),
address_type: 1, address_type: cuprate_types::AddressType::Ipv4,
avg_download: 1, avg_download: 1,
avg_upload: 1, avg_upload: 1,
connection_id: "a5803c4c2dac49e7b201dccdef54c862".into(), connection_id: "a5803c4c2dac49e7b201dccdef54c862".into(),
@ -1269,14 +1275,14 @@ define_request_and_response! {
rpc_port: 18089, rpc_port: 18089,
send_count: 32235, send_count: 32235,
send_idle_time: 6, send_idle_time: 6,
state: "normal".into(), state: cuprate_types::ConnectionState::Normal,
support_flags: 1 support_flags: 1
} }
}, },
SyncInfoPeer { SyncInfoPeer {
info: ConnectionInfo { info: ConnectionInfo {
address: "4iykytmumafy5kjahdqc7uzgcs34s2vwsadfjpk4znvsa5vmcxeup2qd.onion:18083".into(), address: "4iykytmumafy5kjahdqc7uzgcs34s2vwsadfjpk4znvsa5vmcxeup2qd.onion:18083".into(),
address_type: 4, address_type: cuprate_types::AddressType::Tor,
avg_download: 0, avg_download: 0,
avg_upload: 0, avg_upload: 0,
connection_id: "277f7c821bc546878c8bd29977e780f5".into(), connection_id: "277f7c821bc546878c8bd29977e780f5".into(),
@ -1298,7 +1304,7 @@ define_request_and_response! {
rpc_port: 0, rpc_port: 0,
send_count: 99120, send_count: 99120,
send_idle_time: 15, send_idle_time: 15,
state: "normal".into(), state: cuprate_types::ConnectionState::Normal,
support_flags: 0 support_flags: 0
} }
} }
@ -1328,7 +1334,7 @@ define_request_and_response! {
// TODO: enable test after binary string impl. // TODO: enable test after binary string impl.
// #[doc = serde_doc_test!( // #[doc = serde_doc_test!(
// GET_TRANSACTION_POOL_BACKLOG_RESPONSE => GetTransactionPoolBacklogResponse { // GET_TRANSACTION_POOL_BACKLOG_RESPONSE => GetTransactionPoolBacklogResponse {
// base: ResponseBase::ok(), // base: ResponseBase::OK,
// backlog: "...Binary...".into(), // backlog: "...Binary...".into(),
// } // }
// )] // )]
@ -1370,7 +1376,7 @@ define_request_and_response! {
// TODO: enable test after binary string impl. // TODO: enable test after binary string impl.
// #[doc = serde_doc_test!( // #[doc = serde_doc_test!(
// GET_OUTPUT_DISTRIBUTION_RESPONSE => GetOutputDistributionResponse { // GET_OUTPUT_DISTRIBUTION_RESPONSE => GetOutputDistributionResponse {
// base: AccessResponseBase::ok(), // base: AccessResponseBase::OK,
// distributions: vec![Distribution::Uncompressed(DistributionUncompressed { // distributions: vec![Distribution::Uncompressed(DistributionUncompressed {
// start_height: 1462078, // start_height: 1462078,
// base: 0, // base: 0,
@ -1394,7 +1400,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
GET_MINER_DATA_RESPONSE => GetMinerDataResponse { GET_MINER_DATA_RESPONSE => GetMinerDataResponse {
base: ResponseBase::ok(), base: ResponseBase::OK,
already_generated_coins: 18186022843595960691, already_generated_coins: 18186022843595960691,
difficulty: "0x48afae42de".into(), difficulty: "0x48afae42de".into(),
height: 2731375, height: 2731375,
@ -1447,7 +1453,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
PRUNE_BLOCKCHAIN_RESPONSE => PruneBlockchainResponse { PRUNE_BLOCKCHAIN_RESPONSE => PruneBlockchainResponse {
base: ResponseBase::ok(), base: ResponseBase::OK,
pruned: true, pruned: true,
pruning_seed: 387, pruning_seed: 387,
} }
@ -1513,7 +1519,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
FLUSH_CACHE_RESPONSE => FlushCacheResponse { FLUSH_CACHE_RESPONSE => FlushCacheResponse {
base: ResponseBase::ok(), base: ResponseBase::OK,
} }
)] )]
ResponseBase {} ResponseBase {}
@ -1542,7 +1548,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
ADD_AUX_POW_RESPONSE => AddAuxPowResponse { ADD_AUX_POW_RESPONSE => AddAuxPowResponse {
base: ResponseBase::ok(), base: ResponseBase::OK,
aux_pow: vec![AuxPow { aux_pow: vec![AuxPow {
hash: "7b35762de164b20885e15dbe656b1138db06bb402fa1796f5765a23933d8859a".into(), hash: "7b35762de164b20885e15dbe656b1138db06bb402fa1796f5765a23933d8859a".into(),
id: "3200b4ea97c3b2081cd4190b58e49572b2319fed00d030ad51809dff06b5d8c8".into(), id: "3200b4ea97c3b2081cd4190b58e49572b2319fed00d030ad51809dff06b5d8c8".into(),

View file

@ -6,6 +6,7 @@
)] )]
mod constants; mod constants;
#[cfg(any(feature = "serde", feature = "epee"))]
mod defaults; mod defaults;
mod free; mod free;
mod macros; mod macros;

View file

@ -20,8 +20,8 @@ use cuprate_epee_encoding::{
"rpc/core_rpc_server_commands_defs.h", "rpc/core_rpc_server_commands_defs.h",
45..=55 45..=55
)] )]
#[cfg(feature = "epee")] #[cfg(any(feature = "epee", feature = "serde"))]
fn compress_integer_array(_: &[u64]) -> error::Result<Vec<u8>> { fn compress_integer_array(_: &[u64]) -> Vec<u8> {
todo!() todo!()
} }
@ -33,6 +33,7 @@ fn compress_integer_array(_: &[u64]) -> error::Result<Vec<u8>> {
"rpc/core_rpc_server_commands_defs.h", "rpc/core_rpc_server_commands_defs.h",
57..=72 57..=72
)] )]
#[cfg(any(feature = "epee", feature = "serde"))]
fn decompress_integer_array(_: &[u8]) -> Vec<u64> { fn decompress_integer_array(_: &[u8]) -> Vec<u64> {
todo!() todo!()
} }
@ -135,12 +136,7 @@ fn serialize_distribution_as_compressed_data<S>(v: &Vec<u64>, s: S) -> Result<S:
where where
S: serde::Serializer, S: serde::Serializer,
{ {
match compress_integer_array(v) { compress_integer_array(v).serialize(s)
Ok(compressed_data) => compressed_data.serialize(s),
Err(_) => Err(serde::ser::Error::custom(
"error compressing distribution array",
)),
}
} }
/// Deserializer function for [`DistributionCompressedBinary::distribution`]. /// Deserializer function for [`DistributionCompressedBinary::distribution`].
@ -256,7 +252,7 @@ impl EpeeObject for Distribution {
distribution, distribution,
amount, amount,
}) => { }) => {
let compressed_data = compress_integer_array(&distribution)?; let compressed_data = compress_integer_array(&distribution);
start_height.write(w)?; start_height.write(w)?;
base.write(w)?; base.write(w)?;

View file

@ -11,10 +11,10 @@ use serde::{Deserialize, Serialize};
#[cfg(feature = "epee")] #[cfg(feature = "epee")]
use cuprate_epee_encoding::epee_object; use cuprate_epee_encoding::epee_object;
use crate::{ use crate::macros::monero_definition_link;
defaults::{default_string, default_zero},
macros::monero_definition_link, #[cfg(any(feature = "epee", feature = "serde"))]
}; use crate::defaults::default_zero;
//---------------------------------------------------------------------------------------------------- Macros //---------------------------------------------------------------------------------------------------- Macros
/// This macro (local to this file) defines all the misc types. /// This macro (local to this file) defines all the misc types.
@ -110,7 +110,7 @@ define_struct_and_impl_epee! {
/// Used in [`crate::json::GetConnectionsResponse`]. /// Used in [`crate::json::GetConnectionsResponse`].
ConnectionInfo { ConnectionInfo {
address: String, address: String,
address_type: u8, address_type: cuprate_types::AddressType,
avg_download: u64, avg_download: u64,
avg_upload: u64, avg_upload: u64,
connection_id: String, connection_id: String,
@ -135,7 +135,7 @@ define_struct_and_impl_epee! {
// Exists in the original definition, but isn't // Exists in the original definition, but isn't
// used or (de)serialized for RPC purposes. // used or (de)serialized for RPC purposes.
// ssl: bool, // ssl: bool,
state: String, state: cuprate_types::ConnectionState,
support_flags: u32, support_flags: u32,
} }
} }
@ -148,7 +148,7 @@ define_struct_and_impl_epee! {
)] )]
/// Used in [`crate::json::SetBansRequest`]. /// Used in [`crate::json::SetBansRequest`].
SetBan { SetBan {
#[cfg_attr(feature = "serde", serde(default = "default_string"))] #[cfg_attr(feature = "serde", serde(default = "crate::defaults::default_string"))]
host: String, host: String,
#[cfg_attr(feature = "serde", serde(default = "default_zero"))] #[cfg_attr(feature = "serde", serde(default = "default_zero"))]
ip: u32, ip: u32,

View file

@ -8,7 +8,6 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
base::{AccessResponseBase, ResponseBase}, base::{AccessResponseBase, ResponseBase},
defaults::{default_false, default_string, default_true, default_vec, default_zero},
macros::define_request_and_response, macros::define_request_and_response,
misc::{ misc::{
GetOutputsOut, OutKey, Peer, PublicNode, SpentKeyImageInfo, Status, TxEntry, TxInfo, GetOutputsOut, OutKey, Peer, PublicNode, SpentKeyImageInfo, Status, TxEntry, TxInfo,
@ -17,6 +16,9 @@ use crate::{
RpcCallValue, RpcCallValue,
}; };
#[cfg(any(feature = "serde", feature = "epee"))]
use crate::defaults::{default_false, default_string, default_true, default_vec, default_zero};
//---------------------------------------------------------------------------------------------------- Macro //---------------------------------------------------------------------------------------------------- Macro
/// Adds a (de)serialization doc-test to a type in `other.rs`. /// Adds a (de)serialization doc-test to a type in `other.rs`.
/// ///
@ -102,7 +104,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
GET_HEIGHT_RESPONSE => GetHeightResponse { GET_HEIGHT_RESPONSE => GetHeightResponse {
base: ResponseBase::ok(), base: ResponseBase::OK,
hash: "68bb1a1cff8e2a44c3221e8e1aff80bc6ca45d06fa8eff4d2a3a7ac31d4efe3f".into(), hash: "68bb1a1cff8e2a44c3221e8e1aff80bc6ca45d06fa8eff4d2a3a7ac31d4efe3f".into(),
height: 3195160, height: 3195160,
} }
@ -157,7 +159,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
GET_ALT_BLOCKS_HASHES_RESPONSE => GetAltBlocksHashesResponse { GET_ALT_BLOCKS_HASHES_RESPONSE => GetAltBlocksHashesResponse {
base: AccessResponseBase::ok(), base: AccessResponseBase::OK,
blks_hashes: vec!["8ee10db35b1baf943f201b303890a29e7d45437bd76c2bd4df0d2f2ee34be109".into()], blks_hashes: vec!["8ee10db35b1baf943f201b303890a29e7d45437bd76c2bd4df0d2f2ee34be109".into()],
} }
)] )]
@ -187,7 +189,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
IS_KEY_IMAGE_SPENT_RESPONSE => IsKeyImageSpentResponse { IS_KEY_IMAGE_SPENT_RESPONSE => IsKeyImageSpentResponse {
base: AccessResponseBase::ok(), base: AccessResponseBase::OK,
spent_status: vec![1, 1], spent_status: vec![1, 1],
} }
)] )]
@ -283,7 +285,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
START_MINING_RESPONSE => StartMiningResponse { START_MINING_RESPONSE => StartMiningResponse {
base: ResponseBase::ok(), base: ResponseBase::OK,
} }
)] )]
ResponseBase {} ResponseBase {}
@ -298,7 +300,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
STOP_MINING_RESPONSE => StopMiningResponse { STOP_MINING_RESPONSE => StopMiningResponse {
base: ResponseBase::ok(), base: ResponseBase::OK,
} }
)] )]
ResponseBase {} ResponseBase {}
@ -313,7 +315,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
MINING_STATUS_RESPONSE => MiningStatusResponse { MINING_STATUS_RESPONSE => MiningStatusResponse {
base: ResponseBase::ok(), base: ResponseBase::OK,
active: false, active: false,
address: "".into(), address: "".into(),
bg_idle_threshold: 0, bg_idle_threshold: 0,
@ -359,7 +361,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
SAVE_BC_RESPONSE => SaveBcResponse { SAVE_BC_RESPONSE => SaveBcResponse {
base: ResponseBase::ok(), base: ResponseBase::OK,
} }
)] )]
ResponseBase {} ResponseBase {}
@ -385,7 +387,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
GET_PEER_LIST_RESPONSE => GetPeerListResponse { GET_PEER_LIST_RESPONSE => GetPeerListResponse {
base: ResponseBase::ok(), base: ResponseBase::OK,
gray_list: vec![ gray_list: vec![
Peer { Peer {
host: "161.97.193.0".into(), host: "161.97.193.0".into(),
@ -467,7 +469,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
SET_LOG_HASH_RATE_RESPONSE => SetLogHashRateResponse { SET_LOG_HASH_RATE_RESPONSE => SetLogHashRateResponse {
base: ResponseBase::ok(), base: ResponseBase::OK,
} }
)] )]
ResponseBase {} ResponseBase {}
@ -492,7 +494,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
SET_LOG_LEVEL_RESPONSE => SetLogLevelResponse { SET_LOG_LEVEL_RESPONSE => SetLogLevelResponse {
base: ResponseBase::ok(), base: ResponseBase::OK,
} }
)] )]
ResponseBase {} ResponseBase {}
@ -516,7 +518,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
SET_LOG_CATEGORIES_RESPONSE => SetLogCategoriesResponse { SET_LOG_CATEGORIES_RESPONSE => SetLogCategoriesResponse {
base: ResponseBase::ok(), base: ResponseBase::OK,
categories: "*:INFO".into(), categories: "*:INFO".into(),
} }
)] )]
@ -582,7 +584,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
GET_TRANSACTION_POOL_STATS_RESPONSE => GetTransactionPoolStatsResponse { GET_TRANSACTION_POOL_STATS_RESPONSE => GetTransactionPoolStatsResponse {
base: AccessResponseBase::ok(), base: AccessResponseBase::OK,
pool_stats: TxpoolStats { pool_stats: TxpoolStats {
bytes_max: 11843, bytes_max: 11843,
bytes_med: 2219, bytes_med: 2219,
@ -644,7 +646,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
GET_LIMIT_RESPONSE => GetLimitResponse { GET_LIMIT_RESPONSE => GetLimitResponse {
base: ResponseBase::ok(), base: ResponseBase::OK,
limit_down: 1280000, limit_down: 1280000,
limit_up: 1280000, limit_up: 1280000,
} }
@ -676,7 +678,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
SET_LIMIT_RESPONSE => SetLimitResponse { SET_LIMIT_RESPONSE => SetLimitResponse {
base: ResponseBase::ok(), base: ResponseBase::OK,
limit_down: 1024, limit_down: 1024,
limit_up: 128, limit_up: 128,
} }
@ -707,7 +709,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
OUT_PEERS_RESPONSE => OutPeersResponse { OUT_PEERS_RESPONSE => OutPeersResponse {
base: ResponseBase::ok(), base: ResponseBase::OK,
out_peers: 3232235535, out_peers: 3232235535,
} }
)] )]
@ -740,7 +742,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
GET_NET_STATS_RESPONSE => GetNetStatsResponse { GET_NET_STATS_RESPONSE => GetNetStatsResponse {
base: ResponseBase::ok(), base: ResponseBase::OK,
start_time: 1721251858, start_time: 1721251858,
total_bytes_in: 16283817214, total_bytes_in: 16283817214,
total_bytes_out: 34225244079, total_bytes_out: 34225244079,
@ -779,7 +781,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
GET_OUTS_RESPONSE => GetOutsResponse { GET_OUTS_RESPONSE => GetOutsResponse {
base: ResponseBase::ok(), base: ResponseBase::OK,
outs: vec![ outs: vec![
OutKey { OutKey {
height: 51941, height: 51941,
@ -823,7 +825,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
UPDATE_RESPONSE => UpdateResponse { UPDATE_RESPONSE => UpdateResponse {
base: ResponseBase::ok(), base: ResponseBase::OK,
auto_uri: "".into(), auto_uri: "".into(),
hash: "".into(), hash: "".into(),
path: "".into(), path: "".into(),
@ -860,7 +862,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
POP_BLOCKS_RESPONSE => PopBlocksResponse { POP_BLOCKS_RESPONSE => PopBlocksResponse {
base: ResponseBase::ok(), base: ResponseBase::OK,
height: 76482, height: 76482,
} }
)] )]
@ -879,7 +881,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
GET_TRANSACTION_POOL_HASHES_RESPONSE => GetTransactionPoolHashesResponse { GET_TRANSACTION_POOL_HASHES_RESPONSE => GetTransactionPoolHashesResponse {
base: ResponseBase::ok(), base: ResponseBase::OK,
tx_hashes: vec![ tx_hashes: vec![
"aa928aed888acd6152c60194d50a4df29b0b851be6169acf11b6a8e304dd6c03".into(), "aa928aed888acd6152c60194d50a4df29b0b851be6169acf11b6a8e304dd6c03".into(),
"794345f321a98f3135151f3056c0fdf8188646a8dab27de971428acf3551dd11".into(), "794345f321a98f3135151f3056c0fdf8188646a8dab27de971428acf3551dd11".into(),
@ -929,7 +931,7 @@ define_request_and_response! {
#[doc = serde_doc_test!( #[doc = serde_doc_test!(
GET_PUBLIC_NODES_RESPONSE => GetPublicNodesResponse { GET_PUBLIC_NODES_RESPONSE => GetPublicNodesResponse {
base: ResponseBase::ok(), base: ResponseBase::OK,
gray: vec![], gray: vec![],
white: vec![ white: vec![
PublicNode { PublicNode {

View file

@ -9,44 +9,31 @@ repository = "https://github.com/Cuprate/cuprate/tree/main/storage/cuprate-bloc
keywords = ["cuprate", "blockchain", "database"] keywords = ["cuprate", "blockchain", "database"]
[features] [features]
default = ["heed", "service"] default = ["heed"]
# default = ["redb", "service"] # default = ["redb", "service"]
# default = ["redb-memory", "service"] # default = ["redb-memory", "service"]
heed = ["cuprate-database/heed"] heed = ["cuprate-database/heed"]
redb = ["cuprate-database/redb"] redb = ["cuprate-database/redb"]
redb-memory = ["cuprate-database/redb-memory"] redb-memory = ["cuprate-database/redb-memory"]
service = ["dep:thread_local", "dep:rayon", "cuprate-helper/thread"] serde = ["dep:serde", "cuprate-database/serde", "cuprate-database-service/serde"]
[dependencies] [dependencies]
cuprate-database = { workspace = true } cuprate-database = { workspace = true }
cuprate-database-service = { workspace = true } cuprate-database-service = { workspace = true }
cuprate-helper = { workspace = true, features = ["fs", "map", "crypto", "cast"] } cuprate-helper = { workspace = true, features = ["fs", "map", "crypto", "tx", "thread"] }
cuprate-types = { workspace = true, features = ["blockchain"] } cuprate-types = { workspace = true, features = ["blockchain"] }
cuprate-pruning = { workspace = true } cuprate-pruning = { workspace = true }
bitflags = { workspace = true, features = ["std", "serde", "bytemuck"] } bitflags = { workspace = true, features = ["std", "serde", "bytemuck"] }
bytemuck = { workspace = true, features = ["must_cast", "derive", "min_const_generics", "extern_crate_alloc"] } bytemuck = { workspace = true, features = ["must_cast", "derive", "min_const_generics", "extern_crate_alloc"] }
curve25519-dalek = { workspace = true } curve25519-dalek = { workspace = true }
rand = { workspace = true } rand = { workspace = true, features = ["std", "std_rng"] }
monero-serai = { workspace = true, features = ["std"] } monero-serai = { workspace = true, features = ["std"] }
serde = { workspace = true, optional = true } serde = { workspace = true, optional = true }
# `service` feature.
tower = { workspace = true } tower = { workspace = true }
thread_local = { workspace = true, optional = true } thread_local = { workspace = true }
rayon = { workspace = true, optional = true } rayon = { workspace = true }
[dev-dependencies]
cuprate-constants = { workspace = true }
cuprate-helper = { workspace = true, features = ["thread", "cast"] }
cuprate-test-utils = { workspace = true }
tokio = { workspace = true, features = ["full"] }
tempfile = { workspace = true }
pretty_assertions = { workspace = true }
proptest = { workspace = true }
hex = { workspace = true }
hex-literal = { workspace = true }
[lints] [lints]
workspace = true workspace = true

View file

@ -32,9 +32,6 @@ use cuprate_blockchain::{
This ensures the types/traits used from `cuprate_database` are the same ones used by `cuprate_blockchain` internally. This ensures the types/traits used from `cuprate_database` are the same ones used by `cuprate_blockchain` internally.
# Feature flags # Feature flags
The `service` module requires the `service` feature to be enabled.
See the module for more documentation.
Different database backends are enabled by the feature flags: Different database backends are enabled by the feature flags:
- `heed` (LMDB) - `heed` (LMDB)
- `redb` - `redb`
@ -45,7 +42,7 @@ The default is `heed`.
<!-- FIXME: tracing should be behind a feature flag --> <!-- FIXME: tracing should be behind a feature flag -->
# Invariants when not using `service` # Invariants when not using `service`
`cuprate_blockchain` can be used without the `service` feature enabled but `cuprate_blockchain` can be used without the `service` module but
there are some things that must be kept in mind when doing so. there are some things that must be kept in mind when doing so.
Failing to uphold these invariants may cause panics. Failing to uphold these invariants may cause panics.

View file

@ -18,16 +18,12 @@ pub use free::open;
pub mod config; pub mod config;
pub mod ops; pub mod ops;
pub mod service;
pub mod tables; pub mod tables;
pub mod types; pub mod types;
//---------------------------------------------------------------------------------------------------- Feature-gated
#[cfg(feature = "service")]
pub mod service;
//---------------------------------------------------------------------------------------------------- Private //---------------------------------------------------------------------------------------------------- Private
#[cfg(test)] #[cfg(test)]
pub(crate) mod tests; pub(crate) mod tests;
#[cfg(feature = "service")] // only needed in `service` for now
pub(crate) mod unsafe_sendable; pub(crate) mod unsafe_sendable;

View file

@ -10,8 +10,6 @@
//! //!
//! The system is managed by this crate, and only requires [`init`] by the user. //! The system is managed by this crate, and only requires [`init`] by the user.
//! //!
//! This module must be enabled with the `service` feature.
//!
//! ## Handles //! ## Handles
//! The 2 handles to the database are: //! The 2 handles to the database are:
//! - [`BlockchainReadHandle`] //! - [`BlockchainReadHandle`]

View file

@ -121,6 +121,8 @@ fn map_request(
R::DatabaseSize => database_size(env), R::DatabaseSize => database_size(env),
R::OutputHistogram(input) => output_histogram(env, input), R::OutputHistogram(input) => output_histogram(env, input),
R::CoinbaseTxSum { height, count } => coinbase_tx_sum(env, height, count), R::CoinbaseTxSum { height, count } => coinbase_tx_sum(env, height, count),
R::AltChains => alt_chains(env),
R::AltChainCount => alt_chain_count(env),
} }
/* SOMEDAY: post-request handling, run some code for each request? */ /* SOMEDAY: post-request handling, run some code for each request? */
@ -640,3 +642,13 @@ fn output_histogram(env: &ConcreteEnv, input: OutputHistogramInput) -> ResponseR
fn coinbase_tx_sum(env: &ConcreteEnv, height: usize, count: u64) -> ResponseResult { fn coinbase_tx_sum(env: &ConcreteEnv, height: usize, count: u64) -> ResponseResult {
Ok(BlockchainResponse::CoinbaseTxSum(todo!())) Ok(BlockchainResponse::CoinbaseTxSum(todo!()))
} }
/// [`BlockchainReadRequest::AltChains`]
fn alt_chains(env: &ConcreteEnv) -> ResponseResult {
Ok(BlockchainResponse::AltChains(todo!()))
}
/// [`BlockchainReadRequest::AltChainCount`]
fn alt_chain_count(env: &ConcreteEnv) -> ResponseResult {
Ok(BlockchainResponse::AltChainCount(todo!()))
}

View file

@ -9,16 +9,15 @@ repository = "https://github.com/Cuprate/cuprate/tree/main/storage/database"
keywords = ["cuprate", "database"] keywords = ["cuprate", "database"]
[features] [features]
# default = ["heed"] default = ["heed"]
# default = ["redb"] # default = ["redb"]
# default = ["redb-memory"] # default = ["redb-memory"]
heed = ["dep:heed", "dep:cuprate-helper"] heed = []
redb = ["dep:redb"] redb = ["dep:redb"]
redb-memory = ["redb"] redb-memory = ["redb"]
[dependencies] [dependencies]
# `usize_to_u64` needed in `heed` cuprate-helper = { workspace = true, features = ["cast"] }
cuprate-helper = { workspace = true, features = ["cast"], optional = true }
bytemuck = { version = "1.18.0", features = ["must_cast", "derive", "min_const_generics", "extern_crate_alloc"] } bytemuck = { version = "1.18.0", features = ["must_cast", "derive", "min_const_generics", "extern_crate_alloc"] }
bytes = { workspace = true } bytes = { workspace = true }
@ -28,14 +27,9 @@ paste = { workspace = true }
thiserror = { workspace = true } thiserror = { workspace = true }
# Optional features. # Optional features.
heed = { version = "0.20.5", features = ["read-txn-no-tls"], optional = true } heed = { version = "0.20.5", features = ["read-txn-no-tls"] }
redb = { version = "2.1.3", optional = true } redb = { version = "2.1.3", optional = true }
serde = { workspace = true, optional = true } serde = { workspace = true, optional = true }
[dev-dependencies]
bytemuck = { version = "1.18.0", features = ["must_cast", "derive", "min_const_generics", "extern_crate_alloc"] }
page_size = { version = "0.6.0" }
tempfile = { version = "3.12.0" }
[lints] [lints]
workspace = true workspace = true

View file

@ -4,6 +4,8 @@ cfg_if::cfg_if! {
// If both backends are enabled, fallback to `heed`. // If both backends are enabled, fallback to `heed`.
// This is useful when using `--all-features`. // This is useful when using `--all-features`.
if #[cfg(all(feature = "redb", not(feature = "heed")))] { if #[cfg(all(feature = "redb", not(feature = "heed")))] {
use heed as _;
mod redb; mod redb;
pub use redb::ConcreteEnv; pub use redb::ConcreteEnv;
} else { } else {

View file

@ -8,14 +8,20 @@ authors = ["Boog900"]
repository = "https://github.com/Cuprate/cuprate/tree/main/storage/service" repository = "https://github.com/Cuprate/cuprate/tree/main/storage/service"
keywords = ["cuprate", "service", "database"] keywords = ["cuprate", "service", "database"]
[features]
default = ["heed"]
heed = ["cuprate-database/heed"]
redb = ["cuprate-database/redb"]
redb-memorey = ["cuprate-database/redb-memory"]
[dependencies] [dependencies]
cuprate-database = { workspace = true } cuprate-database = { workspace = true }
cuprate-helper = { workspace = true, features = ["fs", "thread", "map"] } cuprate-helper = { workspace = true, features = ["fs", "thread", "map", "asynch"] }
serde = { workspace = true, optional = true } serde = { workspace = true, optional = true }
rayon = { workspace = true } rayon = { workspace = true }
tower = { workspace = true } tower = { workspace = true }
futures = { workspace = true } futures = { workspace = true, features = ["std"] }
crossbeam = { workspace = true, features = ["std"] } crossbeam = { workspace = true, features = ["std"] }
[lints] [lints]

View file

@ -9,18 +9,17 @@ repository = "https://github.com/Cuprate/cuprate/tree/main/storage/txpool"
keywords = ["cuprate", "txpool", "transaction", "pool", "database"] keywords = ["cuprate", "txpool", "transaction", "pool", "database"]
[features] [features]
default = ["heed", "service"] default = ["heed"]
# default = ["redb", "service"] # default = ["redb", "service"]
# default = ["redb-memory", "service"] # default = ["redb-memory", "service"]
heed = ["cuprate-database/heed"] heed = ["cuprate-database/heed"]
redb = ["cuprate-database/redb"] redb = ["cuprate-database/redb"]
redb-memory = ["cuprate-database/redb-memory"] redb-memory = ["cuprate-database/redb-memory"]
service = ["dep:tower", "dep:rayon", "dep:cuprate-database-service"]
serde = ["dep:serde", "cuprate-database/serde", "cuprate-database-service/serde"] serde = ["dep:serde", "cuprate-database/serde", "cuprate-database-service/serde"]
[dependencies] [dependencies]
cuprate-database = { workspace = true, features = ["heed"] } cuprate-database = { workspace = true, features = ["heed"] }
cuprate-database-service = { workspace = true, optional = true } cuprate-database-service = { workspace = true }
cuprate-types = { workspace = true } cuprate-types = { workspace = true }
cuprate-helper = { workspace = true, default-features = false, features = ["constants"] } cuprate-helper = { workspace = true, default-features = false, features = ["constants"] }
@ -28,20 +27,13 @@ monero-serai = { workspace = true, features = ["std"] }
bytemuck = { workspace = true, features = ["must_cast", "derive", "min_const_generics", "extern_crate_alloc"] } bytemuck = { workspace = true, features = ["must_cast", "derive", "min_const_generics", "extern_crate_alloc"] }
bitflags = { workspace = true, features = ["std", "serde", "bytemuck"] } bitflags = { workspace = true, features = ["std", "serde", "bytemuck"] }
thiserror = { workspace = true } thiserror = { workspace = true }
hex = { workspace = true } hex = { workspace = true, features = ["std"] }
blake3 = { workspace = true, features = ["std"] } blake3 = { workspace = true, features = ["std"] }
tower = { workspace = true, optional = true } tower = { workspace = true }
rayon = { workspace = true, optional = true } rayon = { workspace = true }
serde = { workspace = true, optional = true } serde = { workspace = true, optional = true }
[dev-dependencies]
cuprate-test-utils = { workspace = true }
tokio = { workspace = true }
tempfile = { workspace = true }
hex-literal = { workspace = true }
[lints] [lints]
workspace = true workspace = true

View file

@ -37,10 +37,6 @@ use cuprate_txpool::{
This ensures the types/traits used from `cuprate_database` are the same ones used by `cuprate_txpool` internally. This ensures the types/traits used from `cuprate_database` are the same ones used by `cuprate_txpool` internally.
# Feature flags # Feature flags
The `service` module requires the `service` feature to be enabled.
See the module for more documentation.
Different database backends are enabled by the feature flags: Different database backends are enabled by the feature flags:
- `heed` (LMDB) - `heed` (LMDB)

View file

@ -4,10 +4,12 @@
clippy::significant_drop_tightening clippy::significant_drop_tightening
)] )]
// Used in docs: <https://github.com/Cuprate/cuprate/pull/170#discussion_r1823644357>.
use tower as _;
pub mod config; pub mod config;
mod free; mod free;
pub mod ops; pub mod ops;
#[cfg(feature = "service")]
pub mod service; pub mod service;
pub mod tables; pub mod tables;
mod tx; mod tx;
@ -20,8 +22,6 @@ pub use tx::TxEntry;
//re-exports //re-exports
pub use cuprate_database; pub use cuprate_database;
// TODO: remove when used.
use tower as _;
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use cuprate_test_utils as _; use cuprate_test_utils as _;

View file

@ -10,8 +10,6 @@
//! //!
//! The system is managed by this crate, and only requires [`init`] by the user. //! The system is managed by this crate, and only requires [`init`] by the user.
//! //!
//! This module must be enabled with the `service` feature.
//!
//! ## Handles //! ## Handles
//! The 2 handles to the database are: //! The 2 handles to the database are:
//! - [`TxpoolReadHandle`] //! - [`TxpoolReadHandle`]
@ -42,7 +40,7 @@
//! To interact with the database (whether reading or writing data), //! To interact with the database (whether reading or writing data),
//! a `Request` can be sent using one of the above handles. //! a `Request` can be sent using one of the above handles.
//! //!
//! Both the handles implement `tower::Service`, so they can be [`tower::Service::call`]ed. //! Both the handles implement [`tower::Service`], so they can be [`tower::Service::call`]ed.
//! //!
//! An `async`hronous channel will be returned from the call. //! An `async`hronous channel will be returned from the call.
//! This channel can be `.await`ed upon to (eventually) receive //! This channel can be `.await`ed upon to (eventually) receive

View file

@ -35,7 +35,11 @@ pub enum TxpoolReadRequest {
Backlog, Backlog,
/// Get the number of transactions in the pool. /// Get the number of transactions in the pool.
Size, Size {
/// If this is [`true`], the size returned will
/// include private transactions in the pool.
include_sensitive_txs: bool,
},
} }
//---------------------------------------------------------------------------------------------------- TxpoolReadResponse //---------------------------------------------------------------------------------------------------- TxpoolReadResponse
@ -66,7 +70,7 @@ pub enum TxpoolReadResponse {
/// Response to [`TxpoolReadRequest::Backlog`]. /// Response to [`TxpoolReadRequest::Backlog`].
/// ///
/// The inner `Vec` contains information on all /// The inner [`Vec`] contains information on all
/// the transactions currently in the pool. /// the transactions currently in the pool.
Backlog(Vec<TxEntry>), Backlog(Vec<TxEntry>),

View file

@ -71,7 +71,9 @@ fn map_request(
} }
TxpoolReadRequest::TxsForBlock(txs_needed) => txs_for_block(env, txs_needed), TxpoolReadRequest::TxsForBlock(txs_needed) => txs_for_block(env, txs_needed),
TxpoolReadRequest::Backlog => backlog(env), TxpoolReadRequest::Backlog => backlog(env),
TxpoolReadRequest::Size => size(env), TxpoolReadRequest::Size {
include_sensitive_txs,
} => size(env, include_sensitive_txs),
} }
} }
@ -201,6 +203,6 @@ fn backlog(env: &ConcreteEnv) -> ReadResponseResult {
/// [`TxpoolReadRequest::Size`]. /// [`TxpoolReadRequest::Size`].
#[inline] #[inline]
fn size(env: &ConcreteEnv) -> ReadResponseResult { fn size(env: &ConcreteEnv, include_sensitive_txs: bool) -> ReadResponseResult {
Ok(TxpoolReadResponse::Size(todo!())) Ok(TxpoolReadResponse::Size(todo!()))
} }

View file

@ -5,6 +5,8 @@
/// Used in [`TxpoolReadResponse::Backlog`](crate::service::interface::TxpoolReadResponse::Backlog). /// Used in [`TxpoolReadResponse::Backlog`](crate::service::interface::TxpoolReadResponse::Backlog).
#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] #[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct TxEntry { pub struct TxEntry {
/// The transaction's ID (hash).
pub id: [u8; 32],
/// The transaction's weight. /// The transaction's weight.
pub weight: u64, pub weight: u64,
/// The transaction's fee. /// The transaction's fee.

View file

@ -26,9 +26,5 @@ tempfile = { workspace = true }
paste = { workspace = true } paste = { workspace = true }
borsh = { workspace = true, features = ["derive"]} borsh = { workspace = true, features = ["derive"]}
[dev-dependencies]
hex = { workspace = true }
pretty_assertions = { workspace = true }
[lints] [lints]
workspace = true workspace = true

View file

@ -12,31 +12,28 @@ keywords = ["cuprate", "types"]
default = ["blockchain", "epee", "serde", "json", "hex"] default = ["blockchain", "epee", "serde", "json", "hex"]
blockchain = [] blockchain = []
epee = ["dep:cuprate-epee-encoding"] epee = ["dep:cuprate-epee-encoding"]
serde = ["dep:serde"] serde = ["dep:serde", "hex"]
proptest = ["dep:proptest", "dep:proptest-derive"] proptest = ["dep:proptest", "dep:proptest-derive"]
json = ["hex", "dep:cuprate-helper"] json = ["hex", "dep:cuprate-helper"]
hex = ["dep:hex"] # We sadly have no choice but to enable serde here as otherwise we will get warnings from the `hex` dep being unused.
# This isn't too bad as `HexBytes` only makes sense with serde anyway.
hex = ["serde", "dep:hex"]
[dependencies] [dependencies]
cuprate-epee-encoding = { workspace = true, optional = true, features = ["std"] } cuprate-epee-encoding = { workspace = true, optional = true, features = ["std"] }
cuprate-helper = { workspace = true, optional = true, features = ["cast"] } cuprate-helper = { workspace = true, optional = true, features = ["cast"] }
cuprate-fixed-bytes = { workspace = true } cuprate-fixed-bytes = { workspace = true, features = ["std", "serde"] }
bytes = { workspace = true } bytes = { workspace = true }
curve25519-dalek = { workspace = true } curve25519-dalek = { workspace = true }
monero-serai = { workspace = true } monero-serai = { workspace = true }
hex = { workspace = true, features = ["serde", "alloc"], optional = true } hex = { workspace = true, features = ["serde", "alloc"], optional = true }
serde = { workspace = true, features = ["derive"], optional = true } serde = { workspace = true, features = ["std", "derive"], optional = true }
strum = { workspace = true, features = ["derive"] } strum = { workspace = true, features = ["derive"] }
thiserror = { workspace = true } thiserror = { workspace = true }
proptest = { workspace = true, optional = true } proptest = { workspace = true, optional = true }
proptest-derive = { workspace = true, optional = true } proptest-derive = { workspace = true, optional = true }
[dev-dependencies]
hex-literal = { workspace = true }
pretty_assertions = { workspace = true }
serde_json = { workspace = true, features = ["std"] }
[lints] [lints]
workspace = true workspace = true

147
types/src/address_type.rs Normal file
View file

@ -0,0 +1,147 @@
//! Types of network addresses; used in P2P.
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "epee")]
use cuprate_epee_encoding::{
error,
macros::bytes::{Buf, BufMut},
EpeeValue, Marker,
};
use strum::{
AsRefStr, Display, EnumCount, EnumIs, EnumString, FromRepr, IntoStaticStr, VariantArray,
};
/// An enumeration of address types.
///
/// Used in `cuprate_p2p` and `cuprate_types`
///
/// Original definition:
/// - <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/epee/include/net/enums.h/#L49>
///
/// # Serde
/// This type's `serde` implementation (de)serializes from a [`u8`].
///
/// ```rust
/// use cuprate_types::AddressType as A;
/// use serde_json::{to_string, from_str};
///
/// assert_eq!(from_str::<A>(&"0").unwrap(), A::Invalid);
/// assert_eq!(from_str::<A>(&"1").unwrap(), A::Ipv4);
/// assert_eq!(from_str::<A>(&"2").unwrap(), A::Ipv6);
/// assert_eq!(from_str::<A>(&"3").unwrap(), A::I2p);
/// assert_eq!(from_str::<A>(&"4").unwrap(), A::Tor);
///
/// assert_eq!(to_string(&A::Invalid).unwrap(), "0");
/// assert_eq!(to_string(&A::Ipv4).unwrap(), "1");
/// assert_eq!(to_string(&A::Ipv6).unwrap(), "2");
/// assert_eq!(to_string(&A::I2p).unwrap(), "3");
/// assert_eq!(to_string(&A::Tor).unwrap(), "4");
/// ```
#[derive(
Copy,
Clone,
Default,
Debug,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
AsRefStr,
Display,
EnumCount,
EnumIs,
EnumString,
FromRepr,
IntoStaticStr,
VariantArray,
)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(untagged, try_from = "u8", into = "u8"))]
#[repr(u8)]
pub enum AddressType {
#[default]
Invalid,
Ipv4,
Ipv6,
I2p,
Tor,
}
impl AddressType {
/// Convert [`Self`] to a [`u8`].
///
/// ```rust
/// use cuprate_types::AddressType as A;
///
/// assert_eq!(A::Invalid.to_u8(), 0);
/// assert_eq!(A::Ipv4.to_u8(), 1);
/// assert_eq!(A::Ipv6.to_u8(), 2);
/// assert_eq!(A::I2p.to_u8(), 3);
/// assert_eq!(A::Tor.to_u8(), 4);
/// ```
pub const fn to_u8(self) -> u8 {
self as u8
}
/// Convert a [`u8`] to a [`Self`].
///
/// # Errors
/// This returns [`None`] if `u > 4`.
///
/// ```rust
/// use cuprate_types::AddressType as A;
///
/// assert_eq!(A::from_u8(0), Some(A::Invalid));
/// assert_eq!(A::from_u8(1), Some(A::Ipv4));
/// assert_eq!(A::from_u8(2), Some(A::Ipv6));
/// assert_eq!(A::from_u8(3), Some(A::I2p));
/// assert_eq!(A::from_u8(4), Some(A::Tor));
/// assert_eq!(A::from_u8(5), None);
/// ```
pub const fn from_u8(u: u8) -> Option<Self> {
Some(match u {
0 => Self::Invalid,
1 => Self::Ipv4,
2 => Self::Ipv6,
3 => Self::I2p,
4 => Self::Tor,
_ => return None,
})
}
}
impl From<AddressType> for u8 {
fn from(value: AddressType) -> Self {
value.to_u8()
}
}
impl TryFrom<u8> for AddressType {
type Error = u8;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match Self::from_u8(value) {
Some(s) => Ok(s),
None => Err(value),
}
}
}
#[cfg(feature = "epee")]
impl EpeeValue for AddressType {
const MARKER: Marker = u8::MARKER;
fn read<B: Buf>(r: &mut B, marker: &Marker) -> error::Result<Self> {
let u = u8::read(r, marker)?;
Self::from_u8(u).ok_or(error::Error::Format("u8 was greater than 4"))
}
fn write<B: BufMut>(self, w: &mut B) -> error::Result<()> {
let u = self.to_u8();
u8::write(u, w)?;
Ok(())
}
}

View file

@ -136,7 +136,7 @@ impl TransactionBlobs {
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct PrunedTxBlobEntry { pub struct PrunedTxBlobEntry {
/// The transaction. /// The transaction.
pub tx: Bytes, pub blob: Bytes,
/// The prunable transaction hash. /// The prunable transaction hash.
pub prunable_hash: ByteArray<32>, pub prunable_hash: ByteArray<32>,
} }
@ -144,7 +144,7 @@ pub struct PrunedTxBlobEntry {
#[cfg(feature = "epee")] #[cfg(feature = "epee")]
epee_object!( epee_object!(
PrunedTxBlobEntry, PrunedTxBlobEntry,
tx: Bytes, blob: Bytes,
prunable_hash: ByteArray<32>, prunable_hash: ByteArray<32>,
); );

View file

@ -12,7 +12,8 @@ use monero_serai::block::Block;
use crate::{ use crate::{
types::{Chain, ExtendedBlockHeader, OutputOnChain, VerifiedBlockInformation}, types::{Chain, ExtendedBlockHeader, OutputOnChain, VerifiedBlockInformation},
AltBlockInformation, ChainId, CoinbaseTxSum, OutputHistogramEntry, OutputHistogramInput, AltBlockInformation, ChainId, ChainInfo, CoinbaseTxSum, OutputHistogramEntry,
OutputHistogramInput,
}; };
//---------------------------------------------------------------------------------------------------- ReadRequest //---------------------------------------------------------------------------------------------------- ReadRequest
@ -128,6 +129,12 @@ pub enum BlockchainReadRequest {
/// ///
/// TODO: document fields after impl. /// TODO: document fields after impl.
CoinbaseTxSum { height: usize, count: u64 }, CoinbaseTxSum { height: usize, count: u64 },
/// Get information on all alternative chains.
AltChains,
/// Get the amount of alternative chains that exist.
AltChainCount,
} }
//---------------------------------------------------------------------------------------------------- WriteRequest //---------------------------------------------------------------------------------------------------- WriteRequest
@ -276,6 +283,12 @@ pub enum BlockchainResponse {
/// Response to [`BlockchainReadRequest::CoinbaseTxSum`]. /// Response to [`BlockchainReadRequest::CoinbaseTxSum`].
CoinbaseTxSum(CoinbaseTxSum), CoinbaseTxSum(CoinbaseTxSum),
/// Response to [`BlockchainReadRequest::AltChains`].
AltChains(Vec<ChainInfo>),
/// Response to [`BlockchainReadRequest::AltChainCount`].
AltChainCount(usize),
//------------------------------------------------------ Writes //------------------------------------------------------ Writes
/// A generic Ok response to indicate a request was successfully handled. /// A generic Ok response to indicate a request was successfully handled.
/// ///

View file

@ -0,0 +1,148 @@
//! [`ConnectionState`].
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "epee")]
use cuprate_epee_encoding::{
error,
macros::bytes::{Buf, BufMut},
EpeeValue, Marker,
};
use strum::{
AsRefStr, Display, EnumCount, EnumIs, EnumString, FromRepr, IntoStaticStr, VariantArray,
};
/// An enumeration of P2P connection states.
///
/// Used in `cuprate_p2p` and `cuprate_rpc_types`.
///
/// Original definition:
/// - <https://github.com/monero-project/monero/blob/893916ad091a92e765ce3241b94e706ad012b62a/src/cryptonote_basic/connection_context.h#L49>
///
/// # Serde
/// This type's `serde` implementation depends on `snake_case`.
///
/// ```rust
/// use cuprate_types::ConnectionState as C;
/// use serde_json::to_string;
///
/// assert_eq!(to_string(&C::BeforeHandshake).unwrap(), r#""before_handshake""#);
/// assert_eq!(to_string(&C::Synchronizing).unwrap(), r#""synchronizing""#);
/// assert_eq!(to_string(&C::Standby).unwrap(), r#""standby""#);
/// assert_eq!(to_string(&C::Idle).unwrap(), r#""idle""#);
/// assert_eq!(to_string(&C::Normal).unwrap(), r#""normal""#);
///
/// assert_eq!(C::BeforeHandshake.to_string(), "before_handshake");
/// assert_eq!(C::Synchronizing.to_string(), "synchronizing");
/// assert_eq!(C::Standby.to_string(), "standby");
/// assert_eq!(C::Idle.to_string(), "idle");
/// assert_eq!(C::Normal.to_string(), "normal");
/// ```
#[derive(
Copy,
Clone,
Default,
Debug,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
AsRefStr,
Display,
EnumCount,
EnumIs,
EnumString,
FromRepr,
IntoStaticStr,
VariantArray,
)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] // cuprate-rpc-types depends on snake_case
#[strum(serialize_all = "snake_case")]
#[repr(u8)]
pub enum ConnectionState {
BeforeHandshake,
Synchronizing,
Standby,
Idle,
#[default]
Normal,
}
impl ConnectionState {
/// Convert [`Self`] to a [`u8`].
///
/// ```rust
/// use cuprate_types::ConnectionState as C;
///
/// assert_eq!(C::BeforeHandshake.to_u8(), 0);
/// assert_eq!(C::Synchronizing.to_u8(), 1);
/// assert_eq!(C::Standby.to_u8(), 2);
/// assert_eq!(C::Idle.to_u8(), 3);
/// assert_eq!(C::Normal.to_u8(), 4);
/// ```
pub const fn to_u8(self) -> u8 {
self as u8
}
/// Convert a [`u8`] to a [`Self`].
///
/// # Errors
/// This returns [`None`] if `u > 4`.
///
/// ```rust
/// use cuprate_types::ConnectionState as C;
///
/// assert_eq!(C::from_u8(0), Some(C::BeforeHandshake));
/// assert_eq!(C::from_u8(1), Some(C::Synchronizing));
/// assert_eq!(C::from_u8(2), Some(C::Standby));
/// assert_eq!(C::from_u8(3), Some(C::Idle));
/// assert_eq!(C::from_u8(4), Some(C::Normal));
/// assert_eq!(C::from_u8(5), None);
/// ```
pub const fn from_u8(u: u8) -> Option<Self> {
Some(match u {
0 => Self::BeforeHandshake,
1 => Self::Synchronizing,
2 => Self::Standby,
3 => Self::Idle,
4 => Self::Normal,
_ => return None,
})
}
}
impl From<ConnectionState> for u8 {
fn from(value: ConnectionState) -> Self {
value.to_u8()
}
}
impl TryFrom<u8> for ConnectionState {
type Error = u8;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match Self::from_u8(value) {
Some(s) => Ok(s),
None => Err(value),
}
}
}
#[cfg(feature = "epee")]
impl EpeeValue for ConnectionState {
const MARKER: Marker = u8::MARKER;
fn read<B: Buf>(r: &mut B, marker: &Marker) -> error::Result<Self> {
let u = u8::read(r, marker)?;
Self::from_u8(u).ok_or(error::Error::Format("u8 was greater than 4"))
}
fn write<B: BufMut>(self, w: &mut B) -> error::Result<()> {
let u = self.to_u8();
u8::write(u, w)?;
Ok(())
}
}

View file

@ -22,6 +22,7 @@ pub struct HexBytes<const N: usize>(
#[cfg_attr(feature = "serde", serde(with = "hex::serde"))] pub [u8; N], #[cfg_attr(feature = "serde", serde(with = "hex::serde"))] pub [u8; N],
); );
#[cfg(feature = "serde")]
impl<'de, const N: usize> Deserialize<'de> for HexBytes<N> impl<'de, const N: usize> Deserialize<'de> for HexBytes<N>
where where
[u8; N]: hex::FromHex, [u8; N]: hex::FromHex,

View file

@ -51,17 +51,17 @@ impl From<block::Block> for Block {
/// [`Block::miner_tx`]. /// [`Block::miner_tx`].
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[serde(untagged)] #[cfg_attr(feature = "serde", serde(untagged))]
pub enum MinerTransaction { pub enum MinerTransaction {
V1 { V1 {
/// This field is [flattened](https://serde.rs/field-attrs.html#flatten). /// This field is [flattened](https://serde.rs/field-attrs.html#flatten).
#[serde(flatten)] #[cfg_attr(feature = "serde", serde(flatten))]
prefix: MinerTransactionPrefix, prefix: MinerTransactionPrefix,
signatures: [(); 0], signatures: [(); 0],
}, },
V2 { V2 {
/// This field is [flattened](https://serde.rs/field-attrs.html#flatten). /// This field is [flattened](https://serde.rs/field-attrs.html#flatten).
#[serde(flatten)] #[cfg_attr(feature = "serde", serde(flatten))]
prefix: MinerTransactionPrefix, prefix: MinerTransactionPrefix,
rct_signatures: MinerTransactionRctSignatures, rct_signatures: MinerTransactionRctSignatures,
}, },

View file

@ -20,7 +20,7 @@ pub struct Output {
/// [`Output::target`]. /// [`Output::target`].
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[serde(untagged)] #[cfg_attr(feature = "serde", serde(untagged))]
pub enum Target { pub enum Target {
Key { key: HexBytes<32> }, Key { key: HexBytes<32> },
TaggedKey { tagged_key: TaggedKey }, TaggedKey { tagged_key: TaggedKey },

View file

@ -24,17 +24,17 @@ use crate::{
/// - [`/get_transaction_pool` -> `tx_json`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#get_transaction_pool) /// - [`/get_transaction_pool` -> `tx_json`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#get_transaction_pool)
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[serde(untagged)] #[cfg_attr(feature = "serde", serde(untagged))]
pub enum Transaction { pub enum Transaction {
V1 { V1 {
/// This field is [flattened](https://serde.rs/field-attrs.html#flatten). /// This field is [flattened](https://serde.rs/field-attrs.html#flatten).
#[serde(flatten)] #[cfg_attr(feature = "serde", serde(flatten))]
prefix: TransactionPrefix, prefix: TransactionPrefix,
signatures: Vec<HexBytes<64>>, signatures: Vec<HexBytes<64>>,
}, },
V2 { V2 {
/// This field is [flattened](https://serde.rs/field-attrs.html#flatten). /// This field is [flattened](https://serde.rs/field-attrs.html#flatten).
#[serde(flatten)] #[cfg_attr(feature = "serde", serde(flatten))]
prefix: TransactionPrefix, prefix: TransactionPrefix,
rct_signatures: RctSignatures, rct_signatures: RctSignatures,
/// This field is [`Some`] if [`Self::V2::rct_signatures`] /// This field is [`Some`] if [`Self::V2::rct_signatures`]

View file

@ -9,20 +9,25 @@
// //
// Documentation for each module is located in the respective file. // Documentation for each module is located in the respective file.
mod address_type;
mod block_complete_entry; mod block_complete_entry;
mod connection_state;
mod hard_fork; mod hard_fork;
mod transaction_verification_data; mod transaction_verification_data;
mod types; mod types;
pub use address_type::AddressType;
pub use block_complete_entry::{BlockCompleteEntry, PrunedTxBlobEntry, TransactionBlobs}; pub use block_complete_entry::{BlockCompleteEntry, PrunedTxBlobEntry, TransactionBlobs};
pub use connection_state::ConnectionState;
pub use hard_fork::{HardFork, HardForkError}; pub use hard_fork::{HardFork, HardForkError};
pub use transaction_verification_data::{ pub use transaction_verification_data::{
CachedVerificationState, TransactionVerificationData, TxVersion, CachedVerificationState, TransactionVerificationData, TxVersion,
}; };
pub use types::{ pub use types::{
AltBlockInformation, Chain, ChainId, ChainInfo, CoinbaseTxSum, ExtendedBlockHeader, AddAuxPow, AltBlockInformation, AuxPow, Chain, ChainId, ChainInfo, CoinbaseTxSum,
FeeEstimate, HardForkInfo, MinerData, MinerDataTxBacklogEntry, OutputHistogramEntry, ExtendedBlockHeader, FeeEstimate, HardForkInfo, MinerData, MinerDataTxBacklogEntry,
OutputHistogramInput, OutputOnChain, VerifiedBlockInformation, VerifiedTransactionInformation, OutputHistogramEntry, OutputHistogramInput, OutputOnChain, VerifiedBlockInformation,
VerifiedTransactionInformation,
}; };
//---------------------------------------------------------------------------------------------------- Feature-gated //---------------------------------------------------------------------------------------------------- Feature-gated

View file

@ -177,8 +177,6 @@ pub struct OutputHistogramEntry {
pub struct CoinbaseTxSum { pub struct CoinbaseTxSum {
pub emission_amount: u128, pub emission_amount: u128,
pub fee_amount: u128, pub fee_amount: u128,
pub wide_emission_amount: u128,
pub wide_fee_amount: u128,
} }
/// Data to create a custom block template. /// Data to create a custom block template.
@ -242,7 +240,23 @@ pub struct ChainInfo {
pub height: u64, pub height: u64,
pub length: u64, pub length: u64,
pub main_chain_parent_block: [u8; 32], pub main_chain_parent_block: [u8; 32],
pub wide_difficulty: u128, }
/// Used in RPC's `add_aux_pow`.
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AuxPow {
pub id: [u8; 32],
pub hash: [u8; 32],
}
/// Used in RPC's `add_aux_pow`.
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AddAuxPow {
pub blocktemplate_blob: Vec<u8>,
pub blockhashing_blob: Vec<u8>,
pub merkle_root: [u8; 32],
pub merkle_tree_depth: u64,
pub aux_pow: Vec<AuxPow>,
} }
//---------------------------------------------------------------------------------------------------- Tests //---------------------------------------------------------------------------------------------------- Tests