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
12 changes: 0 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,18 +135,6 @@ just integrate

If you do not have `bitcoind` installed, you may simply run `just integrate` and it will be installed for you in the `build` folder.

## Project Layout

`chain`: Contains all logic for syncing block headers, filter headers, filters, parsing blocks. Also contains preset checkpoints for Signet, Regtest, and Bitcoin networks. Notable files: `chain.rs`

`core`: Organizes the primary user-facing components of the API. This includes both the `Node` and the `Client` that all developers will interact with, as well as the `NodeBuilder`. Importantly includes `peer_map.rs`, which is the primary file that handles peer threads by sending messages, persisting new peers, banning peers, and managing peer task handles. `node.rs` is the main application loop, responsible for driving the node actions. Notable files: `node.rs`, `peer_map.rs`, `builder.rs`, `client.rs`

`db`: Defines how data must be persisted with `traits.rs`, and includes some opinionated defaults for database components.

`filters`: Additional structures for managing compact filter headers and filters, used by `chain.rs`

`network`: Opens and closes connections, handles encryption and decryption of messages, generates messages, parses messages, times message response times, performs DNS lookups. Notable files: `peer.rs`, `reader.rs`, `parsers.rs`, `outbound_messages.rs`

## Contributing

Please read [CONTRIBUTING.md](./CONTRIBUTING.md) to get started.
Expand Down
13 changes: 9 additions & 4 deletions doc/DETAILS.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,18 +81,23 @@ The wallet required 12 block downloads, and took 5 minutes.

This section details what behavior to expect when using Kyoto, and why such decisions were made.

### Peer Selection
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is jumping from H1 to H3 a style choice?

## Peer Selection

