Skip to content
Open
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
2 changes: 1 addition & 1 deletion rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[toolchain]
channel = "1.75.0"
channel = "1.88.0"
components = [
"cargo",
"clippy",
Expand Down
10 changes: 9 additions & 1 deletion src/electrum/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,14 @@ impl Connection {
// let _historical_mode =
// bool_from_value_or(params.get(2), "historical", false).unwrap_or(false);

// Parse optional dust_limit parameter
let dust_limit: Option<u64> = params.get(1)
.map(|v| v.as_u64())
.flatten();

// Parse optional exclude_spent parameter
let filter_spent: bool = bool_from_value_or(params.get(2), "filter_spent", false)?;

let sp_begin_height = self.query.sp_begin_height();
// let last_header_entry = self.query.chain().best_header();

Expand All @@ -323,7 +331,7 @@ impl Connection {
height
};

let tweaks = self.query.block_tweaks(scan_height);
let tweaks = self.query.block_tweaks_with_filters(scan_height, dust_limit, filter_spent)?;
Ok(json!(tweaks))
}

Expand Down
8 changes: 8 additions & 0 deletions src/new_index/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,14 @@ impl Query {
.get_block_tweaks(&self.chain.hash_by_height(height as usize).unwrap())
}

pub fn block_tweaks_with_filters(&self, height: u32, dust_limit: Option<u64>, filter_spent: bool) -> Result<Vec<String>> {
let block_hash = self.chain
.hash_by_height(height as usize)
.chain_err(|| format!("block not found at height {}", height))?;
// Note: Parameter name was changed to filter_spent in schema.rs
Ok(self.chain.get_block_tweaks_with_filters(&block_hash, dust_limit, filter_spent))
}

pub fn tweaks_iter_scan_reverse(&self, height: u32) -> ReverseScanIterator {
self.chain.tweaks_iter_scan_reverse(height)
}
Expand Down
63 changes: 60 additions & 3 deletions src/new_index/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,7 @@ impl Indexer {
let amount = (txo.value as Amount).to_sat();
#[allow(deprecated)]
if txo.script_pubkey.is_v1_p2tr()
&& amount >= self.iconfig.sp_min_dust.unwrap_or(1_000) as u64
&& amount >= self.iconfig.sp_min_dust.unwrap_or(0) as u64
{
output_pubkeys.push(VoutData {
vout: txo_index,
Expand Down Expand Up @@ -634,8 +634,8 @@ impl Indexer {
let pubkeys_ref: Vec<_> = pubkeys.iter().collect();
if !pubkeys_ref.is_empty() {
if let Some(tweak) = calculate_tweak_data(&pubkeys_ref, &outpoints).ok() {
// persist tweak index:
// K{blockhash}{txid} → {tweak}{serialized-vout-data}
// persist detailed tweak index:
// K{blockheight}{txid} → {tweak}{serialized-vout-data}
rows.push(
TweakTxRow::new(
blockheight,
Expand All @@ -647,6 +647,7 @@ impl Indexer {
)
.into_row(),
);

tweaks.push(tweak.serialize().to_vec());
}
}
Expand Down Expand Up @@ -1137,8 +1138,64 @@ impl ChainQuery {
}

pub fn get_block_tweaks(&self, hash: &BlockHash) -> Vec<String> {
self.get_block_tweaks_with_filters(hash, None, false)
}

pub fn get_block_tweaks_with_filters(&self, hash: &BlockHash, min_dust: Option<u64>, filter_spent: bool) -> Vec<String> {
let _timer = self.start_timer("get_block_tweaks");

// If no filtering needed, use the fast path (existing behavior)
if (min_dust.is_none() || min_dust == Some(0)) && !filter_spent {
return self.get_block_tweaks_fast_path(hash);
}

// Filtering path: scan TweakTxRow entries for this block
let block_height = self.height_by_hash(hash);
if block_height.is_none() {
return vec![];
}
let block_height = block_height.unwrap() as u32;

let mut filtered_tweaks = Vec::new();
let prefix = TweakTxRow::prefix_blockheight(block_height);
let tweak_iter = self.store.tweak_db.iter_scan(&prefix)
.map(TweakTxRow::from_row)
.take_while(|row| row.key.blockheight == block_height);

for tweak_row in tweak_iter {
let tweak_data = tweak_row.get_tweak_data();

// Apply dust filter if specified
if let Some(min_dust_value) = min_dust {
if !tweak_data.vout_data.iter().any(|vout| vout.amount >= min_dust_value) {
continue; // Skip this tweak - no outputs above dust limit
}
}

// Apply spent filter if specified
if filter_spent {
let has_unspent_output = tweak_data.vout_data.iter().any(|vout| {
let outpoint = OutPoint {
txid: tweak_row.key.txid,
vout: vout.vout as u32,
};
// On-demand spend lookup - if lookup_spend returns None, the output is unspent
self.lookup_spend(&outpoint).is_none()
});

if !has_unspent_output {
continue; // Skip this tweak - all outputs are spent
}
}

filtered_tweaks.push(tweak_data.tweak);
}

filtered_tweaks
}

// Fast path for backward compatibility
fn get_block_tweaks_fast_path(&self, hash: &BlockHash) -> Vec<String> {
let tweaks: Vec<Vec<u8>> = self
.store
.tweak_db
Expand Down