Merge branch 'main' into benches

This commit is contained in:
hinto.janai 2024-10-03 20:05:34 -04:00
commit 39fe790553
No known key found for this signature in database
GPG key ID: D47CE05FA175A499
482 changed files with 26954 additions and 8698 deletions

4
.github/labeler.yml vendored
View file

@ -56,6 +56,10 @@ A-cryptonight:
- changed-files:
- any-glob-to-any-file: cryptonight/**
A-constants:
- changed-files:
- any-glob-to-any-file: constants/**
A-storage:
- changed-files:
- any-glob-to-any-file: storage/**

40
.github/workflows/architecture-book.yml vendored Normal file
View file

@ -0,0 +1,40 @@
# This action attempts to build the architecture book, if changed.
name: Architecture mdBook
on:
push:
branches: ['main']
paths: ['books/architecture/**']
pull_request:
paths: ['books/architecture/**']
workflow_dispatch:
env:
# Version of `mdbook` to install.
MDBOOK_VERSION: 0.4.36
# Version of `mdbook-last-changed` to install.
# <https://github.com/badboy/mdbook-last-changed>.
MDBOOK_LAST_CHANGED_VERSION: 0.1.4
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Cache
uses: actions/cache@v4
with:
path: |
~/.cargo/bin/mdbook
~/.cargo/bin/mdbook-last-changed
key: architecture-book
- name: Install mdBook
run: |
cargo install --locked --version ${MDBOOK_VERSION} mdbook || echo "mdbook already exists"
cargo install --locked --version ${MDBOOK_LAST_CHANGED_VERSION} mdbook-last-changed || echo "mdbook-last-changed already exists"
- name: Build
run: mdbook build books/architecture

View file

@ -7,6 +7,7 @@ on:
paths:
- '**/Cargo.toml'
- '**/Cargo.lock'
workflow_dispatch:
env:
CARGO_TERM_COLOR: always

View file

@ -7,6 +7,7 @@ on:
paths:
- '**/Cargo.toml'
- '**/Cargo.lock'
workflow_dispatch:
env:
CARGO_TERM_COLOR: always

74
.github/workflows/doc.yml vendored Normal file
View file

@ -0,0 +1,74 @@
# This builds `cargo doc` and uploads it to the repo's GitHub Pages.
name: Doc
on:
push:
branches: [ "main" ] # Only deploy if `main` changes.
workflow_dispatch:
env:
# Show colored output in CI.
CARGO_TERM_COLOR: always
# Generate an index page.
RUSTDOCFLAGS: '--cfg docsrs --show-type-layout --enable-index-page -Zunstable-options'
jobs:
# Build documentation.
build:
# FIXME: how to build and merge Windows + macOS docs
# with Linux's? Similar to the OS toggle on docs.rs.
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Rust
uses: dtolnay/rust-toolchain@master
with:
# Nightly required for some `cargo doc` settings.
toolchain: nightly
- name: Cache
uses: actions/cache@v4
with:
# Don't cache actual doc files, just build files.
# This is so that removed crates don't show up.
path: target/debug
key: doc
# Packages other than `Boost` used by `Monero` are listed here.
# https://github.com/monero-project/monero/blob/c444a7e002036e834bfb4c68f04a121ce1af5825/.github/workflows/build.yml#L71
- name: Install dependencies (Linux)
run: sudo apt install -y libboost-dev
- name: Documentation
run: cargo +nightly doc --workspace --all-features
- name: Upload documentation
uses: actions/upload-pages-artifact@v3
with:
path: target/doc/
# Deployment job.
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

40
.github/workflows/monero-book.yml vendored Normal file
View file

@ -0,0 +1,40 @@
# This action attempts to build the Monero book, if changed.
name: Monero mdBook
on:
push:
branches: ['main']
paths: ['books/protocol/**']
pull_request:
paths: ['books/protocol/**']
workflow_dispatch:
env:
# Version of `mdbook` to install.
MDBOOK_VERSION: 0.4.36
# Version of `mdbook-svgbob` to install.
# <https://github.com/boozook/mdbook-svgbob>.
MDBOOK_SVGBOB_VERSION: 0.2.1
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Cache
uses: actions/cache@v4
with:
path: |
~/.cargo/bin/mdbook
~/.cargo/bin/mdbook-svgbob
key: monero-book
- name: Install mdBook
run: |
cargo install --locked --version ${MDBOOK_VERSION} mdbook || echo "mdbook already exists"
cargo install --locked --version ${MDBOOK_SVGBOB_VERSION} mdbook-svgbob || echo "mdbook-svgbob already exists"
- name: Build
run: mdbook build books/protocol

40
.github/workflows/user-book.yml vendored Normal file
View file

@ -0,0 +1,40 @@
# This action attempts to build the user book, if changed.
name: User mdBook
on:
push:
branches: ['main']
paths: ['books/user/**']
pull_request:
paths: ['books/user/**']
workflow_dispatch:
env:
# Version of `mdbook` to install.
MDBOOK_VERSION: 0.4.36
# Version of `mdbook-last-changed` to install.
# <https://github.com/badboy/mdbook-last-changed>.
MDBOOK_LAST_CHANGED_VERSION: 0.1.4
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Cache
uses: actions/cache@v4
with:
path: |
~/.cargo/bin/mdbook
~/.cargo/bin/mdbook-last-changed
key: user-book
- name: Install mdBook
run: |
cargo install --locked --version ${MDBOOK_VERSION} mdbook || echo "mdbook already exists"
cargo install --locked --version ${MDBOOK_LAST_CHANGED_VERSION} mdbook-last-changed || echo "mdbook-last-changed already exists"
- name: Build
run: mdbook build books/user

View file

@ -216,9 +216,9 @@ The description of pull requests should generally follow the template laid out i
If your pull request is long and/or has sections that need clarifying, consider leaving a review on your own PR with comments explaining the changes.
## 5. Documentation
Cuprate's crates (libraries) have inline documentation.
Cuprate's crates (libraries) have inline documentation, they are published from the `main` branch at https://doc.cuprate.org.
These can be built and viewed using the `cargo` tool. For example, to build and view a specific crate's documentation, run the following command at the repository's root:
Documentation can be built and viewed using the `cargo` tool. For example, to build and view a specific crate's documentation, run the following command at the repository's root:
```bash
cargo doc --open --package $CRATE
```

