drk: introduced sled cache

This commit is contained in:
skoupidi
2025-06-03 15:01:43 +03:00
parent 1af99477b1
commit 4eca3e248d
7 changed files with 137 additions and 2 deletions

1
Cargo.lock generated
View File

@@ -2478,6 +2478,7 @@ dependencies = [
"signal-hook",
"signal-hook-async-std",
"simplelog",
"sled-overlay",
"smol",
"structopt",
"structopt-toml",

View File

@@ -27,6 +27,7 @@ prettytable-rs = "0.10.0"
rand = "0.8.5"
rodio = {version = "0.20.1", default-features = false, features = ["minimp3"]}
rusqlite = {version = "0.36.0", features = ["sqlcipher"]}
sled-overlay = "0.1.8"
toml = "0.9.5"
url = "2.5.4"

View File

@@ -14,6 +14,9 @@ fun = true
# Localnet blockchain network configuration
[network_config."localnet"]
# Path to blockchain cache database
cache_path = "~/.local/share/darkfi/drk/localnet/cache"
# Path to wallet database
wallet_path = "~/.local/share/darkfi/drk/localnet/wallet.db"
@@ -25,6 +28,9 @@ endpoint = "tcp://127.0.0.1:8240"
# Testnet blockchain network configuration
[network_config."testnet"]
# Path to blockchain cache database
cache_path = "~/.local/share/darkfi/drk/testnet/cache"
# Path to wallet database
wallet_path = "~/.local/share/darkfi/drk/testnet/wallet.db"
@@ -36,6 +42,9 @@ endpoint = "tcp://127.0.0.1:8340"
# Mainnet blockchain network configuration
[network_config."mainnet"]
# Path to blockchain cache database
cache_path = "~/.local/share/darkfi/drk/mainnet/cache"
# Path to wallet database
wallet_path = "~/.local/share/darkfi/drk/mainnet/wallet.db"

59
bin/drk/src/cache.rs Normal file
View File

@@ -0,0 +1,59 @@
/* This file is part of DarkFi (https://dark.fi)
*
* Copyright (C) 2020-2025 Dyne.org foundation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use darkfi::Result;
use sled_overlay::sled;
pub const SLED_ORDER_TREE: &[u8] = b"_order";
pub const SLED_STATE_INVERSE_DIFF_TREE: &[u8] = b"_state_inverse_diff";
pub const SLED_MERKLE_TREES_TREE: &[u8] = b"_merkle_trees";
pub const SLED_MONEY_SMT_TREE: &[u8] = b"_money_smt";
/// Structure holding all sled trees that define the Blockchain cache.
#[derive(Clone)]
pub struct Cache {
/// Main pointer to the sled db connection
pub sled_db: sled::Db,
/// The `sled` tree storing the order of the blockchain's blocks,
/// where the key is the height number, and the value is the blocks'
/// hash.
pub order: sled::Tree,
/// The `sled` tree storing each blocks' full database state inverse
/// changes, where the key is the block height number, and the value
/// is the serialized database inverse diff.
pub state_inverse_diff: sled::Tree,
/// The `sled` tree storing the merkle trees of the blockchain,
/// where the key is the tree name, and the value is the serialized
/// merkle tree itself.
pub merkle_trees: sled::Tree,
/// The `sled` tree storing the Sparse Merkle Tree of the money
/// contract.
pub money_smt: sled::Tree,
}
impl Cache {
/// Instantiate a new `Cache` with the given `sled` database.
pub fn new(db: &sled::Db) -> Result<Self> {
let order = db.open_tree(SLED_ORDER_TREE)?;
let state_inverse_diff = db.open_tree(SLED_STATE_INVERSE_DIFF_TREE)?;
let merkle_trees = db.open_tree(SLED_MERKLE_TREES_TREE)?;
let money_smt = db.open_tree(SLED_MONEY_SMT_TREE)?;
Ok(Self { sled_db: db.clone(), order, state_inverse_diff, merkle_trees, money_smt })
}
}

View File

@@ -60,8 +60,14 @@ pub mod scanned_blocks;
pub mod walletdb;
use walletdb::{WalletDb, WalletPtr};
/// Blockchain cache database operations handler
pub mod cache;
use cache::Cache;
/// CLI-util structure
pub struct Drk {
/// Blockchain cache database operations handler
pub cache: Cache,
/// Wallet database operations handler
pub wallet: WalletPtr,
/// JSON-RPC client to execute requests to darkfid daemon
@@ -72,12 +78,20 @@ pub struct Drk {
impl Drk {
pub async fn new(
cache_path: String,
wallet_path: String,
wallet_pass: String,
endpoint: Option<Url>,
ex: Arc<smol::Executor<'static>>,
fun: bool,
) -> Result<Self> {
// Initialize blockchain cache database
let db_path = expand_path(&cache_path)?;
let sled_db = sled_overlay::sled::open(&db_path)?;
let Ok(cache) = Cache::new(&sled_db) else {
return Err(Error::DatabaseError(format!("{}", WalletDbError::InitializationFailed)));
};
// Initialize wallet
let wallet_path = expand_path(&wallet_path)?;
if !wallet_path.exists() {
@@ -96,7 +110,7 @@ impl Drk {
None
};
Ok(Self { wallet, rpc_client, fun })
Ok(Self { cache, wallet, rpc_client, fun })
}
/// Initialize wallet with tables for `Drk`.

View File

@@ -550,6 +550,10 @@ enum ContractSubcmd {
#[derive(Clone, Debug, serde::Deserialize, structopt::StructOpt, structopt_toml::StructOptToml)]
#[structopt()]
struct BlockchainNetwork {
#[structopt(long, default_value = "~/.local/share/darkfi/drk/localnet/cache")]
/// Path to blockchain cache database
cache_path: String,
#[structopt(long, default_value = "~/.local/share/darkfi/drk/localnet/wallet.db")]
/// Path to wallet database
wallet_path: String,
@@ -608,6 +612,7 @@ async fn parse_blockchain_config(
/// Auxiliary function to create a `Drk` wallet for provided configuration.
async fn new_wallet(
cache_path: String,
wallet_path: String,
wallet_pass: String,
endpoint: Option<Url>,
@@ -620,7 +625,7 @@ async fn new_wallet(
exit(2);
}
match Drk::new(wallet_path, wallet_pass, endpoint, ex, fun).await {
match Drk::new(cache_path, wallet_path, wallet_pass, endpoint, ex, fun).await {
Ok(wallet) => wallet,
Err(e) => {
eprintln!("Error initializing wallet: {e:?}");
@@ -654,6 +659,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
Subcmd::Ping => {
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
Some(blockchain_config.endpoint),
@@ -696,6 +702,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
}
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
None,
@@ -927,6 +934,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
let tx = parse_tx_from_stdin().await?;
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
None,
@@ -962,6 +970,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
let coin = Coin::from(elem);
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
None,
@@ -979,6 +988,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
Subcmd::Transfer { amount, token, recipient, spend_hook, user_data, half_split } => {
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
Some(blockchain_config.endpoint),
@@ -1059,6 +1069,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
Subcmd::Otc { command } => match command {
OtcSubcmd::Init { value_pair, token_pair } => {
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
Some(blockchain_config.endpoint),
@@ -1092,6 +1103,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
let partial: PartialSwapData = deserialize_async(&bytes).await?;
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
Some(blockchain_config.endpoint),
@@ -1120,6 +1132,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
};
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
None,
@@ -1139,6 +1152,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
let mut tx = parse_tx_from_stdin().await?;
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
None,
@@ -1191,6 +1205,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
let approval_ratio_quot = (approval_ratio * approval_ratio_base as f64) as u64;
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
None,
@@ -1256,6 +1271,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
let params = DaoParams::from_toml_str(&buf)?;
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
None,
@@ -1277,6 +1293,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
let params = DaoParams::from_toml_str(&buf)?;
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
None,
@@ -1294,6 +1311,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
DaoSubcmd::List { name } => {
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
None,
@@ -1311,6 +1329,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
DaoSubcmd::Balance { name } => {
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
None,
@@ -1362,6 +1381,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
DaoSubcmd::Mint { name } => {
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
Some(blockchain_config.endpoint),
@@ -1391,6 +1411,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
user_data,
} => {
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
Some(blockchain_config.endpoint),
@@ -1472,6 +1493,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
DaoSubcmd::ProposeGeneric { name, duration, user_data } => {
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
Some(blockchain_config.endpoint),
@@ -1516,6 +1538,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
DaoSubcmd::Proposals { name } => {
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
None,
@@ -1542,6 +1565,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
};
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
Some(blockchain_config.endpoint),
@@ -1749,6 +1773,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
let encrypted_proposal: AeadEncryptedNote = deserialize_async(&bytes).await?;
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
None,
@@ -1815,6 +1840,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
};
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
Some(blockchain_config.endpoint),
@@ -1844,6 +1870,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
};
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
Some(blockchain_config.endpoint),
@@ -1903,6 +1930,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
let mut tx = parse_tx_from_stdin().await?;
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
Some(blockchain_config.endpoint),
@@ -1932,6 +1960,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
let tx = parse_tx_from_stdin().await?;
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
Some(blockchain_config.endpoint),
@@ -1965,6 +1994,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
Subcmd::Subscribe => {
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
Some(blockchain_config.endpoint.clone()),
@@ -1983,6 +2013,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
Subcmd::Scan { reset } => {
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
Some(blockchain_config.endpoint),
@@ -2012,6 +2043,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
let tx_hash = TransactionHash(*blake3::Hash::from_hex(&tx_hash)?.as_bytes());
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
Some(blockchain_config.endpoint),
@@ -2053,6 +2085,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
let tx = parse_tx_from_stdin().await?;
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
Some(blockchain_config.endpoint),
@@ -2077,6 +2110,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
ExplorerSubcmd::TxsHistory { tx_hash, encode } => {
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
None,
@@ -2127,6 +2161,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
ExplorerSubcmd::ClearReverted => {
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
None,
@@ -2145,6 +2180,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
ExplorerSubcmd::ScannedBlocks { height } => {
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
None,
@@ -2210,6 +2246,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
};
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
None,
@@ -2238,6 +2275,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
};
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
None,
@@ -2266,6 +2304,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
AliasSubcmd::Remove { alias } => {
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
None,
@@ -2301,6 +2340,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
};
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
None,
@@ -2316,6 +2356,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
TokenSubcmd::GenerateMint => {
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
None,
@@ -2333,6 +2374,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
TokenSubcmd::List => {
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
None,
@@ -2379,6 +2421,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
TokenSubcmd::Mint { token, amount, recipient, spend_hook, user_data } => {
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
Some(blockchain_config.endpoint),
@@ -2456,6 +2499,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
TokenSubcmd::Freeze { token } => {
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
Some(blockchain_config.endpoint),
@@ -2488,6 +2532,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
Subcmd::Contract { command } => match command {
ContractSubcmd::GenerateDeploy => {
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
None,
@@ -2506,6 +2551,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
ContractSubcmd::List => {
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
None,
@@ -2538,6 +2584,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
let deploy_ix = smol::fs::read(expand_path(&deploy_ix)?).await?;
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
Some(blockchain_config.endpoint),
@@ -2566,6 +2613,7 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
ContractSubcmd::Lock { deploy_auth } => {
let drk = new_wallet(
blockchain_config.cache_path,
blockchain_config.wallet_path,
blockchain_config.wallet_pass,
Some(blockchain_config.endpoint),

View File

@@ -11,6 +11,9 @@ network = "localnet"
# Localnet blockchain network configuration
[network_config."localnet"]
# Path to blockchain cache database
cache_path = "drk/cache"
# Path to wallet database
wallet_path = "drk/wallet.db"