From b483415c87d704d8d6d47e3285d0497849749f72 Mon Sep 17 00:00:00 2001
From: Boog900 <54e72d8a-345f-4599-bd90-c6b9bc7d0ec5@aleeas.com>
Date: Tue, 1 Aug 2023 02:04:57 +0100
Subject: [PATCH] Add design document
---
README.md | 5 +-
misc/DESIGN.md | 207 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 209 insertions(+), 3 deletions(-)
create mode 100644 misc/DESIGN.md
diff --git a/README.md b/README.md
index 96889a32..99fa20f4 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,5 @@
-
-
-
+![Cuprate](misc/logo/wordmark/CuprateWordmark.svg)
+
----
diff --git a/misc/DESIGN.md b/misc/DESIGN.md
new file mode 100644
index 00000000..9a56ae85
--- /dev/null
+++ b/misc/DESIGN.md
@@ -0,0 +1,207 @@
+![Cuprate](logo/wordmark/CuprateWordmark.svg)
+
+---
+
+## Index
+
+1. [Introduction](#introduction)
+2. [P2P](#p2p)
+ 1. [levin-cuprate](#levin-cuprate)
+ 2. [monero-wire](#monero-wire)
+ 3. [cuprate-p2p](#cuprate-p2p)
+3. [Verifier](#verifier)
+ 1. [block](#block)
+ 2. [transaction](#transaction)
+4. [Syncer](#syncer)
+ 1. [Block downloader](#the-block-downloader)
+5. [Database](#database)
+
+
+
+### Introduction
+
+This document outlines the initial plan for Cuprate, a Rust Monero node. Currently, Monero only
+has one node implementation, which many would class as an issue.
+
+This document isn't supposed to outline everything, but it is meant to give a good overview of the
+plan.
+
+Cuprate won't build everything from scratch and aims to use crates already in existence
+when they're a good fit, an example is monero-serai for our transactions and blocks.
+
+Cuprate makes heavy use of [tower](https://docs.rs/tower/latest/tower/index.html) to modularize its
+parts. Using tower across the node will provide us with a consistent API and will allow us to use towers
+extensive middleware, for tasks such as routing requests and timeouts.
+
+---
+
+### P2P
+
+Cuprates P2P takes heavy inspiration from Zebra. The P2P crate will abstract the network into one endpoint,
+meaning other parts of the node will have no P2P code except from sending requests to this one endpoint.
+This endpoint will be made of a few different tower::Services for the different routing methods, the most
+simple method is to use a load balancing algorithm to send a request to one peer.
+
+The peer to peer part of Cuprate will be split into 3 crates:
+
+| Name | Short Description |
+|---------------|-----------------------------------------------------------------------------------------------|
+| levin-cuprate | A library containing the levin header format. |
+| monero-wire | A library containing all Monero P2P messages built on-top of `levin-cuprate`. |
+| cuprate-p2p | A library abstracting the P2P network away, with logic for handshakes, the address book, etc. |
+
+#### levin-cuprate
+
+This library will have the [levin header format](https://github.com/monero-project/monero/blob/master/docs/LEVIN_PROTOCOL.md#header),
+with a [tokio-codec](https://docs.rs/tokio-util/0.7.8/tokio_util/codec/index.html) for encoding and
+decoding p2p messages. To do this a trait `LevinMessage` will be used so users can define their own
+P2P messages. This will allow other Rust projects to use the levin header format with different messages.
+
+#### monero-wire
+
+This will be a library built on top of [levin-cuprate](#levin-cuprate), It will contain every P2P
+message with decoding/ encoding capability. This library will implement the `LevinMessage` trait.
+
+The serialization format used for P2P messages has already been implemented in Rust, multiple times :). I have decided to
+implement it yet again in the crate: `epee-encoding`. This crate was created specifically for use in Cuprate.
+
+The monero-wire crate will be able to be used in other Rust projects who want to interact with Monero's P2P network.
+
+#### cuprate-p2p
+
+This library will abstract the P2P network away into one endpoint. Sadly, this endpoint will have to be made
+up of different tower::Services for the different routing methods. For example, new blocks need to be sent to every
+peer but a request may only need to go to a single peer.
+
+The library will be split into many modules:
+
+##### protocol
+
+To be compatible with tower::Service the Monero P2P protocol needs to be split into requests and responses.
+Levin admin messages are already in the request/ response format, but notifications are not. For some
+notifications it's easy: `GetObjectsRequest` but for others it's harder.
+Here is a table of the Monero P2P messages put in either requests or responses:
+```
+/// Admin (These are already in request/ response format):
+/// Handshake,
+/// TimedSync,
+/// Ping,
+/// SupportFlags
+/// Protocol:
+/// Request: GetObjectsRequest, Response: GetObjectsResponse,
+/// Request: ChainRequest, Response: ChainEntryResponse,
+/// Request: FluffyMissingTransactionsRequest, Response: NewFluffyBlock, <- these 2 could be requests or responses
+/// Request: GetTxPoolCompliment, Response: NewTransactions, <-
+/// Request: NewBlock, Response: None,
+/// Request: NewFluffyBlock, Response: None,
+/// Request: NewTransactions, Response: None
+```
+
+To split messages that can be requests or responses we will need to keep track of sent
+requests.
+
+##### peer
+
+This will contain a `Client` and `Connection`. The `Connection` will be an async task that gives requests from
+the peer to the inbound request handler and sends requests from Cuprate to the peer. The `Client` will implement
+tower::Service and will simply pass requests from our node to the `Connection` task.
+
+This module will also contain a `Handshaker` which is responsible for taking a peer connection doing a handshake with it
+and creating a `Client` and `Connection`.
+
+##### address book
+
+The address book will use the same overall idea as monerod's address book. It will contain a White, Grey and Anchor
+list. Under the hood we will have 3 separate address books for each network (clear, i2p, Tor) and will route requests
+using a tower::Steer.
+
+White: Peers we have connected to at some point.
+
+Gray: Peers we have heard about but haven't attempted to connect to.
+
+Anchor: A list of currently connected peers so, if we were to re-start, we can choose a couple peers from this list to
+reduce our chance of being isolated.
+
+The address book will be an async task which we will be able to interact with through a tower::Service.
+
+##### peer set
+
+This is the part of the P2P crate that holds all currently connected peers. The rest of Cuprate will interact with this
+structure to send requests to the network. There will be multiple tower::Service interfaces to interact with the network
+for the different routing methods:
+
+- broadcast: send a message to all ready `Clients`
+- single: use a load balancing algorithm to route a message to a single `Client`
+- multiple: sends a request to an amount of peers chosen by the requester, this might be joined with broadcast.
+
+*There may be more routing methods in the future*
+
+---
+
+### Verifier
+
+The verifier will be split into 2 different tower::Services: block and transaction. All checks will
+be explicit and won't be scattered around the codebase, if for some reason we do have to scatter checks
+(some are preformed at de-serialisation for example) they will be referred to in to in the non-scattered
+location.
+
+The verifiers tower::Services will be optional and behind a feature flags so projects that need Monero's consensus
+rules won't have to use the tower interface.
+
+#### Block
+
+Responsible for performing block validation, able to handle multiple blocks at once.
+
+Block verification will need Random-X. Cuprate, at the moment will use Rust bindings and not the Rust Monero
+Miner, although in the future we would like to move to a Rust Random-X. We will also use Rust bindings to the
+old CryptoNight POW(s).
+
+#### Transaction
+
+Responsible for validating transactions. This is able to handle one or more transactions at a time to
+benefit from batching verification where we can, currently only bulletproofs(+) is able to be batched.
+monero-serai already has the API to allow batch verification of bulletproofs(+). Also accepting multiple
+transactions will also allow us to use a thread-pool like `rayon` to parallelize verification that can't
+be batched.
+
+Transaction verification will be split into 2 sections: hard and soft.
+
+##### Hard:
+If a transaction fails this, the node will reject the transaction completely including in blocks.
+
+##### Soft:
+If a transaction fails this, the node won't broadcast the transaction but will allow it in blocks.
+
+This is to make it easy to do things like stopping transaction with too large extra fields and making transactions
+follow a standard decoy selection algorithm (this isn't planned) without the need for a hard fork.
+
+---
+
+### Syncer
+
+The syncer will be responsible for syncing the blockchain after falling behind. It will utilize many of the components
+we have discussed, a new tower::Service is needed though `The block downloader`.
+
+#### The block downloader
+
+This will be responsible for finding the chain tip and getting blocks from peers, it does no verification* and simply gets
+the next block.
+
+(*) some verification may be done here just to see if the block we got is the one we asked for but TBD.
+
+The syncer will call the block downloader to get the chain-tip then it will call for the next batch of blocks, when it has this batch
+it will send it to the block verifier, which will return if the blocks are valid, if they are we add them to our blockchain.
+
+---
+
+### Database
+
+The database interface will abstract away the underlying database to allow us to easily swap out the database for a different one,
+this makes it possible to performance test different databases for our workload, which we plan to do. Initially we plan to go with
+MDBX, a database similar to LMDB which is used in monerod.
+
+We plan to investigate the database schema for optimisations as well, so our schema will more than likely be different than monerods.
+
+Cuprate will interact with the database though a tower::Service providing another layer of abstraction, the service will make use of
+the database interface abstraction. This allows us to make use of towers middleware for the database and makes the database conform to
+the API of the rest of the node.