1338
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,8 @@
[workspace]
resolver = "2"
members = [
# Binaries
"binaries/cuprated",
# Benchmarks
"benches/harness",
"benches/harness/lib",
@ -23,13 +25,15 @@ members = [
"p2p/address-book",
# Storage
"storage/blockchain",
"storage/service",
"storage/txpool",
"storage/database",
# RPC
"rpc/json-rpc",
"rpc/rpc-types",
"rpc/rpc-interface",
"rpc/types",
"rpc/interface",
# Misc
"constants",
"cryptonight",
"helper",
"pruning",
@ -56,52 +60,54 @@ opt-level = 1
opt-level = 3
[workspace.dependencies]
async-trait = { version = "0.1.74", default-features = false }
bitflags = { version = "2.4.2", default-features = false }
borsh = { version = "1.2.1", default-features = false }
bytemuck = { version = "1.14.3", default-features = false }
bytes = { version = "1.5.0", default-features = false }
anyhow = { version = "1.0.89", default-features = false }
async-trait = { version = "0.1.82", default-features = false }
bitflags = { version = "2.6.0", default-features = false }
borsh = { version = "1.5.1", default-features = false }
bytemuck = { version = "1.18.0", default-features = false }
bytes = { version = "1.7.2", default-features = false }
cfg-if = { version = "1.0.0", default-features = false }
clap = { version = "4.4.7", default-features = false }
chrono = { version = "0.4.31", default-features = false }
clap = { version = "4.5.17", default-features = false }
chrono = { version = "0.4.38", default-features = false }
crypto-bigint = { version = "0.5.5", default-features = false }
crossbeam = { version = "0.8.4", default-features = false }
curve25519-dalek = { version = "4.1.1", default-features = false }
dalek-ff-group = { git = "https://github.com/Cuprate/serai.git", rev = "d27d934", default-features = false }
const_format = { version = "0.2.33", default-features = false }
curve25519-dalek = { version = "4.1.3", default-features = false }
dashmap = { version = "5.5.3", default-features = false }
dirs = { version = "5.0.1", default-features = false }
futures = { version = "0.3.29", default-features = false }
futures = { version = "0.3.30", default-features = false }
hex = { version = "0.4.3", default-features = false }
hex-literal = { version = "0.4", default-features = false }
indexmap = { version = "2.2.5", default-features = false }
monero-serai = { git = "https://github.com/Cuprate/serai.git", rev = "d27d934", default-features = false }
multiexp = { git = "https://github.com/Cuprate/serai.git", rev = "d27d934", default-features = false }
paste = { version = "1.0.14", default-features = false }
pin-project = { version = "1.1.3", default-features = false }
indexmap = { version = "2.5.0", 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 }
pin-project = { version = "1.1.5", 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_distr = { version = "0.4.3", default-features = false }
rayon = { version = "1.9.0", default-features = false }
serde_bytes = { version = "0.11.12", default-features = false }
serde_json = { version = "1.0.108", default-features = false }
serde = { version = "1.0.190", default-features = false }
thiserror = { version = "1.0.50", default-features = false }
thread_local = { version = "1.1.7", default-features = false }
tokio-util = { version = "0.7.10", default-features = false }
tokio-stream = { version = "0.1.14", default-features = false }
tokio = { version = "1.33.0", default-features = false }
tower = { version = "0.4.13", default-features = false }
tracing-subscriber = { version = "0.3.17", default-features = false }
rayon = { version = "1.10.0", default-features = false }
serde_bytes = { version = "0.11.15", default-features = false }
serde_json = { version = "1.0.128", default-features = false }
serde = { version = "1.0.210", default-features = false }
thiserror = { version = "1.0.63", default-features = false }
thread_local = { version = "1.1.8", default-features = false }
tokio-util = { version = "0.7.12", default-features = false }
tokio-stream = { version = "0.1.16", default-features = false }
tokio = { version = "1.40.0", default-features = false }
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 = { version = "0.1.40", default-features = false }
## workspace.dev-dependencies
criterion = { version = "0.5.1" }
function_name = { version = "0.3.0" }
tempfile = { version = "3" }
pretty_assertions = { version = "1.4.0" }
proptest = { version = "1" }
proptest-derive = { version = "0.4.0" }
tokio-test = { version = "0.4.4" }
criterion = { version = "0.5.1" }
function_name = { version = "0.3.0" }
tempfile = { version = "3.13.0" }
monero-rpc = { git = "https://github.com/Cuprate/serai.git", rev = "d5205ce" }
monero-simple-request-rpc = { git = "https://github.com/Cuprate/serai.git", rev = "d5205ce" }
pretty_assertions = { version = "1.4.1" }
proptest = { version = "1" }
proptest-derive = { version = "0.4.0" }
tokio-test = { version = "0.4.4" }
## TODO:
## Potential dependencies.
@ -111,4 +117,221 @@ tokio-test = { version = "0.4.4" }
# once_cell = { version = "1.18.0" } # Lazy/one-time initialization | https://github.com/matklad/once_cell
# open = { version = "5.0.0" } # Open PATH/URL, probably for binaries | https://github.com/byron/open-rs
# regex = { version = "1.10.2" } # Regular expressions | https://github.com/rust-lang/regex
# ryu = { version = "1.0.15" } # Fast float to string formatting | https://github.com/dtolnay/ryu
# ryu = { version = "1.0.15" } # Fast float to string formatting | https://github.com/dtolnay/ryu
# Lints: cold, warm, hot: <https://github.com/Cuprate/cuprate/issues/131>
[workspace.lints.clippy]
# Cold
borrow_as_ptr = "deny"
case_sensitive_file_extension_comparisons = "deny"
cast_lossless = "deny"
cast_ptr_alignment = "deny"
checked_conversions = "deny"
cloned_instead_of_copied = "deny"
const_is_empty = "deny"
doc_lazy_continuation = "deny"
doc_link_with_quotes = "deny"
duplicated_attributes = "deny"
empty_enum = "deny"
enum_glob_use = "deny"
expl_impl_clone_on_copy = "deny"
explicit_into_iter_loop = "deny"
filter_map_next = "deny"
flat_map_option = "deny"
from_iter_instead_of_collect = "deny"
if_not_else = "deny"
ignored_unit_patterns = "deny"
inconsistent_struct_constructor = "deny"
index_refutable_slice = "deny"
inefficient_to_string = "deny"
invalid_upcast_comparisons = "deny"
iter_filter_is_ok = "deny"
iter_filter_is_some = "deny"
implicit_clone = "deny"
legacy_numeric_constants = "deny"
manual_c_str_literals = "deny"
manual_pattern_char_comparison = "deny"
manual_instant_elapsed = "deny"
manual_inspect = "deny"
manual_is_variant_and = "deny"
manual_let_else = "deny"
manual_ok_or = "deny"
manual_string_new = "deny"
manual_unwrap_or_default = "deny"
map_unwrap_or = "deny"
match_bool = "deny"
match_same_arms = "deny"
match_wildcard_for_single_variants = "deny"
mismatching_type_param_order = "deny"
missing_transmute_annotations = "deny"
mut_mut = "deny"
needless_bitwise_bool = "deny"
needless_character_iteration = "deny"
needless_continue = "deny"
needless_for_each = "deny"
needless_maybe_sized = "deny"
needless_raw_string_hashes = "deny"
no_effect_underscore_binding = "deny"
no_mangle_with_rust_abi = "deny"
option_as_ref_cloned = "deny"
option_option = "deny"
ptr_as_ptr = "deny"
ptr_cast_constness = "deny"
pub_underscore_fields = "deny"
redundant_closure_for_method_calls = "deny"
ref_as_ptr = "deny"
ref_option_ref = "deny"
same_functions_in_if_condition = "deny"
semicolon_if_nothing_returned = "deny"
trivially_copy_pass_by_ref = "deny"
uninlined_format_args = "deny"
unnecessary_join = "deny"
unnested_or_patterns = "deny"
unused_async = "deny"
unused_self = "deny"
used_underscore_binding = "deny"
zero_sized_map_values = "deny"
as_ptr_cast_mut = "deny"
clear_with_drain = "deny"
collection_is_never_read = "deny"
debug_assert_with_mut_call = "deny"
derive_partial_eq_without_eq = "deny"
empty_line_after_doc_comments = "deny"
empty_line_after_outer_attr = "deny"
equatable_if_let = "deny"
iter_on_empty_collections = "deny"
iter_on_single_items = "deny"
iter_with_drain = "deny"
needless_collect = "deny"
needless_pass_by_ref_mut = "deny"
negative_feature_names = "deny"
non_send_fields_in_send_ty = "deny"
nonstandard_macro_braces = "deny"
path_buf_push_overwrite = "deny"
read_zero_byte_vec = "deny"
redundant_clone = "deny"
redundant_feature_names = "deny"
trailing_empty_array = "deny"
trait_duplication_in_bounds = "deny"
type_repetition_in_bounds = "deny"
uninhabited_references = "deny"
unnecessary_struct_initialization = "deny"
unused_peekable = "deny"
unused_rounding = "deny"
use_self = "deny"
useless_let_if_seq = "deny"
wildcard_dependencies = "deny"
unseparated_literal_suffix = "deny"
unnecessary_safety_doc = "deny"
unnecessary_safety_comment = "deny"
unnecessary_self_imports = "deny"
string_to_string = "deny"
rest_pat_in_fully_bound_structs = "deny"
redundant_type_annotations = "deny"
infinite_loop = "deny"
zero_repeat_side_effects = "deny"
# Warm
cast_possible_truncation = "deny"
cast_possible_wrap = "deny"
cast_precision_loss = "deny"
cast_sign_loss = "deny"
copy_iterator = "deny"
doc_markdown = "deny"
explicit_deref_methods = "deny"
explicit_iter_loop = "deny"
float_cmp = "deny"
fn_params_excessive_bools = "deny"
into_iter_without_iter = "deny"
iter_without_into_iter = "deny"
iter_not_returning_iterator = "deny"
large_digit_groups = "deny"
large_types_passed_by_value = "deny"
manual_assert = "deny"
maybe_infinite_iter = "deny"
missing_fields_in_debug = "deny"
needless_pass_by_value = "deny"
range_minus_one = "deny"
range_plus_one = "deny"
redundant_else = "deny"
ref_binding_to_reference = "deny"
return_self_not_must_use = "deny"
single_match_else = "deny"
string_add_assign = "deny"
transmute_ptr_to_ptr = "deny"
unchecked_duration_subtraction = "deny"
unnecessary_box_returns = "deny"
unnecessary_wraps = "deny"
branches_sharing_code = "deny"
fallible_impl_from = "deny"
missing_const_for_fn = "deny"
significant_drop_in_scrutinee = "deny"
significant_drop_tightening = "deny"
try_err = "deny"
lossy_float_literal = "deny"
let_underscore_must_use = "deny"
iter_over_hash_type = "deny"
get_unwrap = "deny"
error_impl_error = "deny"
empty_structs_with_brackets = "deny"
empty_enum_variants_with_brackets = "deny"
empty_drop = "deny"
clone_on_ref_ptr = "deny"
upper_case_acronyms = "deny"
allow_attributes = "deny"
# Hot
# inline_always = "deny"
# large_futures = "deny"
# large_stack_arrays = "deny"
# linkedlist = "deny"
# missing_errors_doc = "deny"
# missing_panics_doc = "deny"
# should_panic_without_expect = "deny"
# similar_names = "deny"
# too_many_lines = "deny"
# unreadable_literal = "deny"
# wildcard_imports = "deny"
# allow_attributes_without_reason = "deny"
# missing_assert_message = "deny"
# missing_docs_in_private_items = "deny"
undocumented_unsafe_blocks = "deny"
# multiple_unsafe_ops_per_block = "deny"
# single_char_lifetime_names = "deny"
# wildcard_enum_match_arm = "deny"
[workspace.lints.rust]
# Cold
future_incompatible = { level = "deny", priority = -1 }
nonstandard_style = { level = "deny", priority = -1 }
absolute_paths_not_starting_with_crate = "deny"
explicit_outlives_requirements = "deny"
keyword_idents_2018 = "deny"
keyword_idents_2024 = "deny"
missing_abi = "deny"
non_ascii_idents = "deny"
non_local_definitions = "deny"
redundant_lifetimes = "deny"
single_use_lifetimes = "deny"
trivial_casts = "deny"
trivial_numeric_casts = "deny"
unsafe_op_in_unsafe_fn = "deny"
unused_crate_dependencies = "deny"
unused_import_braces = "deny"
unused_lifetimes = "deny"
unused_macro_rules = "deny"
ambiguous_glob_imports = "deny"
unused_unsafe = "deny"
# Warm
let_underscore = { level = "deny", priority = -1 }
unreachable_pub = "deny"
unused_qualifications = "deny"
variant_size_differences = "deny"
non_camel_case_types = "deny"
# Hot
# unused_results = "deny"
# non_exhaustive_omitted_patterns = "deny"
# missing_docs = "deny"
# missing_copy_implementations = "deny"

View file

@ -49,7 +49,7 @@ Cuprate maintains various documentation books:
| [Monero's protocol book](https://monero-book.cuprate.org) | Documents the Monero protocol |
| [Cuprate's user book](https://user.cuprate.org) | Practical user-guide for using `cuprated` |
For crate (library) documentation, see the `Documentation` section in [`CONTRIBUTING.md`](CONTRIBUTING.md).
For crate (library) documentation, see: https://doc.cuprate.org. This site holds documentation for Cuprate's crates and all dependencies. All Cuprate crates start with `cuprate_`, for example: [`cuprate_database`](https://doc.cuprate.org/cuprate_database).
## Contributing

View file

@ -0,0 +1,77 @@
[package]
name = "cuprated"
version = "0.0.1"
edition = "2021"
description = "The Cuprate Monero Rust node."
license = "AGPL-3.0-only"
authors = ["Boog900", "hinto-janai", "SyntheticBird45"]
repository = "https://github.com/Cuprate/cuprate/tree/main/binaries/cuprated"
[dependencies]
# TODO: after v1.0.0, remove unneeded dependencies.
cuprate-consensus = { path = "../../consensus" }
cuprate-fast-sync = { path = "../../consensus/fast-sync" }
cuprate-consensus-rules = { path = "../../consensus/rules" }
cuprate-cryptonight = { path = "../../cryptonight" }
cuprate-helper = { path = "../../helper" }
cuprate-epee-encoding = { path = "../../net/epee-encoding" }
cuprate-fixed-bytes = { path = "../../net/fixed-bytes" }
cuprate-levin = { path = "../../net/levin" }
cuprate-wire = { path = "../../net/wire" }
cuprate-p2p = { path = "../../p2p/p2p" }
cuprate-p2p-core = { path = "../../p2p/p2p-core" }
cuprate-dandelion-tower = { path = "../../p2p/dandelion-tower" }
cuprate-async-buffer = { path = "../../p2p/async-buffer" }
cuprate-address-book = { path = "../../p2p/address-book" }
cuprate-blockchain = { path = "../../storage/blockchain" }
cuprate-database-service = { path = "../../storage/service" }
cuprate-txpool = { path = "../../storage/txpool" }
cuprate-database = { path = "../../storage/database" }
cuprate-pruning = { path = "../../pruning" }
cuprate-test-utils = { path = "../../test-utils" }
cuprate-types = { path = "../../types" }
cuprate-json-rpc = { path = "../../rpc/json-rpc" }
cuprate-rpc-interface = { path = "../../rpc/interface" }
cuprate-rpc-types = { path = "../../rpc/types" }
# TODO: after v1.0.0, remove unneeded dependencies.
anyhow = { workspace = true }
async-trait = { workspace = true }
bitflags = { workspace = true }
borsh = { workspace = true }
bytemuck = { workspace = true }
bytes = { workspace = true }
cfg-if = { workspace = true }
clap = { workspace = true, features = ["cargo"] }
chrono = { workspace = true }
crypto-bigint = { workspace = true }
crossbeam = { workspace = true }
curve25519-dalek = { workspace = true }
const_format = { workspace = true }
dashmap = { workspace = true }
dirs = { workspace = true }
futures = { workspace = true }
hex = { workspace = true }
hex-literal = { workspace = true }
indexmap = { workspace = true }
monero-serai = { workspace = true }
paste = { workspace = true }
pin-project = { workspace = true }
randomx-rs = { workspace = true }
rand = { workspace = true }
rand_distr = { workspace = true }
rayon = { workspace = true }
serde_bytes = { workspace = true }
serde_json = { workspace = true }
serde = { workspace = true }
thiserror = { workspace = true }
thread_local = { workspace = true }
tokio-util = { workspace = true }
tokio-stream = { workspace = true }
tokio = { workspace = true }
tower = { workspace = true }
tracing-subscriber = { workspace = true }
tracing = { workspace = true }
[lints]
workspace = true

View file

@ -0,0 +1,2 @@
# `cuprated`
TODO

View file

@ -0,0 +1,6 @@
//! Blockchain
//!
//! Will contain the chain manager and syncer.
mod manager;
mod syncer;

View file

@ -0,0 +1 @@
//! cuprated config

View file

@ -0,0 +1,34 @@
//! General constants used throughout `cuprated`.
use const_format::formatcp;
/// `cuprated`'s semantic version (`MAJOR.MINOR.PATCH`) as string.
pub const VERSION: &str = clap::crate_version!();
/// [`VERSION`] + the build type.
///
/// If a debug build, the suffix is `-debug`, else it is `-release`.
pub const VERSION_BUILD: &str = if cfg!(debug_assertions) {
formatcp!("{VERSION}-debug")
} else {
formatcp!("{VERSION}-release")
};
#[cfg(test)]
mod test {
use super::*;
#[test]
fn version() {
assert_eq!(VERSION, "0.0.1");
}
#[test]
fn version_build() {
if cfg!(debug_assertions) {
assert_eq!(VERSION_BUILD, "0.0.1-debug");
} else {
assert_eq!(VERSION_BUILD, "0.0.1-release");
}
}
}

View file

@ -0,0 +1,28 @@
#![doc = include_str!("../README.md")]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![allow(
unused_imports,
unreachable_pub,
unused_crate_dependencies,
dead_code,
unused_variables,
clippy::needless_pass_by_value,
clippy::unused_async,
reason = "TODO: remove after v1.0.0"
)]
mod blockchain;
mod config;
mod constants;
mod p2p;
mod rpc;
mod statics;
mod txpool;
fn main() {
// Initialize global static `LazyLock` data.
statics::init_lazylock_statics();
// TODO: everything else.
todo!()
}

View file

@ -0,0 +1,5 @@
//! P2P
//!
//! Will handle initiating the P2P and contains a protocol request handler.
mod request_handler;

View file

@ -0,0 +1 @@

View file

@ -0,0 +1,10 @@
//! RPC
//!
//! Will contain the code to initiate the RPC and a request handler.
mod bin;
mod handler;
mod json;
mod other;
pub use handler::{CupratedRpcHandler, CupratedRpcHandlerState};

View file

@ -0,0 +1,85 @@
use anyhow::Error;
use cuprate_rpc_types::{
bin::{
BinRequest, BinResponse, GetBlocksByHeightRequest, GetBlocksByHeightResponse,
GetBlocksRequest, GetBlocksResponse, GetHashesRequest, GetHashesResponse,
GetOutputIndexesRequest, GetOutputIndexesResponse, GetOutsRequest, GetOutsResponse,
GetTransactionPoolHashesRequest, GetTransactionPoolHashesResponse,
},
json::{GetOutputDistributionRequest, GetOutputDistributionResponse},
};
use crate::rpc::CupratedRpcHandlerState;
/// Map a [`BinRequest`] to the function that will lead to a [`BinResponse`].
pub(super) async fn map_request(
state: CupratedRpcHandlerState,
request: BinRequest,
) -> Result<BinResponse, Error> {
use BinRequest as Req;
use BinResponse as Resp;
Ok(match request {
Req::GetBlocks(r) => Resp::GetBlocks(get_blocks(state, r).await?),
Req::GetBlocksByHeight(r) => Resp::GetBlocksByHeight(get_blocks_by_height(state, r).await?),
Req::GetHashes(r) => Resp::GetHashes(get_hashes(state, r).await?),
Req::GetOutputIndexes(r) => Resp::GetOutputIndexes(get_output_indexes(state, r).await?),
Req::GetOuts(r) => Resp::GetOuts(get_outs(state, r).await?),
Req::GetTransactionPoolHashes(r) => {
Resp::GetTransactionPoolHashes(get_transaction_pool_hashes(state, r).await?)
}
Req::GetOutputDistribution(r) => {
Resp::GetOutputDistribution(get_output_distribution(state, r).await?)
}
})
}
async fn get_blocks(
state: CupratedRpcHandlerState,
request: GetBlocksRequest,
) -> Result<GetBlocksResponse, Error> {
todo!()
}
async fn get_blocks_by_height(
state: CupratedRpcHandlerState,
request: GetBlocksByHeightRequest,
) -> Result<GetBlocksByHeightResponse, Error> {
todo!()
}
async fn get_hashes(
state: CupratedRpcHandlerState,
request: GetHashesRequest,
) -> Result<GetHashesResponse, Error> {
todo!()
}
async fn get_output_indexes(
state: CupratedRpcHandlerState,
request: GetOutputIndexesRequest,
) -> Result<GetOutputIndexesResponse, Error> {
todo!()
}
async fn get_outs(
state: CupratedRpcHandlerState,
request: GetOutsRequest,
) -> Result<GetOutsResponse, Error> {
todo!()
}
async fn get_transaction_pool_hashes(
state: CupratedRpcHandlerState,
request: GetTransactionPoolHashesRequest,
) -> Result<GetTransactionPoolHashesResponse, Error> {
todo!()
}
async fn get_output_distribution(
state: CupratedRpcHandlerState,
request: GetOutputDistributionRequest,
) -> Result<GetOutputDistributionResponse, Error> {
todo!()
}

View file

@ -0,0 +1,103 @@
//! Dummy implementation of [`RpcHandler`].
use std::task::{Context, Poll};
use anyhow::Error;
use futures::{channel::oneshot::channel, future::BoxFuture};
use serde::{Deserialize, Serialize};
use tower::Service;
use cuprate_blockchain::service::BlockchainReadHandle;
use cuprate_helper::asynch::InfallibleOneshotReceiver;
use cuprate_json_rpc::Id;
use cuprate_rpc_interface::RpcHandler;
use cuprate_rpc_types::{
bin::{BinRequest, BinResponse},
json::{JsonRpcRequest, JsonRpcResponse},
other::{OtherRequest, OtherResponse},
};
use cuprate_txpool::service::TxpoolReadHandle;
use crate::rpc::{bin, json, other};
/// TODO
#[derive(Clone)]
pub struct CupratedRpcHandler {
/// Should this RPC server be [restricted](RpcHandler::restricted)?
//
// INVARIANT:
// We don't need to include this in `state` and check for
// `self.is_restricted()` because `cuprate-rpc-interface` handles that.
pub restricted: bool,
/// State needed for request -> response mapping.
pub state: CupratedRpcHandlerState,
}
/// TODO
#[derive(Clone)]
pub struct CupratedRpcHandlerState {
/// Read handle to the blockchain database.
pub blockchain: BlockchainReadHandle,
/// Read handle to the transaction pool database.
pub txpool: TxpoolReadHandle,
}
impl CupratedRpcHandler {
/// TODO
pub fn init() {
todo!()
}
}
impl RpcHandler for CupratedRpcHandler {
fn restricted(&self) -> bool {
self.restricted
}
}
impl Service<JsonRpcRequest> for CupratedRpcHandler {
type Response = JsonRpcResponse;
type Error = Error;
type Future = BoxFuture<'static, Result<JsonRpcResponse, Error>>;
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, request: JsonRpcRequest) -> Self::Future {
let state = CupratedRpcHandlerState::clone(&self.state);
Box::pin(json::map_request(state, request))
}
}
impl Service<BinRequest> for CupratedRpcHandler {
type Response = BinResponse;
type Error = Error;
type Future = BoxFuture<'static, Result<BinResponse, Error>>;
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, request: BinRequest) -> Self::Future {
let state = CupratedRpcHandlerState::clone(&self.state);
Box::pin(bin::map_request(state, request))
}
}
impl Service<OtherRequest> for CupratedRpcHandler {
type Response = OtherResponse;
type Error = Error;
type Future = BoxFuture<'static, Result<OtherResponse, Error>>;
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, request: OtherRequest) -> Self::Future {
let state = CupratedRpcHandlerState::clone(&self.state);
Box::pin(other::map_request(state, request))
}
}