Kyoto will first connect to all of the configured peers to maintain the connection requirement, and will use peers gleaned from the peer-to-peer gossip thereafter. If no peers are configured when building the node, and no peers are in the database, Kyoto will resort to DNS. Kyoto will not select a peer of the same netgroup (`/16`) as a previously connected peer. When selecting a new peer from the database, a random preference will be selected between a "new" peer and a peer that has been "tried." Rational is derived from [this research](https://www.ethanheilman.com/p/eclipse/index.html)

### Block Headers and Storage
## Block Headers and Storage

Kyoto expects users to adopt some form of persistence between sessions when it comes to block header data. Reason being, Kyoto emits block headers that have been reorganized back to the client in such an event. To do so, in a rare but potential circumstance where the client has shut down on a stale tip, one that is reorganized in the future, Kyoto may use the header persistence to load the older chain into memory. Further, this allows the memory footprint of storing headers in a chain structure to remain small. Kyoto has a soft limit of 20,000 headers in memory at any given time, and if the chain representation exceeds that, Kyoto has a reliable backend to move the excess of block headers. To compensate for this, Kyoto only expects some generic datastore, and does not care about how persistence is implemented.

### Filters
## Filters

Block filters for a full block may be 300-400 bytes, and may be needless overhead if scripts are revealed "into the future" for the underlying wallet. Full filters are checked for matches as they are downloaded, but are discarded thereafter. As a result, if the user adds scripts that are believe to be included in blocks _in the past_, Kyoto will have to redownload the filters. But if the wallet has up to date information, a revealing a new script is guaranteed to have not been used. This memory tradeoff was deemed worthwhile, as it is expected rescanning will only occur for recovery scenarios.

### Structure
## Structure

* `chain`: Contains all logic for syncing block headers, filter headers, filters, parsing blocks. Also contains preset checkpoints for Signet, Regtest, and Bitcoin networks. Notable files: `chain.rs`
* `db`: Defines how data must be persisted with `traits.rs`, and includes some opinionated defaults for database components.
* `filters`: Additional structures for managing compact filter headers and filters, used by `chain.rs`
* `network`: Opens and closes connections, handles encryption and decryption of messages, generates messages, parses messages, times message response times, performs DNS lookups. Notable files: `peer.rs`, `reader.rs`, `parsers.rs`, `outbound_messages.rs`

![Layout](https://github.com/user-attachments/assets/21280bb4-aa88-4e11-9223-aed35a885e99)
4 changes: 2 additions & 2 deletions example/managed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
//! many possible scripts to check. Enable the `filter-control` feature to check filters
//! manually in your program.

use kyoto::core::messages::Event;
use kyoto::{chain::checkpoints::HeaderCheckpoint, core::builder::NodeBuilder, Client};
use kyoto::messages::Event;
use kyoto::{builder::NodeBuilder, chain::checkpoints::HeaderCheckpoint, Client};
use kyoto::{AddrV2, Address, BlockHash, LogLevel, Network, ServiceFlags, TrustedPeer};
use std::collections::HashSet;
use std::{net::Ipv4Addr, str::FromStr};
Expand Down
2 changes: 1 addition & 1 deletion example/rescan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//! the filters for inclusions of these scripts and download the relevant
//! blocks.

use kyoto::{chain::checkpoints::HeaderCheckpoint, core::builder::NodeBuilder};
use kyoto::{builder::NodeBuilder, chain::checkpoints::HeaderCheckpoint};
use kyoto::{Address, Client, Event, Network};
use std::collections::HashSet;
use std::str::FromStr;
Expand Down
2 changes: 1 addition & 1 deletion example/signet.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Usual sync on Signet.

use kyoto::{chain::checkpoints::HeaderCheckpoint, core::builder::NodeBuilder};
use kyoto::{builder::NodeBuilder, chain::checkpoints::HeaderCheckpoint};
use kyoto::{AddrV2, Address, Client, Event, Log, Network, ServiceFlags, TrustedPeer};
use std::collections::HashSet;
use std::{
Expand Down
2 changes: 1 addition & 1 deletion example/testnet4.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Usual sync on Testnet.

use kyoto::{chain::checkpoints::HeaderCheckpoint, core::builder::NodeBuilder};
use kyoto::{builder::NodeBuilder, chain::checkpoints::HeaderCheckpoint};
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not shown in the diff, but managed and tor examples will likely also need an upgrade. They require the additional features flag when building.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah missed that ok, I am gonna try and add that feature flag matrix to CI in a separate PR too.

use kyoto::{Address, Client, Event, Log, Network, PeerStoreSizeConfig, TrustedPeer};
use std::collections::HashSet;
use std::{net::Ipv4Addr, str::FromStr};
Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions src/core/builder.rs → src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use bitcoin::Network;
#[cfg(not(feature = "filter-control"))]
use bitcoin::ScriptBuf;

use super::{client::Client, config::NodeConfig, node::Node, FilterSyncPolicy};
use super::{client::Client, config::NodeConfig, node::Node};
#[cfg(feature = "database")]
use crate::db::error::SqlInitializationError;
#[cfg(feature = "database")]
Expand All @@ -15,7 +15,7 @@ use crate::{
chain::checkpoints::HeaderCheckpoint,
db::traits::{HeaderStore, PeerStore},
};
use crate::{ConnectionType, LogLevel, PeerStoreSizeConfig, TrustedPeer};
use crate::{ConnectionType, FilterSyncPolicy, LogLevel, PeerStoreSizeConfig, TrustedPeer};

#[cfg(feature = "database")]
/// The default node returned from the [`NodeBuilder`](crate::core).
Expand Down
4 changes: 2 additions & 2 deletions src/chain/block_queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use bitcoin::BlockHash;
use tokio::time::Instant;

#[cfg(feature = "filter-control")]
use crate::core::messages::BlockRequest;
use crate::core::messages::BlockSender;
use crate::messages::BlockRequest;
use crate::messages::BlockSender;

const SPAM_LIMIT: u64 = 5;

Expand Down
18 changes: 9 additions & 9 deletions src/chain/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,13 @@ use super::{
HeightMonitor,
};
#[cfg(feature = "filter-control")]
use crate::core::error::FetchBlockError;
use crate::error::FetchBlockError;
#[cfg(feature = "filter-control")]
use crate::core::messages::BlockRequest;
use crate::messages::BlockRequest;
#[cfg(feature = "filter-control")]
use crate::IndexedFilter;
use crate::{
chain::header_batch::HeadersBatch,
core::{
dialog::Dialog,
error::HeaderPersistenceError,
messages::{Event, Warning},
},
db::traits::HeaderStore,
filters::{
cfheader_batch::CFHeaderBatch,
Expand All @@ -41,6 +36,11 @@ use crate::{
Filter, CF_HEADER_BATCH_SIZE, FILTER_BATCH_SIZE,
},
IndexedBlock,
{
dialog::Dialog,
error::HeaderPersistenceError,
messages::{Event, Warning},
},
};

const MAX_REORG_DEPTH: u32 = 5_000;
Expand Down Expand Up @@ -902,11 +902,11 @@ mod tests {
checkpoints::{HeaderCheckpoint, HeaderCheckpoints},
error::HeaderSyncError,
},
core::{
filters::cfheader_chain::AppendAttempt,
{
dialog::Dialog,
messages::{Event, Log, Warning},
},
filters::cfheader_chain::AppendAttempt,
};

use super::{Chain, HeightMonitor};
Expand Down
2 changes: 1 addition & 1 deletion src/chain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub(crate) mod header_chain;

use std::collections::HashMap;

use crate::core::PeerId;
use crate::network::PeerId;

type Height = u32;

Expand Down
4 changes: 1 addition & 3 deletions src/core/channel_messages.rs → src/channel_messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ use bitcoin::{
Block, BlockHash, FeeRate, Transaction, Wtxid,
};

use crate::core::messages::RejectPayload;

use super::PeerId;
use crate::{messages::RejectPayload, network::PeerId};

#[derive(Debug, Clone)]
pub(crate) enum MainThreadMessage {
Expand Down
File renamed without changes.
6 changes: 2 additions & 4 deletions src/core/config.rs → src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@ use std::{collections::HashSet, path::PathBuf, time::Duration};
use bitcoin::ScriptBuf;

use crate::{
chain::checkpoints::HeaderCheckpoint, network::dns::DnsResolver, ConnectionType, LogLevel,
PeerStoreSizeConfig, TrustedPeer,
chain::checkpoints::HeaderCheckpoint, network::dns::DnsResolver, ConnectionType,
FilterSyncPolicy, LogLevel, PeerStoreSizeConfig, TrustedPeer,
};

use super::FilterSyncPolicy;

const REQUIRED_PEERS: u8 = 1;
const TIMEOUT_SECS: u64 = 5;
// sec min hour
Expand Down
108 changes: 0 additions & 108 deletions src/core/mod.rs

This file was deleted.

File renamed without changes.
File renamed without changes.
49 changes: 39 additions & 10 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,6 @@
//! }
//! ```
//!
//! # Getting started
//!
//! The [`core`] module documentation is likely the best place to start when developing an application with Kyoto.
//!
//! # Features
//!
//! `database`: use the default `rusqlite` database implementations. Default and recommend feature.
Expand All @@ -85,12 +81,34 @@

#![warn(missing_docs)]
pub mod chain;
pub mod core;
pub mod db;

mod filters;
mod network;
mod prelude;

mod broadcaster;
/// Convenient way to build a compact filters node.
pub mod builder;
pub(crate) mod channel_messages;
/// Structures to communicate with a node.
pub mod client;
/// Node configuration options.
pub(crate) mod config;
pub(crate) mod dialog;
/// Errors associated with a node.
pub mod error;
/// Messages the node may send a client.
pub mod messages;
/// The structure that communicates with the Bitcoin P2P network and collects data.
pub mod node;

/// Receive an [`IndexedBlock`] from a request.
#[cfg(feature = "filter-control")]
pub type BlockReceiver = tokio::sync::oneshot::Receiver<Result<IndexedBlock, FetchBlockError>>;

#[cfg(feature = "filter-control")]
use crate::error::FetchBlockError;
#[cfg(feature = "filter-control")]
use filters::Filter;
#[cfg(feature = "filter-control")]
Expand Down Expand Up @@ -123,11 +141,12 @@ pub use tokio::sync::mpsc::UnboundedReceiver;

#[doc(inline)]
pub use {
crate::core::builder::NodeBuilder,
crate::core::client::{Client, Requester},
crate::core::error::{ClientError, NodeError},
crate::core::messages::{Event, Log, Progress, RejectPayload, SyncUpdate, Warning},
crate::core::node::{Node, NodeState},
crate::builder::NodeBuilder,
crate::client::{Client, Requester},
crate::error::{ClientError, NodeError},
crate::messages::{Event, Log, Progress, RejectPayload, SyncUpdate, Warning},
crate::network::PeerTimeoutConfig,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was previously used internally and did not hit the public API, but I think another method on the builder to allow users to use the PeerTimeoutConfig type would be a good follow up

crate::node::{Node, NodeState},
};

#[doc(inline)]
Expand Down Expand Up @@ -439,6 +458,16 @@ pub enum LogLevel {
Warning,
}

/// Should the node immediately download filters or wait for a command
#[derive(Debug, Default)]
pub enum FilterSyncPolicy {
/// The node will wait for an explicit command to start downloading and checking filters
Halt,
/// Filters are downloaded immediately after CBF headers are synced.
#[default]
Continue,
}

macro_rules! log {
($dialog:expr, $expr:expr) => {
match $dialog.log_level {
Expand Down
2 changes: 1 addition & 1 deletion src/core/messages.rs → src/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ pub(crate) enum ClientMessage {
AddScript(ScriptBuf),
/// Starting at the configured anchor checkpoint, look for block inclusions with newly added scripts.
Rescan,
/// If the [`FilterSyncPolicy`](crate) is set to `Halt`, issuing this command will
/// If the [`FilterSyncPolicy`] is set to `Halt`, issuing this command will
/// start the filter download and checking process. Otherwise, this command will not have any effect
/// on node operation.
ContinueDownload,
Expand Down
Loading