node_db.rs
Overview
This file implements the NodeDb structure, which provides read-only access to a node database stored in an SQLite file. It primarily facilitates querying account data and extracting sets of blockchain-related entities such as accounts and wallets. The database interactions are encapsulated in safe methods that handle opening connections, executing SQL queries, and deserializing blockchain data structures into usable Rust objects.
NodeDb also implements two key traits: AccountProvider and BkSetProvider, enabling it to serve as a source for account information and a "bk set" (a set of wallet addresses derived from epochs) within the broader blockchain resolver system.
Structures and Traits
NodeDb
pub struct NodeDb {
path: PathBuf,
}
Description
Encapsulates the path to the node database file and provides methods to open the database and query blockchain account data.
Fields
path: PathBuf— the filesystem path to the SQLite database file.
Methods
pub fn new(path: impl AsRef<Path>) -> SelfConstructs a new
NodeDbinstance with the specified database file path.Parameters:
path— any type convertible to a filesystem path reference.
Returns: A new
NodeDbinstance.Usage Example:
let db = NodeDb::new("/path/to/node_db.sqlite");fn open_conn(path: &PathBuf) -> anyhow::Result<rusqlite::Connection>Opens a read-only SQLite connection to the node database file with specific flags to ensure safe concurrent reads.
Parameters:
path— a reference to the database file path.
Returns: A
rusqlite::Connectionor an error if the file cannot be opened.fn get_account(conn: &rusqlite::Connection, id: &UInt256) -> anyhow::Result<Account>Retrieves an account record from the database by its unique identifier.
Parameters:
conn— active SQLite connection.id— account identifier as a 256-bit unsigned integer.
Returns: An
Accountobject or an error if not found or data is corrupted.Implementation Details:
Executes a SQL query to get the serialized account BOC (Bag of Cells).
Deserializes the BOC bytes into a
tvm_types::Cell.Loads a
SliceDatafrom the cell.Constructs an
Accountinstance from the slice.
fn get_account_ids_by_code_hash(conn: &rusqlite::Connection, code_hash: UInt256) -> anyhow::Result<Vec<UInt256>>Queries all account IDs whose code hash matches the specified value.
Parameters:
conn— active SQLite connection.code_hash— the code hash to filter accounts.
Returns: A vector of account IDs (
UInt256).Implementation Details:
Runs a SQL query filtering on the
code_hashfield.Parses the string IDs into
UInt256.
fn get_bk_set(conn: &rusqlite::Connection) -> anyhow::Result<Vec<UInt256>>Computes the set of wallet addresses involved in the blockchain epochs.
Parameters:
conn— active SQLite connection.
Returns: A vector of wallet addresses (
UInt256).Implementation Details:
Retrieves the root account (using a constant root address).
Extracts the epoch code hash from the root.
Finds all epoch accounts by this code hash.
Extracts owner addresses from each epoch and aggregates them into a set.
fn with_connection<T>(&self, f: impl FnOnce(&rusqlite::Connection) -> anyhow::Result<T>) -> Option<T>Helper function that opens a connection and executes a provided closure with error handling.
Parameters:
f— closure that accepts a connection and returns a result.
Returns:
Somewith the closure's successful output orNoneon error.Error Handling:
Logs errors using
tracing::error!.Converts internal errors into
Noneto avoid panics.
Constants and Helper Functions
const ROOT_ADDR: [u8; 32] = [0x77u8; 32];Hardcoded 32-byte array representing the root account address.
fn root_addr() -> UInt256Converts the constant
ROOT_ADDRinto aUInt256instance.
Trait Implementations
BkSetProvider for NodeDb
fn get_bk_set(&self) -> Vec<UInt256> {
self.with_connection(Self::get_bk_set).unwrap_or_default()
}
Provides the blockchain wallet set by delegating to the internal
get_bk_setmethod.Returns an empty vector if database access fails.
AccountProvider for NodeDb
fn get_account(&self, id: &UInt256) -> Option<Account> {
self.with_connection(|conn| Self::get_account(conn, id))
}
Returns an optional
Accountfor a given account ID by querying the database.Returns
Noneif the account is not found or if an error occurs.
Important Implementation Details and Algorithms
Database Access: Uses
rusqlitewithSQLITE_OPEN_READ_ONLYand other flags to ensure safe concurrent access without locks (SQLITE_OPEN_NO_MUTEX).Account Storage: Accounts are stored in an
accountstable with fields includingidand serializedboc.Deserialization: Uses the TVM (TON Virtual Machine)
tvm_typesto deserialize Bag of Cells (BOC) data into blockchain account structures.Error Handling: Combines Rust's
anyhowcrate with detailed error messages and logging viatracing.Set Construction: Uses a
HashSetto avoid duplicates when collecting wallet IDs from epochs.
File Interaction with Other System Components
Blockchain Entities: Interacts with blockchain domain objects such as
Account,Epoch, andRootimported fromtvm_blockandresolver::blockchain::accounts.Traits: Implements
AccountProviderandBkSetProviderfrom theresolver::blockchainmodule, enabling integration with the blockchain resolver system.Database Layer: Acts as a data source for blockchain state by reading from a node's SQLite database.
The deserialization and account structure logic rely on the
tvm_typesandtvm_blockcrates, which encapsulate the TON blockchain data model.Logging and error handling are consistent with the application's tracing and error management approaches.
Visual Diagram
classDiagram
class NodeDb {
-path: PathBuf
+new()
-open_conn()
-get_account()
-get_account_ids_by_code_hash()
-get_bk_set()
-with_connection()
}
NodeDb ..|> AccountProvider
NodeDb ..|> BkSetProvider
class AccountProvider {
<<trait>>
+get_account()
}
class BkSetProvider {
<<trait>>
+get_bk_set()
}
This class diagram shows NodeDb as the central data access struct with private methods for database operations and public trait implementations for providing account and blockchain wallet set data. The diagram highlights the encapsulation of database path and internal helper functions.