View file

@ -0,0 +1,294 @@
use std::sync::Arc;
use anyhow::Error;
use tower::ServiceExt;
use cuprate_rpc_types::json::{
AddAuxPowRequest, AddAuxPowResponse, BannedRequest, BannedResponse, CalcPowRequest,
CalcPowResponse, FlushCacheRequest, FlushCacheResponse, FlushTransactionPoolRequest,
FlushTransactionPoolResponse, GenerateBlocksRequest, GenerateBlocksResponse,
GetAlternateChainsRequest, GetAlternateChainsResponse, GetBansRequest, GetBansResponse,
GetBlockCountRequest, GetBlockCountResponse, GetBlockHeaderByHashRequest,
GetBlockHeaderByHashResponse, GetBlockHeaderByHeightRequest, GetBlockHeaderByHeightResponse,
GetBlockHeadersRangeRequest, GetBlockHeadersRangeResponse, GetBlockRequest, GetBlockResponse,
GetCoinbaseTxSumRequest, GetCoinbaseTxSumResponse, GetConnectionsRequest,
GetConnectionsResponse, GetFeeEstimateRequest, GetFeeEstimateResponse, GetInfoRequest,
GetInfoResponse, GetLastBlockHeaderRequest, GetLastBlockHeaderResponse, GetMinerDataRequest,
GetMinerDataResponse, GetOutputHistogramRequest, GetOutputHistogramResponse,
GetTransactionPoolBacklogRequest, GetTransactionPoolBacklogResponse, GetTxIdsLooseRequest,
GetTxIdsLooseResponse, GetVersionRequest, GetVersionResponse, HardForkInfoRequest,
HardForkInfoResponse, JsonRpcRequest, JsonRpcResponse, OnGetBlockHashRequest,
OnGetBlockHashResponse, PruneBlockchainRequest, PruneBlockchainResponse, RelayTxRequest,
RelayTxResponse, SetBansRequest, SetBansResponse, SubmitBlockRequest, SubmitBlockResponse,
SyncInfoRequest, SyncInfoResponse,
};
use crate::rpc::CupratedRpcHandlerState;
/// Map a [`JsonRpcRequest`] to the function that will lead to a [`JsonRpcResponse`].
pub(super) async fn map_request(
state: CupratedRpcHandlerState,
request: JsonRpcRequest,
) -> Result<JsonRpcResponse, Error> {
use JsonRpcRequest as Req;
use JsonRpcResponse as Resp;
Ok(match request {
Req::GetBlockCount(r) => Resp::GetBlockCount(get_block_count(state, r).await?),
Req::OnGetBlockHash(r) => Resp::OnGetBlockHash(on_get_block_hash(state, r).await?),
Req::SubmitBlock(r) => Resp::SubmitBlock(submit_block(state, r).await?),
Req::GenerateBlocks(r) => Resp::GenerateBlocks(generate_blocks(state, r).await?),
Req::GetLastBlockHeader(r) => {
Resp::GetLastBlockHeader(get_last_block_header(state, r).await?)
}
Req::GetBlockHeaderByHash(r) => {
Resp::GetBlockHeaderByHash(get_block_header_by_hash(state, r).await?)
}
Req::GetBlockHeaderByHeight(r) => {
Resp::GetBlockHeaderByHeight(get_block_header_by_height(state, r).await?)
}
Req::GetBlockHeadersRange(r) => {
Resp::GetBlockHeadersRange(get_block_headers_range(state, r).await?)
}
Req::GetBlock(r) => Resp::GetBlock(get_block(state, r).await?),
Req::GetConnections(r) => Resp::GetConnections(get_connections(state, r).await?),
Req::GetInfo(r) => Resp::GetInfo(get_info(state, r).await?),
Req::HardForkInfo(r) => Resp::HardForkInfo(hard_fork_info(state, r).await?),
Req::SetBans(r) => Resp::SetBans(set_bans(state, r).await?),
Req::GetBans(r) => Resp::GetBans(get_bans(state, r).await?),
Req::Banned(r) => Resp::Banned(banned(state, r).await?),
Req::FlushTransactionPool(r) => {
Resp::FlushTransactionPool(flush_transaction_pool(state, r).await?)
}
Req::GetOutputHistogram(r) => {
Resp::GetOutputHistogram(get_output_histogram(state, r).await?)
}
Req::GetCoinbaseTxSum(r) => Resp::GetCoinbaseTxSum(get_coinbase_tx_sum(state, r).await?),
Req::GetVersion(r) => Resp::GetVersion(get_version(state, r).await?),
Req::GetFeeEstimate(r) => Resp::GetFeeEstimate(get_fee_estimate(state, r).await?),
Req::GetAlternateChains(r) => {
Resp::GetAlternateChains(get_alternate_chains(state, r).await?)
}
Req::RelayTx(r) => Resp::RelayTx(relay_tx(state, r).await?),
Req::SyncInfo(r) => Resp::SyncInfo(sync_info(state, r).await?),
Req::GetTransactionPoolBacklog(r) => {
Resp::GetTransactionPoolBacklog(get_transaction_pool_backlog(state, r).await?)
}
Req::GetMinerData(r) => Resp::GetMinerData(get_miner_data(state, r).await?),
Req::PruneBlockchain(r) => Resp::PruneBlockchain(prune_blockchain(state, r).await?),
Req::CalcPow(r) => Resp::CalcPow(calc_pow(state, r).await?),
Req::FlushCache(r) => Resp::FlushCache(flush_cache(state, r).await?),
Req::AddAuxPow(r) => Resp::AddAuxPow(add_aux_pow(state, r).await?),
Req::GetTxIdsLoose(r) => Resp::GetTxIdsLoose(get_tx_ids_loose(state, r).await?),
})
}
async fn get_block_count(
state: CupratedRpcHandlerState,
request: GetBlockCountRequest,
) -> Result<GetBlockCountResponse, Error> {
todo!()
}
async fn on_get_block_hash(
state: CupratedRpcHandlerState,
request: OnGetBlockHashRequest,
) -> Result<OnGetBlockHashResponse, Error> {
todo!()
}
async fn submit_block(
state: CupratedRpcHandlerState,
request: SubmitBlockRequest,
) -> Result<SubmitBlockResponse, Error> {
todo!()
}
async fn generate_blocks(
state: CupratedRpcHandlerState,
request: GenerateBlocksRequest,
) -> Result<GenerateBlocksResponse, Error> {
todo!()
}
async fn get_last_block_header(
state: CupratedRpcHandlerState,
request: GetLastBlockHeaderRequest,
) -> Result<GetLastBlockHeaderResponse, Error> {
todo!()
}
async fn get_block_header_by_hash(
state: CupratedRpcHandlerState,
request: GetBlockHeaderByHashRequest,
) -> Result<GetBlockHeaderByHashResponse, Error> {
todo!()
}
async fn get_block_header_by_height(
state: CupratedRpcHandlerState,
request: GetBlockHeaderByHeightRequest,
) -> Result<GetBlockHeaderByHeightResponse, Error> {
todo!()
}
async fn get_block_headers_range(
state: CupratedRpcHandlerState,
request: GetBlockHeadersRangeRequest,
) -> Result<GetBlockHeadersRangeResponse, Error> {
todo!()
}
async fn get_block(
state: CupratedRpcHandlerState,
request: GetBlockRequest,
) -> Result<GetBlockResponse, Error> {
todo!()
}
async fn get_connections(
state: CupratedRpcHandlerState,
request: GetConnectionsRequest,
) -> Result<GetConnectionsResponse, Error> {
todo!()
}
async fn get_info(
state: CupratedRpcHandlerState,
request: GetInfoRequest,
) -> Result<GetInfoResponse, Error> {
todo!()
}
async fn hard_fork_info(
state: CupratedRpcHandlerState,
request: HardForkInfoRequest,
) -> Result<HardForkInfoResponse, Error> {
todo!()
}
async fn set_bans(
state: CupratedRpcHandlerState,
request: SetBansRequest,
) -> Result<SetBansResponse, Error> {
todo!()
}
async fn get_bans(
state: CupratedRpcHandlerState,
request: GetBansRequest,
) -> Result<GetBansResponse, Error> {
todo!()
}
async fn banned(
state: CupratedRpcHandlerState,
request: BannedRequest,
) -> Result<BannedResponse, Error> {
todo!()
}
async fn flush_transaction_pool(
state: CupratedRpcHandlerState,
request: FlushTransactionPoolRequest,
) -> Result<FlushTransactionPoolResponse, Error> {
todo!()
}
async fn get_output_histogram(
state: CupratedRpcHandlerState,
request: GetOutputHistogramRequest,
) -> Result<GetOutputHistogramResponse, Error> {
todo!()
}
async fn get_coinbase_tx_sum(
state: CupratedRpcHandlerState,
request: GetCoinbaseTxSumRequest,
) -> Result<GetCoinbaseTxSumResponse, Error> {
todo!()
}
async fn get_version(
state: CupratedRpcHandlerState,
request: GetVersionRequest,
) -> Result<GetVersionResponse, Error> {
todo!()
}
async fn get_fee_estimate(
state: CupratedRpcHandlerState,
request: GetFeeEstimateRequest,
) -> Result<GetFeeEstimateResponse, Error> {
todo!()
}
async fn get_alternate_chains(
state: CupratedRpcHandlerState,
request: GetAlternateChainsRequest,
) -> Result<GetAlternateChainsResponse, Error> {
todo!()
}
async fn relay_tx(
state: CupratedRpcHandlerState,
request: RelayTxRequest,
) -> Result<RelayTxResponse, Error> {
todo!()
}
async fn sync_info(
state: CupratedRpcHandlerState,
request: SyncInfoRequest,
) -> Result<SyncInfoResponse, Error> {
todo!()
}
async fn get_transaction_pool_backlog(
state: CupratedRpcHandlerState,
request: GetTransactionPoolBacklogRequest,
) -> Result<GetTransactionPoolBacklogResponse, Error> {
todo!()
}
async fn get_miner_data(
state: CupratedRpcHandlerState,
request: GetMinerDataRequest,
) -> Result<GetMinerDataResponse, Error> {
todo!()
}
async fn prune_blockchain(
state: CupratedRpcHandlerState,
request: PruneBlockchainRequest,
) -> Result<PruneBlockchainResponse, Error> {
todo!()
}
async fn calc_pow(
state: CupratedRpcHandlerState,
request: CalcPowRequest,
) -> Result<CalcPowResponse, Error> {
todo!()
}
async fn flush_cache(
state: CupratedRpcHandlerState,
request: FlushCacheRequest,
) -> Result<FlushCacheResponse, Error> {
todo!()
}
async fn add_aux_pow(
state: CupratedRpcHandlerState,
request: AddAuxPowRequest,
) -> Result<AddAuxPowResponse, Error> {
todo!()
}
async fn get_tx_ids_loose(
state: CupratedRpcHandlerState,
request: GetTxIdsLooseRequest,
) -> Result<GetTxIdsLooseResponse, Error> {
todo!()
}

