Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/ch01-01-utreexonode.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ Blocks fetched by `UtreexoNode` are passed to a blockchain backend for validatio

Below is the actual type definition, which is a struct with two fields and trait bounds for the `Chain` backend.

Filename: floresta-wire/src/p2p_wire/node.rs
Filename: floresta-wire/src/p2p_wire/node/mod.rs

```rust
# // Path: floresta-wire/src/p2p_wire/node.rs
# // Path: floresta-wire/src/p2p_wire/node/mod.rs
#
pub struct UtreexoNode<Chain: ChainBackend, Context = RunningNode> {
pub(crate) common: NodeCommon<Chain>,
Expand Down
2 changes: 1 addition & 1 deletion src/ch01-02-chain-backend-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ pub trait BlockchainInterface {
# fn update_acc(
# &self,
# acc: Stump,
# block: Block,
# block: &Block,
# height: u32,
# proof: Proof,
# del_hashes: Vec<sha256::Hash>,
Expand Down
2 changes: 1 addition & 1 deletion src/ch03-04-block-validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub fn validate_block_no_acc(

let bip34_height = self.chain_params().params.bip34_height;
// If bip34 is active, check that the encoded block height is correct
if height >= bip34_height && self.get_bip34_height(block) != Some(height) {
if height >= bip34_height && Consensus::get_bip34_height(block) != Some(height) {
return Err(BlockValidationErrors::BadBip34)?;
}

Expand Down
8 changes: 3 additions & 5 deletions src/ch04-01-transaction-validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub fn validate_block_no_acc(
#
# let bip34_height = self.chain_params().params.bip34_height;
# // If bip34 is active, check that the encoded block height is correct
# if height >= bip34_height && self.get_bip34_height(block) != Some(height) {
# if height >= bip34_height && Consensus::get_bip34_height(block) != Some(height) {
# return Err(BlockValidationErrors::BadBip34)?;
# }
#
Expand Down Expand Up @@ -169,10 +169,8 @@ pub fn verify_block_transactions(
let coinbase_total = transactions[0]
.output
.iter()
.try_fold(Amount::ZERO, |acc, out| {
acc.checked_add(out.value)
.ok_or(BlockValidationErrors::TooManyCoins)
})?;
.try_fold(Amount::ZERO, |acc, out| acc.checked_add(out.value))
.ok_or(BlockValidationErrors::TooManyCoins)?;

if coinbase_total > allowed_reward {
return Err(BlockValidationErrors::BadCoinbaseOutValue)?;
Expand Down
10 changes: 5 additions & 5 deletions src/ch06-00-utreexonode-in-depth.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ The two fields of `UtreexoNode` are the `NodeCommon<Chain>` struct and the gener

`NodeCommon` represents the core state and data required for node operations, independent of the context. It keeps the `Chain` backend, optional compact block filters, the mempool, the `UtreexoNodeConfig` and `Network`, peer connection data, networking configurations, and time-based events to enable effective node behavior and synchronization.

Filename: floresta-wire/src/p2p_wire/node.rs
Filename: floresta-wire/src/p2p_wire/node/mod.rs

```rust
# // Path: floresta-wire/src/p2p_wire/node.rs
# // Path: floresta-wire/src/p2p_wire/node/mod.rs
#
pub struct NodeCommon<Chain: ChainBackend> {
// 1. Core Blockchain and Transient Data
Expand Down Expand Up @@ -71,10 +71,10 @@ pub struct UtreexoNode<Chain: ChainBackend, Context = RunningNode> {

On the other hand, the `Context` generic in `UtreexoNode` will allow the node to implement additional functionality and manage data specific to a particular context. This is explained in the [next section](ch06-01-node-contexts.md).

Although the `Context` generic in the type definition is not constrained by any trait, in the `UtreexoNode` implementation block (from the same _node.rs_ file), this generic is bound by both a `NodeContext` trait and the `Default` trait.
Although the `Context` generic in the type definition is not constrained by any trait, in the `UtreexoNode` implementation blocks this generic is bound by both a `NodeContext` trait and the `Default` trait.

```rust
# // Path: floresta-wire/src/p2p_wire/node.rs
# // Path: floresta-wire/src/p2p_wire/node/mod.rs
#
impl<T, Chain> UtreexoNode<Chain, T>
where
Expand All @@ -94,7 +94,7 @@ In this implementation block, we also encounter a `WireError`, which serves as t
To avoid repetitively calling `self.common.field_name` to access the many inner `NodeCommon` fields, `UtreexoNode` implements the `Deref` and `DerefMut` traits. This means that we can access the `NodeCommon` fields as if they were fields of `UtreexoNode`.

```rust
# // Path: floresta-wire/src/p2p_wire/node.rs
# // Path: floresta-wire/src/p2p_wire/node/mod.rs
#
impl<Chain: ChainBackend, T> Deref for UtreexoNode<Chain, T> {
fn deref(&self) -> &Self::Target {
Expand Down
4 changes: 3 additions & 1 deletion src/ch06-01-node-contexts.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ pub trait NodeContext {
const BLOCKS_PER_GETDATA: usize = 5;
# /// How many concurrent GETDATA packages we can send at the same time
const MAX_CONCURRENT_GETDATA: usize = 10;
# /// How often we perform the main loop maintenance tasks (checking for timeouts, peers, etc.)
const MAINTENANCE_TICK: Duration = Duration::from_secs(1);

fn get_required_services(&self) -> ServiceFlags {
ServiceFlags::NETWORK
Expand Down Expand Up @@ -118,6 +120,6 @@ where

Since `UtreexoNode<RunningNode, _>`, `UtreexoNode<SyncNode, _>`, and `UtreexoNode<ChainSelector, _>` are all entirely different types (because Rust considers each generic parameter combination a separate type), we cannot mistakenly use methods that are not intended for a specific context.

The only shared functionality is that which is implemented generically for `T: NodeContext`, which all three contexts satisfy, located in _p2p_wire/node.rs_ (as we have seen [in the previous section](ch06-00-utreexonode-in-depth.md)).
The shared functionality is what is implemented generically for `T: NodeContext`, which all three contexts satisfy (as we have seen [in the previous section](ch06-00-utreexonode-in-depth.md)).

In the next sections within this chapter we will see some of these shared functions and methods implementations.
6 changes: 3 additions & 3 deletions src/ch06-02-utreexonode-config-and-builder.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ While `ChainSelector`, `SyncNode`, and `RunningNode` provide `impl` blocks for `

### UtreexoNode Builder

Let's start with the builder function, taking a `UtreexoNodeConfig`, the `Chain` backend, a mempool type, optional compact block filters from the `floresta-compact-filters` crate, a kill signal to stop the node, and the address manager backend (that we will see [later in this chapter](ch06-04-address-manager.md)).
Let's start with the builder function, taking a `UtreexoNodeConfig`, the `Chain` backend, a floresta mempool type, optional compact block filters from the `floresta-compact-filters` crate, a kill signal to stop the node, and the address manager backend (that we will see [later in this chapter](ch06-04-address-manager.md)).

```rust
# // Path: floresta-wire/src/p2p_wire/node.rs
# // Path: floresta-wire/src/p2p_wire/node/mod.rs
#
impl<T, Chain> UtreexoNode<Chain, T>
where
Expand Down Expand Up @@ -79,7 +79,7 @@ where

The `UtreexoNodeConfig` type outlines all the customizable options for running a `UtreexoNode`. It specifies essential settings like the network, connection preferences, and resource management options. It also has a `UtreexoNodeConfig::default` implementation. This type is better explained below.

Then, the `Mempool` type that we see in the signature is a very simple mempool implementation for broadcasting transactions to the network.
Then, the `Mempool` type that we see in the signature is a simple mempool implementation for broadcasting transactions to the network.

The first line creates an unbounded **multi-producer, single-consumer** (mpsc) channel, allowing multiple tasks in the `UtreexoNode` to send messages (via the sender `node_tx`) to a central task that processes them (via the receiver `node_rx`). If you are not familiar with channels, there's [a section from the Rust book](https://doc.rust-lang.org/book/ch16-02-message-passing.html) that covers them. Here, we use `tokio` channels instead of Rust's standard library channels.

Expand Down
14 changes: 7 additions & 7 deletions src/ch06-03-opening-connections.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ In this section we are finally going to understand how Floresta connects to peer
The `maybe_open_connection` method determines whether the node should establish a new connection to a peer and, if so, calls `create_connection`.

```rust
# // Path: floresta-wire/src/p2p_wire/node.rs
# // Path: floresta-wire/src/p2p_wire/node/conn.rs
#
pub(crate) fn maybe_open_connection(
&mut self,
Expand All @@ -21,9 +21,9 @@ pub(crate) fn maybe_open_connection(

// If we've tried getting some connections, but the addresses we have are not
// working. Try getting some more addresses from DNS
self.maybe_ask_for_dns_peers();
self.maybe_ask_dns_seed_for_addresses();
let needs_utreexo = required_service.has(service_flags::UTREEXO.into());
self.maybe_use_hadcoded_addresses(needs_utreexo);
self.maybe_use_hardcoded_addresses(needs_utreexo);

// Try to connect with manually added peers
self.maybe_open_connection_with_added_peers()?;
Expand All @@ -46,7 +46,7 @@ The `ConnectionKind` struct that `create_connection` takes as argument is explai
### Connection Kinds

```rust
# // Path: floresta-wire/src/p2p_wire/node.rs
# // Path: floresta-wire/src/p2p_wire/node/mod.rs
#
pub enum ConnectionKind {
Feeler,
Expand All @@ -72,7 +72,7 @@ Extra connections extend the node’s reach by connecting to additional peers fo
If no fixed peer is specified, we get a suitable peer address (or `LocalAddress`) for connection by calling `self.address_man.get_address_to_connect`. This method takes the required services and a boolean indicating whether a feeler connection is desired. We will explore this method in the next section.

```rust
# // Path: floresta-wire/src/p2p_wire/node.rs
# // Path: floresta-wire/src/p2p_wire/node/conn.rs
#
pub(crate) fn create_connection(&mut self, kind: ConnectionKind) -> Result<(), WireError> {
let required_services = match kind {
Expand Down Expand Up @@ -146,7 +146,7 @@ Moving on to `open_connection`, we create a new `unbounded_channel` for sending
Then, depending on the value of `self.socks5` we will call `UtreexoNode::open_proxy_connection` or `UtreexoNode::open_non_proxy_connection`. Each one of these functions will create a `Peer` instance with the provided data and the channel receiver.

```rust
# // Path: floresta-wire/src/p2p_wire/node.rs
# // Path: floresta-wire/src/p2p_wire/node/conn.rs
#
pub(crate) fn open_connection(
&mut self,
Expand Down Expand Up @@ -232,7 +232,7 @@ pub(crate) fn open_connection(
}
```

Last of all, we simply insert the new inflight request (via the `InflightRequests` type) to our tracker `HashMap`, as well as the new peer (via the `LocalPeerView`). Both types are also defined in _p2p_wire/node.rs_, along with `UtreexoNode`, `NodeCommon`, `ConnectionKind`, and a few other types.
Last of all, we simply insert the new inflight request (via the `InflightRequests` type) to our tracker `HashMap`, as well as the new peer (via the `LocalPeerView`). Both types are defined in _p2p_wire/node/mod.rs_, along with `UtreexoNode`, `NodeCommon`, `ConnectionKind`, and a few other types.

### Recap

Expand Down
4 changes: 2 additions & 2 deletions src/ch07-00-peer-to-peer-networking.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ If successful, we get the transport reader and writer, which are of type `ReadTr
It then sets up an 'actor', that is, an independent component that reads incoming messages and communicates them to the 'actor receiver'. The actor is effectively a transport reader wrapper.

```rust
# // Path: floresta-wire/src/p2p_wire/node.rs
# // Path: floresta-wire/src/p2p_wire/node/conn.rs
#
pub(crate) async fn open_non_proxy_connection(
kind: ConnectionKind,
Expand Down Expand Up @@ -81,7 +81,7 @@ By the end of this function, a fully initialized `Peer` is ready to manage commu
The `open_proxy_connection` is pretty much the same, except we get the transport reader and writer from the proxy connection instead, handled by `transport::connect_proxy`.

```rust
# // Path: floresta-wire/src/p2p_wire/node.rs
# // Path: floresta-wire/src/p2p_wire/node/conn.rs
#
pub(crate) async fn open_proxy_connection(
proxy: SocketAddr,
Expand Down