mirror of
https://github.com/Cuprate/cuprate.git
synced 2024-12-22 19:49:28 +00:00
Add design document
This commit is contained in:
parent
58a076f3aa
commit
b483415c87
2 changed files with 209 additions and 3 deletions
|
@ -1,6 +1,5 @@
|
||||||
<div>
|
![Cuprate](misc/logo/wordmark/CuprateWordmark.svg)
|
||||||
<img src="misc/logo/wordmark/CuprateWordmark.svg" alt="Cuprate"/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
|
|
207
misc/DESIGN.md
Normal file
207
misc/DESIGN.md
Normal file
|
@ -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.
|
Loading…
Reference in a new issue