View file

@ -0,0 +1,260 @@
use anyhow::Error;
use cuprate_rpc_types::other::{
GetAltBlocksHashesRequest, GetAltBlocksHashesResponse, GetHeightRequest, GetHeightResponse,
GetLimitRequest, GetLimitResponse, GetNetStatsRequest, GetNetStatsResponse, GetOutsRequest,
GetOutsResponse, GetPeerListRequest, GetPeerListResponse, GetPublicNodesRequest,
GetPublicNodesResponse, GetTransactionPoolHashesRequest, GetTransactionPoolHashesResponse,
GetTransactionPoolRequest, GetTransactionPoolResponse, GetTransactionPoolStatsRequest,
GetTransactionPoolStatsResponse, GetTransactionsRequest, GetTransactionsResponse,
InPeersRequest, InPeersResponse, IsKeyImageSpentRequest, IsKeyImageSpentResponse,
MiningStatusRequest, MiningStatusResponse, OtherRequest, OtherResponse, OutPeersRequest,
OutPeersResponse, PopBlocksRequest, PopBlocksResponse, SaveBcRequest, SaveBcResponse,
SendRawTransactionRequest, SendRawTransactionResponse, SetBootstrapDaemonRequest,
SetBootstrapDaemonResponse, SetLimitRequest, SetLimitResponse, SetLogCategoriesRequest,
SetLogCategoriesResponse, SetLogHashRateRequest, SetLogHashRateResponse, SetLogLevelRequest,
SetLogLevelResponse, StartMiningRequest, StartMiningResponse, StopDaemonRequest,
StopDaemonResponse, StopMiningRequest, StopMiningResponse, UpdateRequest, UpdateResponse,
};
use crate::rpc::CupratedRpcHandlerState;
/// Map a [`OtherRequest`] to the function that will lead to a [`OtherResponse`].
pub(super) async fn map_request(
state: CupratedRpcHandlerState,
request: OtherRequest,
) -> Result<OtherResponse, Error> {
use OtherRequest as Req;
use OtherResponse as Resp;
Ok(match request {
Req::GetHeight(r) => Resp::GetHeight(get_height(state, r).await?),
Req::GetTransactions(r) => Resp::GetTransactions(get_transactions(state, r).await?),
Req::GetAltBlocksHashes(r) => {
Resp::GetAltBlocksHashes(get_alt_blocks_hashes(state, r).await?)
}
Req::IsKeyImageSpent(r) => Resp::IsKeyImageSpent(is_key_image_spent(state, r).await?),
Req::SendRawTransaction(r) => {
Resp::SendRawTransaction(send_raw_transaction(state, r).await?)
}
Req::StartMining(r) => Resp::StartMining(start_mining(state, r).await?),
Req::StopMining(r) => Resp::StopMining(stop_mining(state, r).await?),
Req::MiningStatus(r) => Resp::MiningStatus(mining_status(state, r).await?),
Req::SaveBc(r) => Resp::SaveBc(save_bc(state, r).await?),
Req::GetPeerList(r) => Resp::GetPeerList(get_peer_list(state, r).await?),
Req::SetLogHashRate(r) => Resp::SetLogHashRate(set_log_hash_rate(state, r).await?),
Req::SetLogLevel(r) => Resp::SetLogLevel(set_log_level(state, r).await?),
Req::SetLogCategories(r) => Resp::SetLogCategories(set_log_categories(state, r).await?),
Req::SetBootstrapDaemon(r) => {
Resp::SetBootstrapDaemon(set_bootstrap_daemon(state, r).await?)
}
Req::GetTransactionPool(r) => {
Resp::GetTransactionPool(get_transaction_pool(state, r).await?)
}
Req::GetTransactionPoolStats(r) => {
Resp::GetTransactionPoolStats(get_transaction_pool_stats(state, r).await?)
}
Req::StopDaemon(r) => Resp::StopDaemon(stop_daemon(state, r).await?),
Req::GetLimit(r) => Resp::GetLimit(get_limit(state, r).await?),
Req::SetLimit(r) => Resp::SetLimit(set_limit(state, r).await?),
Req::OutPeers(r) => Resp::OutPeers(out_peers(state, r).await?),
Req::InPeers(r) => Resp::InPeers(in_peers(state, r).await?),
Req::GetNetStats(r) => Resp::GetNetStats(get_net_stats(state, r).await?),
Req::GetOuts(r) => Resp::GetOuts(get_outs(state, r).await?),
Req::Update(r) => Resp::Update(update(state, r).await?),
Req::PopBlocks(r) => Resp::PopBlocks(pop_blocks(state, r).await?),
Req::GetTransactionPoolHashes(r) => {
Resp::GetTransactionPoolHashes(get_transaction_pool_hashes(state, r).await?)
}
Req::GetPublicNodes(r) => Resp::GetPublicNodes(get_public_nodes(state, r).await?),
})
}
async fn get_height(
state: CupratedRpcHandlerState,
request: GetHeightRequest,
) -> Result<GetHeightResponse, Error> {
todo!()
}
async fn get_transactions(
state: CupratedRpcHandlerState,
request: GetTransactionsRequest,
) -> Result<GetTransactionsResponse, Error> {
todo!()
}
async fn get_alt_blocks_hashes(
state: CupratedRpcHandlerState,
request: GetAltBlocksHashesRequest,
) -> Result<GetAltBlocksHashesResponse, Error> {
todo!()
}
async fn is_key_image_spent(
state: CupratedRpcHandlerState,
request: IsKeyImageSpentRequest,
) -> Result<IsKeyImageSpentResponse, Error> {
todo!()
}
async fn send_raw_transaction(
state: CupratedRpcHandlerState,
request: SendRawTransactionRequest,
) -> Result<SendRawTransactionResponse, Error> {
todo!()
}
async fn start_mining(
state: CupratedRpcHandlerState,
request: StartMiningRequest,
) -> Result<StartMiningResponse, Error> {
todo!()
}
async fn stop_mining(
state: CupratedRpcHandlerState,
request: StopMiningRequest,
) -> Result<StopMiningResponse, Error> {
todo!()
}
async fn mining_status(
state: CupratedRpcHandlerState,
request: MiningStatusRequest,
) -> Result<MiningStatusResponse, Error> {
todo!()
}
async fn save_bc(
state: CupratedRpcHandlerState,
request: SaveBcRequest,
) -> Result<SaveBcResponse, Error> {
todo!()
}
async fn get_peer_list(
state: CupratedRpcHandlerState,
request: GetPeerListRequest,
) -> Result<GetPeerListResponse, Error> {
todo!()
}
async fn set_log_hash_rate(
state: CupratedRpcHandlerState,
request: SetLogHashRateRequest,
) -> Result<SetLogHashRateResponse, Error> {
todo!()
}
async fn set_log_level(
state: CupratedRpcHandlerState,
request: SetLogLevelRequest,
) -> Result<SetLogLevelResponse, Error> {
todo!()
}
async fn set_log_categories(
state: CupratedRpcHandlerState,
request: SetLogCategoriesRequest,
) -> Result<SetLogCategoriesResponse, Error> {
todo!()
}
async fn set_bootstrap_daemon(
state: CupratedRpcHandlerState,
request: SetBootstrapDaemonRequest,
) -> Result<SetBootstrapDaemonResponse, Error> {
todo!()
}
async fn get_transaction_pool(
state: CupratedRpcHandlerState,
request: GetTransactionPoolRequest,
) -> Result<GetTransactionPoolResponse, Error> {
todo!()
}
async fn get_transaction_pool_stats(
state: CupratedRpcHandlerState,
request: GetTransactionPoolStatsRequest,
) -> Result<GetTransactionPoolStatsResponse, Error> {
todo!()
}
async fn stop_daemon(
state: CupratedRpcHandlerState,
request: StopDaemonRequest,
) -> Result<StopDaemonResponse, Error> {
todo!()
}
async fn get_limit(
state: CupratedRpcHandlerState,
request: GetLimitRequest,
) -> Result<GetLimitResponse, Error> {
todo!()
}
async fn set_limit(
state: CupratedRpcHandlerState,
request: SetLimitRequest,
) -> Result<SetLimitResponse, Error> {
todo!()
}
async fn out_peers(
state: CupratedRpcHandlerState,
request: OutPeersRequest,
) -> Result<OutPeersResponse, Error> {
todo!()
}
async fn in_peers(
state: CupratedRpcHandlerState,
request: InPeersRequest,
) -> Result<InPeersResponse, Error> {
todo!()
}
async fn get_net_stats(
state: CupratedRpcHandlerState,
request: GetNetStatsRequest,
) -> Result<GetNetStatsResponse, Error> {
todo!()
}
async fn get_outs(
state: CupratedRpcHandlerState,
request: GetOutsRequest,
) -> Result<GetOutsResponse, Error> {
todo!()
}
async fn update(
state: CupratedRpcHandlerState,
request: UpdateRequest,
) -> Result<UpdateResponse, Error> {
todo!()
}
async fn pop_blocks(
state: CupratedRpcHandlerState,
request: PopBlocksRequest,
) -> Result<PopBlocksResponse, Error> {
todo!()
}
async fn get_transaction_pool_hashes(
state: CupratedRpcHandlerState,
request: GetTransactionPoolHashesRequest,
) -> Result<GetTransactionPoolHashesResponse, Error> {
todo!()
}
async fn get_public_nodes(
state: CupratedRpcHandlerState,
request: GetPublicNodesRequest,
) -> Result<GetPublicNodesResponse, Error> {
todo!()
}

View file

@ -0,0 +1,53 @@
//! Global `static`s used throughout `cuprated`.
use std::{
sync::{atomic::AtomicU64, LazyLock},
time::{SystemTime, UNIX_EPOCH},
};
/// Define all the `static`s that should be always be initialized early on.
///
/// This wraps all `static`s inside a `LazyLock` and generates
/// a [`init_lazylock_statics`] function that must/should be
/// used by `main()` early on.
macro_rules! define_init_lazylock_statics {
($(
$( #[$attr:meta] )*
$name:ident: $t:ty = $init_fn:expr;
)*) => {
/// Initialize global static `LazyLock` data.
pub fn init_lazylock_statics() {
$(
LazyLock::force(&$name);
)*
}
$(
$(#[$attr])*
pub static $name: LazyLock<$t> = LazyLock::new(|| $init_fn);
)*
};
}
define_init_lazylock_statics! {
/// The start time of `cuprated`.
START_INSTANT: SystemTime = SystemTime::now();
/// Start time of `cuprated` as a UNIX timestamp.
START_INSTANT_UNIX: u64 = START_INSTANT
.duration_since(UNIX_EPOCH)
.expect("Failed to set `cuprated` startup time.")
.as_secs();
}
#[cfg(test)]
mod test {
use super::*;
/// Sanity check for startup UNIX time.
#[test]
fn start_instant_unix() {
// Fri Sep 27 01:07:13 AM UTC 2024
assert!(*START_INSTANT_UNIX > 1727399233);
}
}

View file

@ -0,0 +1,3 @@
//! Transaction Pool
//!
//! Will handle initiating the tx-pool, providing the preprocessor required for the dandelion pool.

View file

@ -1,4 +1,4 @@
## Cuprate's architecture (implementation) book
## Cuprate's architecture book
This book documents Cuprate's architecture and implementation.
See:

View file

@ -1,19 +1,17 @@
[book]
authors = ["hinto-janai"]
authors = ["Cuprate Contributors"]
language = "en"
multilingual = false
src = "src"
title = "Cuprate Architecture"
git-repository-url = "https://github.com/Cuprate/architecture-book"
# TODO: fix after importing real files.
#
# [preprocessor.last-changed]
# command = "mdbook-last-changed"
# renderer = ["html"]
#
# [output.html]
# default-theme = "ayu"
# preferred-dark-theme = "ayu"
# git-repository-url = "https://github.com/hinto-janai/cuprate-architecture"
# additional-css = ["last-changed.css"]
[preprocessor.last-changed]
command = "mdbook-last-changed"
renderer = ["html"]
[output.html]
default-theme = "ayu"
preferred-dark-theme = "ayu"
git-repository-url = "https://github.com/Cuprate/architecture-book"
additional-css = ["last-changed.css"]

View file

@ -0,0 +1,7 @@
footer {
font-size: 0.8em;
text-align: center;
border-top: 1px solid;
margin-top: 4%;
padding: 5px 0;
}

View file

@ -1,3 +1,165 @@
# Summary
- [TODO](todo.md)
[Cuprate Architecture](cuprate-architecture.md)
[🟡 Foreword](foreword.md)
---
- [🟠 Intro](intro/intro.md)
- [🟡 Who this book is for](intro/who-this-book-is-for.md)
- [🔴 Required knowledge](intro/required-knowledge.md)
- [🔴 How to use this book](intro/how-to-use-this-book.md)
---
- [⚪️ Bird's eye view](birds-eye-view/intro.md)
- [⚪️ Map](birds-eye-view/map.md)
- [⚪️ Components](birds-eye-view/components.md)
---
- [⚪️ Formats, protocols, types](formats-protocols-types/intro.md)
- [⚪️ monero_serai](formats-protocols-types/monero-serai.md)
- [⚪️ cuprate_types](formats-protocols-types/cuprate-types.md)
- [⚪️ cuprate_helper](formats-protocols-types/cuprate-helper.md)
- [⚪️ Epee](formats-protocols-types/epee.md)
- [⚪️ Levin](formats-protocols-types/levin.md)
---
- [🟢 Storage](storage/intro.md)
- [🟢 Database abstraction](storage/db/intro.md)
- [🟢 Abstraction](storage/db/abstraction/intro.md)
- [🟢 Backend](storage/db/abstraction/backend.md)
- [🟢 ConcreteEnv](storage/db/abstraction/concrete_env.md)
- [🟢 Trait](storage/db/abstraction/trait.md)
- [🟢 Syncing](storage/db/syncing.md)
- [🟢 Resizing](storage/db/resizing.md)
- [🟢 (De)serialization](storage/db/serde.md)
- [🟢 Known issues and tradeoffs](storage/db/issues/intro.md)
- [🟢 Abstracting backends](storage/db/issues/traits.md)
- [🟢 Hot-swap](storage/db/issues/hot-swap.md)
- [🟢 Unaligned bytes](storage/db/issues/unaligned.md)
- [🟢 Endianness](storage/db/issues/endian.md)
- [🟢 Multimap](storage/db/issues/multimap.md)
- [🟢 Common behavior](storage/common/intro.md)
- [🟢 Types](storage/common/types.md)
- [🟢 `ops`](storage/common/ops.md)
- [🟢 `tower::Service`](storage/common/service/intro.md)
- [🟢 Initialization](storage/common/service/initialization.md)
- [🟢 Requests](storage/common/service/requests.md)
- [🟢 Responses](storage/common/service/responses.md)
- [🟢 Resizing](storage/common/service/resizing.md)
- [🟢 Thread model](storage/common/service/thread-model.md)
- [🟢 Shutdown](storage/common/service/shutdown.md)
- [🟢 Blockchain](storage/blockchain/intro.md)
- [🟢 Schema](storage/blockchain/schema/intro.md)
- [🟢 Tables](storage/blockchain/schema/tables.md)
- [🟢 Multimap tables](storage/blockchain/schema/multimap.md)
- [⚪️ Transaction pool](storage/txpool/intro.md)
- [⚪️ Pruning](storage/pruning/intro.md)
---
- [🟢 RPC](rpc/intro.md)
- [🟡 JSON-RPC 2.0](rpc/json-rpc.md)
- [🟢 The types](rpc/types/intro.md)
- [🟢 Misc types](rpc/types/misc-types.md)
- [🟢 Base RPC types](rpc/types/base-types.md)
- [🟢 The type generator macro](rpc/types/macro.md)
- [🟢 Metadata](rpc/types/metadata.md)
- [🟡 (De)serialization](rpc/types/deserialization.md)
- [🟢 The interface](rpc/interface.md)
- [🔴 The handler](rpc/handler/intro.md)
- [🔴 The server](rpc/server/intro.md)
- [🟢 Differences with `monerod`](rpc/differences/intro.md)
- [🟢 JSON field ordering](rpc/differences/json-field-ordering.md)
- [🟢 JSON formatting](rpc/differences/json-formatting.md)
- [🟢 JSON strictness](rpc/differences/json-strictness.md)
- [🟡 JSON-RPC strictness](rpc/differences/json-rpc-strictness.md)
- [🟡 HTTP methods](rpc/differences/http-methods.md)
- [🟡 RPC payment](rpc/differences/rpc-payment.md)
- [🟢 Custom strings](rpc/differences/custom-strings.md)
- [🔴 Unsupported RPC calls](rpc/differences/unsupported-rpc-calls.md)
- [🔴 RPC calls with different behavior](rpc/differences/rpc-calls-with-different-behavior.md)
---
- [⚪️ ZMQ](zmq/intro.md)
- [⚪️ TODO](zmq/todo.md)
---
- [⚪️ Consensus](consensus/intro.md)
- [⚪️ Verifier](consensus/verifier.md)
- [⚪️ TODO](consensus/todo.md)
---
- [⚪️ Networking](networking/intro.md)
- [⚪️ P2P](networking/p2p.md)
- [⚪️ Dandelion++](networking/dandelion.md)
- [⚪️ Proxy](networking/proxy.md)
- [⚪️ Tor](networking/tor.md)
- [⚪️ i2p](networking/i2p.md)
- [⚪️ IPv4/IPv6](networking/ipv4-ipv6.md)
---
- [🔴 Instrumentation](instrumentation/intro.md)
- [⚪️ Logging](instrumentation/logging.md)
- [⚪️ Data collection](instrumentation/data-collection.md)
---
- [⚪️ Binary](binary/intro.md)
- [⚪️ CLI](binary/cli.md)
- [⚪️ Config](binary/config.md)
- [⚪️ Logging](binary/logging.md)
---
- [⚪️ Resources](resources/intro.md)
- [⚪️ File system](resources/fs/intro.md)
- [🟡 Index of PATHs](resources/fs/paths.md)
- [⚪️ Sockets](resources/sockets/index.md)
- [🔴 Index of ports](resources/sockets/ports.md)
- [⚪️ Memory](resources/memory.md)
- [🟡 Concurrency and parallelism](resources/cap/intro.md)
- [⚪️ Map](resources/cap/map.md)
- [⚪️ The RPC server](resources/cap/the-rpc-server.md)
- [⚪️ The database](resources/cap/the-database.md)
- [⚪️ The block downloader](resources/cap/the-block-downloader.md)
- [⚪️ The verifier](resources/cap/the-verifier.md)
- [⚪️ Thread exit](resources/cap/thread-exit.md)
- [🔴 Index of threads](resources/cap/threads.md)
---
- [⚪️ External Monero libraries](external-monero-libraries/intro.md)
- [⚪️ Cryptonight](external-monero-libraries/cryptonight.md)
- [🔴 RandomX](external-monero-libraries/randomx.md)
- [🔴 monero_serai](external-monero-libraries/monero_serai.md)
---
- [⚪️ Benchmarking](benchmarking/intro.md)
- [⚪️ Criterion](benchmarking/criterion.md)
- [⚪️ Harness](benchmarking/harness.md)
- [⚪️ Testing](testing/intro.md)
- [⚪️ Monero data](testing/monero-data.md)
- [⚪️ RPC client](testing/rpc-client.md)
- [⚪️ Spawning `monerod`](testing/spawning-monerod.md)
- [⚪️ Known issues and tradeoffs](known-issues-and-tradeoffs/intro.md)
- [⚪️ Networking](known-issues-and-tradeoffs/networking.md)
- [⚪️ RPC](known-issues-and-tradeoffs/rpc.md)
- [⚪️ Storage](known-issues-and-tradeoffs/storage.md)
---
- [⚪️ Appendix](appendix/intro.md)
- [🟢 Crates](appendix/crates.md)
- [🔴 Contributing](appendix/contributing.md)
- [🔴 Build targets](appendix/build-targets.md)
- [🔴 Protocol book](appendix/protocol-book.md)
- [⚪️ User book](appendix/user-book.md)

View file

@ -0,0 +1,7 @@
# Build targets
- x86
- ARM64
- Windows
- Linux
- macOS
- FreeBSD(?)

View file

@ -0,0 +1,2 @@
# Contributing
<https://github.com/Cuprate/cuprate/blob/main/CONTRIBUTING.md>

View file

@ -0,0 +1,63 @@
# Crates
This is an index of all of Cuprate's in-house crates it uses and maintains.
They are categorized into groups.
Crate documentation for each crate can be found by clicking the crate name or by visiting <https://doc.cuprate.org>. Documentation can also be built manually by running this at the root of the `cuprate` repository:
```bash
cargo doc --package $CRATE
```
For example, this will generate and open `cuprate-blockchain` documentation:
```bash
cargo doc --open --package cuprate-blockchain
```
## Consensus
| Crate | In-tree path | Purpose |
|-------|--------------|---------|
| [`cuprate-consensus`](https://doc.cuprate.org/cuprate_consensus) | [`consensus/`](https://github.com/Cuprate/cuprate/tree/main/consensus) | TODO
| [`cuprate-consensus-rules`](https://doc.cuprate.org/cuprate_consensus_rules) | [`consensus/rules/`](https://github.com/Cuprate/cuprate/tree/main/consensus-rules) | TODO
| [`cuprate-fast-sync`](https://doc.cuprate.org/cuprate_fast_sync) | [`consensus/fast-sync/`](https://github.com/Cuprate/cuprate/tree/main/consensus/fast-sync) | Fast block synchronization
## Networking
| Crate | In-tree path | Purpose |
|-------|--------------|---------|
| [`cuprate-epee-encoding`](https://doc.cuprate.org/cuprate_epee_encoding) | [`net/epee-encoding/`](https://github.com/Cuprate/cuprate/tree/main/net/epee-encoding) | Epee (de)serialization
| [`cuprate-fixed-bytes`](https://doc.cuprate.org/cuprate_fixed_bytes) | [`net/fixed-bytes/`](https://github.com/Cuprate/cuprate/tree/main/net/fixed-bytes) | Fixed byte containers backed by `byte::Byte`
| [`cuprate-levin`](https://doc.cuprate.org/cuprate_levin) | [`net/levin/`](https://github.com/Cuprate/cuprate/tree/main/net/levin) | Levin bucket protocol implementation
| [`cuprate-wire`](https://doc.cuprate.org/cuprate_wire) | [`net/wire/`](https://github.com/Cuprate/cuprate/tree/main/net/wire) | TODO
## P2P
| Crate | In-tree path | Purpose |
|-------|--------------|---------|
| [`cuprate-address-book`](https://doc.cuprate.org/cuprate_address_book) | [`p2p/address-book/`](https://github.com/Cuprate/cuprate/tree/main/p2p/address-book) | TODO
| [`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-p2p`](https://doc.cuprate.org/cuprate_p2p) | [`p2p/p2p/`](https://github.com/Cuprate/cuprate/tree/main/p2p/p2p) | 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
| Crate | In-tree path | Purpose |
|-------|--------------|---------|
| [`cuprate-blockchain`](https://doc.cuprate.org/cuprate_blockchain) | [`storage/blockchain/`](https://github.com/Cuprate/cuprate/tree/main/storage/blockchain) | Blockchain database built on-top of `cuprate-database` & `cuprate-database-service`
| [`cuprate-database`](https://doc.cuprate.org/cuprate_database) | [`storage/database/`](https://github.com/Cuprate/cuprate/tree/main/storage/database) | Pure database abstraction
| [`cuprate-database-service`](https://doc.cuprate.org/cuprate_database_service) | [`storage/database-service/`](https://github.com/Cuprate/cuprate/tree/main/storage/database-service) | `tower::Service` + thread-pool abstraction built on-top of `cuprate-database`
| [`cuprate-txpool`](https://doc.cuprate.org/cuprate_txpool) | [`storage/txpool/`](https://github.com/Cuprate/cuprate/tree/main/storage/txpool) | Transaction pool database built on-top of `cuprate-database` & `cuprate-database-service`
## RPC
| Crate | In-tree path | Purpose |
|-------|--------------|---------|
| [`cuprate-json-rpc`](https://doc.cuprate.org/cuprate_json_rpc) | [`rpc/json-rpc/`](https://github.com/Cuprate/cuprate/tree/main/rpc/json-rpc) | JSON-RPC 2.0 implementation
| [`cuprate-rpc-types`](https://doc.cuprate.org/cuprate_rpc_types) | [`rpc/types/`](https://github.com/Cuprate/cuprate/tree/main/rpc/types) | Monero RPC types and traits
| [`cuprate-rpc-interface`](https://doc.cuprate.org/cuprate_rpc_interface) | [`rpc/interface/`](https://github.com/Cuprate/cuprate/tree/main/rpc/interface) | RPC interface & routing
| [`cuprate-rpc-handler`](https://doc.cuprate.org/cuprate_rpc_handler) | [`rpc/handler/`](https://github.com/Cuprate/cuprate/tree/main/rpc/handler) | RPC inner handlers
## 1-off crates
| Crate | In-tree path | Purpose |
|-------|--------------|---------|
| [`cuprate-constants`](https://doc.cuprate.org/cuprate_constants) | [`constants/`](https://github.com/Cuprate/cuprate/tree/main/constants) | Shared `const/static` data across Cuprate
| [`cuprate-cryptonight`](https://doc.cuprate.org/cuprate_cryptonight) | [`cryptonight/`](https://github.com/Cuprate/cuprate/tree/main/cryptonight) | CryptoNight hash functions
| [`cuprate-pruning`](https://doc.cuprate.org/cuprate_pruning) | [`pruning/`](https://github.com/Cuprate/cuprate/tree/main/pruning) | Monero pruning logic/types
| [`cuprate-helper`](https://doc.cuprate.org/cuprate_helper) | [`helper/`](https://github.com/Cuprate/cuprate/tree/main/helper) | Kitchen-sink helper crate for Cuprate
| [`cuprate-test-utils`](https://doc.cuprate.org/cuprate_test_utils) | [`test-utils/`](https://github.com/Cuprate/cuprate/tree/main/test-utils) | Testing utilities for Cuprate
| [`cuprate-types`](https://doc.cuprate.org/cuprate_types) | [`types/`](https://github.com/Cuprate/cuprate/tree/main/types) | Shared types across Cuprate

View file

@ -0,0 +1 @@
# Appendix

View file

@ -0,0 +1,2 @@
# Protocol book
<https://monero-book.cuprate.org>

View file

@ -0,0 +1 @@
# ⚪️ User book

View file

@ -0,0 +1 @@
# ⚪️ Criterion

View file

@ -0,0 +1 @@
# ⚪️ Harness

View file

@ -0,0 +1 @@
# ⚪️ Benchmarking

View file

@ -0,0 +1 @@
# ⚪️ CLI

View file

@ -0,0 +1 @@
# ⚪️ Config

View file

@ -0,0 +1 @@
# ⚪️ Binary

View file

@ -0,0 +1 @@
# ⚪️ Logging

View file

@ -0,0 +1 @@
# ⚪️ Components

View file

@ -0,0 +1 @@
# ⚪️ Bird's eye view

View file

@ -0,0 +1 @@
# ⚪️ Map

View file

@ -0,0 +1 @@
# ⚪️ Consensus

View file

@ -0,0 +1 @@
# ⚪️ TODO

View file

@ -0,0 +1 @@
# ⚪️ Verifier

View file

@ -0,0 +1,22 @@
# Cuprate Architecture
WIP
[Cuprate](https://github.com/Cuprate/cuprate)'s architecture book.
Sections are notated with colors indicating how complete they are:
| Color | Meaning |
|-------|---------|
| ⚪️ | Empty
| 🔴 | Severely lacking information
| 🟠 | Lacking some information
| 🟡 | Almost ready
| 🟢 | OK
---
Continue to the next chapter by clicking the right `>` button, or by selecting it on the left side.
All chapters are viewable by clicking the top-left `☰` button.
The entire book can searched by clicking the top-left 🔍 button.

View file

@ -0,0 +1 @@
# ⚪️ Cryptonight

View file

@ -0,0 +1 @@
# ⚪️ External Monero libraries

View file

@ -0,0 +1,2 @@
# monero_serai
<https://github.com/serai-dex/serai/tree/develop/coins/monero>

View file

@ -0,0 +1,2 @@
# RandomX
<https://github.com/tari-project/randomx-rs>

View file

@ -0,0 +1,36 @@
# Foreword
Monero[^1] is a large software project, coming in at 329k lines of C++, C, headers, and make files.[^2] It is directly responsible for 2.6 billion dollars worth of value.[^3] It has had over 400 contributors, more if counting unnamed contributions.[^4] It has over 10,000 node operators and a large active userbase.[^5]
The project wasn't always this big, but somewhere in the midst of contributors coming and going, various features being added, bugs being fixed, and celebrated cryptography being implemented - there was an aspect that was lost by the project that it could not easily gain again: **maintainability**.
Within large and complicated software projects, there is an important transfer of knowledge that must occur for long-term survival. Much like an organism that must eventually pass the torch onto the next generation, projects must do the same for future contributors.
However, newcomers often lack experience, past contributors might not be around, and current maintainers may be too busy. For whatever reason, this transfer of knowledge is not always smooth.
There is a solution to this problem: **documentation**.
The activity of writing the what, where, why, and how of the solutions to technical problems can be done in an author's lonesome.
The activity of reading these ideas can be done by future readers at any time without permission.
These readers may be new prospective contributors, it may be the current maintainers, it may be researchers, it may be users of various scale. Whoever it may be, documentation acts as the link between the past and present; a bottle of wisdom thrown into the river of time for future participants to open.
This book is the manifestation of this will, for Cuprate[^6], an alternative Monero node. It documents Cuprate's implementation from head-to-toe such that in the case of a contributor's untimely disappearance, the project can continue.
People come and go, documentation is forever.
— hinto-janai
---
[^1]: [`monero-project/monero`](https://github.com/monero-project/monero)
[^2]: `git ls-files | grep "\.cpp$\|\.h$\|\.c$\|CMake" | xargs cat | wc -l` on [`cc73fe7`](https://github.com/monero-project/monero/tree/cc73fe71162d564ffda8e549b79a350bca53c454)
[^3]: 2024-05-24: $143.55 USD * 18,151,608 XMR = $2,605,663,258
[^4]: `git log --all --pretty="%an" | sort -u | wc -l` on [`cc73fe7`](https://github.com/monero-project/monero/tree/cc73fe71162d564ffda8e549b79a350bca53c454)
[^5]: <https://monero.fail/map>
[^6]: <https://github.com/Cuprate/cuprate>

View file

@ -0,0 +1 @@
# ⚪️ cuprate_helper

View file

@ -0,0 +1 @@
# ⚪️ cuprate_types

View file

@ -0,0 +1 @@
# ⚪️ Epee

View file

@ -0,0 +1 @@
# ⚪️ Formats, protocols, types

View file

@ -0,0 +1 @@
# ⚪️ Levin

View file

@ -0,0 +1 @@
# ⚪️ monero_serai

View file

@ -0,0 +1 @@
# ⚪️ Data collection

View file

@ -0,0 +1,2 @@
# Instrumentation
Cuprate is built with [instrumentation](https://en.wikipedia.org/wiki/Instrumentation) in mind.

View file

@ -0,0 +1 @@
# ⚪️ Logging

View file

@ -0,0 +1,5 @@
# How to use this book
## Maintainers
## Contributors
## Researchers

View file

@ -0,0 +1,15 @@
# Intro
[Cuprate](https://github.com/Cuprate/cuprate) is an alternative [Monero](https://getmonero.org) node implementation.
This book describes Cuprate's architecture, ranging from small things like database pruning to larger meta-components like the networking stack.
A brief overview of some aspects covered within this book:
- Component designs
- Implementation details
- File location and purpose
- Design decisions and tradeoffs
- Things in relation to `monerod`
- Dependency usage
## Source code
The source files for this book can be found on at: <https://github.com/Cuprate/architecture-book>.

View file

@ -0,0 +1,28 @@
# Required knowledge
## General
- Rust
- Monero
- System design
## Components
### Storage
- Embedded databases
- LMDB
- redb
### RPC
- `axum`
- `tower`
- `async`
- JSON-RPC 2.0
- Epee
### Networking
- `tower`
- `tokio`
- `async`
- Levin
### Instrumentation
- `tracing`

View file

@ -0,0 +1,31 @@
# Who this book is for
## Maintainers
As mentioned in [`Foreword`](../foreword.md), the group of people that benefit from this book's value the most by far are the current and future Cuprate maintainers.
Cuprate's system design is documented in this book such that if you were ever to build it again from scratch, you would have an excellent guide on how to do such, and also where improvements could be made.
Practically, what that means for maintainers is that it acts as _the_ reference. During maintenance, it is quite valuable to have a book that contains condensed knowledge on the behavior of components, or how certain code works, or why it was built a certain way.
## Contributors
Contributors also have access to the inner-workings of Cuprate via this book, which helps when making larger contributions.
Design decisions and implementation details notated in this book helps answer questions such as:
- Why is it done this way?
- Why can it _not_ be done this way?
- Were other methods attempted?
Cuprate's testing and benchmarking suites, unknown to new contributors, are also documented within this book.
## Researchers
This book contains the why, where, and how of the _implementation_ of formal research.
Although it is an informal specification, this book still acts as a more accessible overview of Cuprate compared to examining the codebase itself.
## Operators & users
This book is not a practical guide for using Cuprate itself.
For configuration, data collection (also important for researchers), and other practical usage, see [Cuprate's user book](https://user.cuprate.org).
## Observers
Anyone curious enough is free to learn the inner-workings of Cuprate via this book, and maybe even contribute someday.

View file

@ -0,0 +1 @@
# ⚪️ Known issues and tradeoffs

View file

@ -0,0 +1 @@
# ⚪️ Networking

View file

@ -0,0 +1 @@
# ⚪️ RPC

View file

@ -0,0 +1 @@
# ⚪️ Storage

View file

@ -0,0 +1 @@
# ⚪️ Dandelion++

View file

@ -0,0 +1 @@
# ⚪️ i2p

View file

@ -0,0 +1 @@
# ⚪️ Networking

View file

@ -0,0 +1 @@
# ⚪️ IPv4/IPv6

View file

@ -0,0 +1 @@
# ⚪️ P2P

View file

@ -0,0 +1 @@
# ⚪️ Proxy

View file

@ -0,0 +1 @@
# ⚪️ Tor

View file

@ -0,0 +1,32 @@
# Concurrency and parallelism
It is incumbent upon software like Cuprate to take advantage of today's highly parallel hardware as much as practically possible.
With that said, programs must setup guardrails when operating in a concurrent and parallel manner, [for correctness and safety](https://en.wikipedia.org/wiki/Concurrency_(computer_science)).
There are "synchronization primitives" that help with this, common ones being:
- [Locks](https://en.wikipedia.org/wiki/Lock_(computer_science))
- [Channels](https://en.wikipedia.org/wiki/Channel_(programming))
- [Atomics](https://en.wikipedia.org/wiki/Linearizability#Primitive_atomic_instructions)
These tools are relatively easy to use in isolation, but trickier to do so when considering the entire system. It is not uncommon for _the_ bottleneck to be the [poor orchastration](https://en.wikipedia.org/wiki/Starvation_(computer_science)) of these primitives.
## Analogy
A common analogy for a parallel system is an intersection.
Like a parallel computer system, an intersection contains:
1. **Parallelism:** multiple individual units that want to move around (cars, pedestrians, etc)
1. **Synchronization primitives:** traffic lights, car lights, walk signals
In theory, the amount of "work" the units can do is only limited by the speed of the units themselves, but in practice, the slow cascading reaction speeds between all units, the frequent hiccups that can occur, and the synchronization primitives themselves become bottlenecks far before the maximum speed of any unit is reached.
A car that hogs the middle of the intersection on the wrong light is akin to a system thread holding onto a lock longer than it should be - it degrades total system output.
Unlike humans however, computer systems at least have the potential to move at lightning speeds, but only if the above synchronization primitives are used correctly.
## Goal
To aid the long-term maintenance of highly concurrent and parallel code, this section documents:
1. All system threads spawned and maintained
1. All major sections where synchronization primitives are used
1. The asynchronous behavior of some components
and how these compose together efficiently in Cuprate.

View file

@ -0,0 +1 @@
# ⚪️ Map

View file

@ -0,0 +1 @@
# ⚪️ The block downloader

View file

@ -0,0 +1 @@
# ⚪️ The database

View file

@ -0,0 +1 @@
# ⚪️ The RPC server

View file

@ -0,0 +1 @@
# ⚪️ The verifier

View file

@ -0,0 +1 @@
# ⚪️ Thread exit

View file

@ -0,0 +1,2 @@
# Index of threads
This is an index of all of the system threads Cuprate actively uses.

View file

@ -0,0 +1 @@
# ⚪️ File system

View file

@ -0,0 +1,87 @@
# Index of PATHs
This is an index of all of the filesystem PATHs Cuprate actively uses.
The [`cuprate_helper::fs`](https://doc.cuprate.org/cuprate_helper/fs/index.html)
module defines the general locations used throughout Cuprate.
[`dirs`](https://docs.rs/dirs) is used internally, which follows
the PATH standards/conventions on each OS Cuprate supports, i.e.:
- the [XDG base directory](https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html) and the [XDG user directory](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/) specifications on Linux
- the [Known Folder](https://msdn.microsoft.com/en-us/library/windows/desktop/bb776911(v=vs.85).aspx) system on Windows
- the [Standard Directories](https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html#//apple_ref/doc/uid/TP40010672-CH2-SW6) on macOS
## Cache
Cuprate's cache directory.
| OS | PATH |
|---------|-----------------------------------------|
| Windows | `C:\Users\Alice\AppData\Local\Cuprate\` |
| macOS | `/Users/Alice/Library/Caches/Cuprate/` |
| Linux | `/home/alice/.cache/cuprate/` |
## Config
Cuprate's config directory.
| OS | PATH |
|---------|-----------------------------------------------------|
| Windows | `C:\Users\Alice\AppData\Roaming\Cuprate\` |
| macOS | `/Users/Alice/Library/Application Support/Cuprate/` |
| Linux | `/home/alice/.config/cuprate/` |
## Data
Cuprate's data directory.
| OS | PATH |
|---------|-----------------------------------------------------|
| Windows | `C:\Users\Alice\AppData\Roaming\Cuprate\` |
| macOS | `/Users/Alice/Library/Application Support/Cuprate/` |
| Linux | `/home/alice/.local/share/cuprate/` |
## Blockchain
Cuprate's blockchain directory.
| OS | PATH |
|---------|----------------------------------------------------------------|
| Windows | `C:\Users\Alice\AppData\Roaming\Cuprate\blockchain\` |
| macOS | `/Users/Alice/Library/Application Support/Cuprate/blockchain/` |
| Linux | `/home/alice/.local/share/cuprate/blockchain/` |
## Transaction pool
Cuprate's transaction pool directory.
| OS | PATH |
|---------|------------------------------------------------------------|
| Windows | `C:\Users\Alice\AppData\Roaming\Cuprate\txpool\` |
| macOS | `/Users/Alice/Library/Application Support/Cuprate/txpool/` |
| Linux | `/home/alice/.local/share/cuprate/txpool/` |
## Database
Cuprate's database location/filenames depend on:
- Which database it is
- Which backend is being used
---
`cuprate_blockchain` files are in the above mentioned `blockchain` folder.
`cuprate_txpool` files are in the above mentioned `txpool` folder.
---
If the `heed` backend is being used, these files will be created:
| Filename | Purpose |
|------------|--------------------|
| `data.mdb` | Main data file |
| `lock.mdb` | Database lock file |
For example: `/home/alice/.local/share/cuprate/blockchain/lock.mdb`.
If the `redb` backend is being used, these files will be created:
| Filename | Purpose |
|-------------|--------------------|
| `data.redb` | Main data file |
For example: `/home/alice/.local/share/cuprate/txpool/data.redb`.

View file

@ -0,0 +1 @@
# Resources

View file

@ -0,0 +1 @@
# ⚪️ Memory

View file

@ -0,0 +1 @@
# Sockets

View file

@ -0,0 +1,2 @@
# Index of ports
This is an index of all of the network sockets Cuprate actively uses.

View file

@ -0,0 +1,7 @@
# Custom strings
Many JSON response fields contain strings with custom messages.
This may be error messages, status, etc.
Although the field + string type will be followed, Cuprate will not always
have the exact same message, particularly when it comes to error messages.

View file

@ -0,0 +1,17 @@
# HTTP methods
`monerod` endpoints supports multiple [HTTP methods](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods)
that do not necessarily make sense.
For example:
```bash
curl \
http://127.0.0.1:18081/get_limit \
-H 'Content-Type: application/json' \
--request DELETE
```
This is sending an HTTP `DELETE` request, which should be a `GET`.
`monerod` will respond to this the same as `GET`, `POST`, `PUT`, and `TRACE`.
## Cuprate's behavior
> TODO: decide allowed HTTP methods for Cuprate <https://github.com/Cuprate/cuprate/pull/233#discussion_r1700934928>.

View file

@ -0,0 +1,9 @@
# Differences with `monerod`
As noted in the [introduction](../intro.md), `monerod`'s RPC behavior cannot always be perfectly followed by Cuprate.
The reasoning for the differences can vary from:
- Technical limitations
- Behavior being `monerod`-specific
- Purposeful decision to not support behavior
This section lays out the details of the differences between `monerod`'s and Cuprate's RPC system.

View file

@ -0,0 +1,51 @@
# JSON field ordering
When serializing JSON, `monerod` has the behavior to order key fields within a scope alphabetically.
For example:
```json
{
"id": "0",
"jsonrpc": "2.0",
"result": {
"blockhashing_blob": "...",
"blocktemplate_blob": "...",
"difficulty": 283305047039,
"difficulty_top64": 0,
"expected_reward": 600000000000,
"height": 3195018,
"next_seed_hash": "",
"prev_hash": "9d648e741d85ca0e7acb4501f051b27e9b107d3cd7a3f03aa7f776089117c81a",
"reserved_offset": 131,
"seed_hash": "e2aa0b7b55042cd48b02e395d78fa66a29815ccc1584e38db2d1f0e8485cd44f",
"seed_height": 3194880,
"status": "OK",
"untrusted": false,
"wide_difficulty": "0x41f64bf3ff"
}
}
```
In the main `{}`, `id` comes before `jsonrpc`, which comes before `result`.
The same alphabetical ordering is applied to the fields within `result`.
Cuprate uses [`serde`](https://docs.rs/serde) for JSON serialization,
which serializes fields based on the _definition_ order, i.e. whatever
order the fields are defined in the code, is the order they will appear
in JSON.
Some `struct` fields within Cuprate's RPC types happen to be alphabetical, but this is not a guarantee.
As these are JSON maps, the ordering of fields should not matter,
although this is something to note as the output will technically differ.
## Example incompatibility
An example of where this leads to incompatibility is if specific
line numbers are depended on to contain specific fields.
For example, this will print the 10th line:
```bash
curl http://127.0.0.1:18081/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"get_block_template","params":{"wallet_address":"44GBHzv6ZyQdJkjqZje6KLZ3xSyN1hBSFAnLP6EAqJtCRVzMzZmeXTC2AHKDS9aEDTRKmo6a6o9r9j86pYfhCWDkKjbtcns","reserve_size":60}' -H 'Content-Type: application/json' | sed -n 10p
```
It will be `"height": 3195018` in `monerod`'s case, but may not necessarily be for Cuprate.
By all means, this should not be relied upon in the first place, although it is shown as an example.

View file

@ -0,0 +1,118 @@
# JSON formatting
In general, Cuprate's JSON formatting is very similar to `monerod`, but there are some differences.
This is a list of those differences.
## Pretty vs compact
> TODO: decide when handlers are created if we should allow custom formatting.
Cuprate's RPC (really, [`serde_json`](https://docs.rs/serde_json)) can be configured to use either:
- [Pretty formatting](https://docs.rs/serde_json/latest/serde_json/ser/struct.PrettyFormatter.html)
- [Compact formatting](https://docs.rs/serde_json/latest/serde_json/ser/struct.CompactFormatter.html)
`monerod` uses something _similar_ to pretty formatting.
As an example, pretty formatting:
```json
{
"number": 1,
"array": [
0,
1
],
"string": "",
"array_of_objects": [
{
"x": 1.0,
"y": -1.0
},
{
"x": 2.0,
"y": -2.0
}
]
}
```
compact formatting:
```json
{"number":1,"array":[0,1],"string":"","array_of_objects":[{"x":1.0,"y":-1.0},{"x":2.0,"y":-2.0}]}
```
## Array of objects
`monerod` will format an array of objects like such:
```json
{
"array_of_objects": [{
"x": 0.0,
"y": 0.0,
},{
"x": 0.0,
"y": 0.0,
},{
"x": 0.0,
"y": 0.0
}]
}
```
Cuprate will format the above like such:
```json
{
"array_of_objects": [
{
"x": 0.0,
"y": 0.0,
},
{
"x": 0.0,
"y": 0.0,
},
{
"x": 0.0,
"y": 0.0
}
]
}
```
## Array of maps containing named objects
An method that contains outputs like this is the `peers` field in the `sync_info` method:
```bash
curl \
http://127.0.0.1:18081/json_rpc \
-d '{"jsonrpc":"2.0","id":"0","method":"sync_info"}' \
-H 'Content-Type: application/json'
```
`monerod` will format an array of maps that contains named objects like such:
```json
{
"array": [{
"named_object": {
"field": ""
}
},{
"named_object": {
"field": ""
}
}]
}
```
Cuprate will format the above like such:
```json
{
"array": [
{
"named_object": {
"field": ""
}
},
{
"named_object": {
"field": ""
}
}
]
}
```

Some files were not shown because too many files have changed in this diff Show more