Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
8b549f7
feat: sp tweak index
Jul 18, 2024
d537590
fix: db, rows, scan method
Jul 23, 2024
4dfee71
changes
Jul 23, 2024
76a0493
fix: scanning, add db read range
Jul 31, 2024
2bed6c2
fix: warnings & errors
Jul 31, 2024
c27f7fb
feat: regex sanity check, fix build warning
Aug 2, 2024
d6d60bf
fix: blocks missing
Aug 7, 2024
fd2a088
fix: new blocks update rescanning all headers
Aug 8, 2024
f4e46c2
feat: change tweak db to use block height instead of hash, perf impro…
Aug 14, 2024
f003a0e
feat: cached tip height for tweak spent querying
Aug 20, 2024
32daa81
Merge remote-tracking branch 'origin/new-index' into cake-update-v1
Aug 20, 2024
0a0bea5
chore: logs
Aug 20, 2024
dd808a4
fix: make initial sp height pub
Aug 20, 2024
3ec687b
fix: scan_height override
Aug 20, 2024
15023af
refactor: fix cargo warns, strip unnedeed code & deps
Aug 22, 2024
db38605
feat: config options for SP and more debug options
Aug 22, 2024
df2db35
Merge remote-tracking branch 'origin/new-index' into cake-update-v1
Aug 22, 2024
2064fb3
refactor: closer to upstream
Aug 22, 2024
ff163f0
refactor: more undoings
Aug 22, 2024
49bbc6a
refactor: more undoings
Aug 22, 2024
ca131be
perf: faster sync attempt
Aug 22, 2024
24845d4
feat: fixes scanning
Aug 28, 2024
f88b5f7
perf: remove daemon dependency from sp tweak sync
Sep 4, 2024
425acd6
fix: 3 blocks left scanning
Sep 4, 2024
8884618
fix: scan jumping to the end
Sep 5, 2024
f393307
fix: sync from 0
Sep 12, 2024
44bb2d5
feat: limit count
Sep 13, 2024
cf9e03b
perf: move query check to every row height not every tweak vout
Sep 13, 2024
9dffb84
Merge new-index branch into cake-update-v1
KarimMokhtar Feb 13, 2026
010803a
fix merge conflicts
KarimMokhtar Feb 14, 2026
2df0e44
solve merge conflicts
KarimMokhtar Feb 14, 2026
5d2e53b
use hex for string
KarimMokhtar Feb 15, 2026
ad16c4c
fix hex string usage
KarimMokhtar Feb 15, 2026
fb8d6e8
update hex version
KarimMokhtar Feb 15, 2026
abcbbd2
remove unused code
KarimMokhtar Feb 15, 2026
8ee5196
Implement parallel indexing of blocks with enhanced transaction histo…
KarimMokhtar Feb 24, 2026
c63d41f
Enhance history database write functionality by renaming method to `w…
KarimMokhtar Feb 24, 2026
45049e7
Refactor update method in Indexer to streamline reorg handling and tr…
KarimMokhtar Feb 24, 2026
54a074b
fix tests run
KarimMokhtar Feb 24, 2026
9f97dd4
Refactor test_indexing_after_new_block to simplify store access by us…
KarimMokhtar Feb 24, 2026
5c027ae
Add indexed_blockhashes to Store and update indexing logic in Indexer
KarimMokhtar Feb 24, 2026
047a1c5
Refactor amount and witness handling in Indexer for conditional suppo…
KarimMokhtar Feb 25, 2026
396f274
Update import statements in schema.rs to include ScriptMethods for en…
KarimMokhtar Feb 25, 2026
38b118a
Enhance test_indexing_after_new_block to ensure indexed_headers are p…
KarimMokhtar Feb 25, 2026
02bed2b
Improve test_indexing_after_new_block by adding an assertion to verif…
KarimMokhtar Feb 25, 2026
c7d0da2
Update flake.nix to build dependencies for all features, including si…
KarimMokhtar Feb 25, 2026
aae16bf
temporary remove test_indexing_sync_and_state
KarimMokhtar Feb 25, 2026
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
21 changes: 21 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ default-run = "electrs"
[features]
liquid = ["elements"]
electrum-discovery = ["electrum-client"]
silent-payments = []
bench = []
otlp-tracing = [
"tracing",
Expand All @@ -40,6 +41,7 @@ dirs = "5.0.1"
elements = { version = "0.25", features = ["serde"], optional = true }
error-chain = "0.12.4"
glob = "0.3"
hex = "0.4"
itertools = "0.12"
lazy_static = "1.3.0"
libc = "0.2.81"
Expand All @@ -62,6 +64,7 @@ tiny_http = "0.12.0"
url = "2.2.0"
hyper = "0.14"
hyperlocal = "0.8"
silentpayments = { git = "https://github.com/cygnet3/rust-silentpayments", branch = "master" }
# close to same tokio version as dependent by hyper v0.14 and hyperlocal 0.8 -- things can go awry if they mismatch
tokio = { version = "1", features = ["sync", "macros", "rt-multi-thread", "rt"] }
opentelemetry = { version = "0.20.0", features = ["rt-tokio"], optional = true }
Expand Down
21 changes: 19 additions & 2 deletions doc/schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ The index is stored as three RocksDB databases:

### Indexing process

The indexing is done in the two phase, where each can be done concurrently within itself.
The first phase populates the `txstore` database, the second phase populates the `history` database.
The indexing is done in three phases, where each can be done concurrently within itself.
The first phase populates the `txstore` database, the second phase populates the `history` database, and the third populates the `tweak` database.

NOTE: in order to construct the history rows for spending inputs in phase #2, we rely on having the transactions being processed at phase #1, so they can be looked up efficiently (using parallel point lookups).

After the indexing is completed, both funding and spending are indexed as independent rows under `H{scripthash}`, so that they can be queried in-order in one go.


### `txstore`

Each block results in the following new rows:
Expand Down Expand Up @@ -60,6 +61,22 @@ Each block results in the following new row:

* `"D{blockhash}" → ""` (signifies the block was indexed)

#### Silent Payments only

### `tweaks`

Each block results in the following new rows:

* `"W{blockhash}" → "{tweak1}...{tweakN}"` (list of txids included in the block)

Each transaction results in the following new rows:

* `"K{blockheight}{txid}" → "{tweak_data1}...{tweak_dataN}"` (txid -> tweak, and list of vout:amount:scripthash for each valid sp output)

Every time a block is scanned for tweaks, the following row is updated:

* `"B{blockheight}" → "{tip}"` (the blockheight scanned -> the tip of the chain during scanning, this allows to cache the last tip and avoid running spent checks for the same block multiple times, until a new block comes in, then outputs need to be checked if they were spent the next time they are scanned)

#### Elements only

Assets (re)issuances results in the following new rows (only for user-issued assets):
Expand Down
6 changes: 5 additions & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,11 @@
inherit src buildInputs nativeBuildInputs;
} // envVars;

cargoArtifacts = craneLib.buildDepsOnly commonArgs;
# Build deps for all features (including silent-payments) so vendored/cached
# crates include bech32 0.9.1 required by silentpayments.
cargoArtifacts = craneLib.buildDepsOnly (commonArgs // {
cargoExtraArgs = "--all-features";
});
bin = craneLib.buildPackage (commonArgs // {
inherit cargoArtifacts;
});
Expand Down
7 changes: 6 additions & 1 deletion src/bin/electrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ fn fetch_from(config: &Config, store: &Store) -> FetchFrom {
}

fn run_server(config: Arc<Config>, salt_rwlock: Arc<RwLock<String>>) -> Result<()> {
rayon::ThreadPoolBuilder::new()
.num_threads(16)
.thread_name(|i| format!("history-{}", i))
.build()
.unwrap();

let (block_hash_notify, block_hash_receive) = channel::bounded(1);
let signal = Waiter::start(block_hash_receive);
let metrics = Metrics::new(config.monitoring_addr);
Expand Down Expand Up @@ -95,7 +101,6 @@ fn run_server(config: Arc<Config>, salt_rwlock: Arc<RwLock<String>>) -> Result<(
&metrics,
Arc::clone(&config),
)));

while !Mempool::update(&mempool, &daemon, &tip)? {
// Mempool syncing was aborted because the chain tip moved;
// Index the new block(s) and try again.
Expand Down
45 changes: 45 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ pub struct Config {
pub electrum_announce: bool,
#[cfg(feature = "electrum-discovery")]
pub tor_proxy: Option<std::net::SocketAddr>,
pub sp_begin_height: Option<usize>,
pub sp_min_dust: Option<usize>,
pub sp_check_spends: bool,
pub skip_history: bool,
pub skip_tweaks: bool,
pub skip_mempool: bool,
}

fn str_to_socketaddr(address: &str, what: &str) -> SocketAddr {
Expand Down Expand Up @@ -256,6 +262,14 @@ impl Config {
.long("zmq-addr")
.help("Optional zmq socket address of the bitcoind daemon")
.takes_value(true),
).arg(
Arg::with_name("skip_history")
.long("skip-history")
.help("Skip history indexing"),
).arg(
Arg::with_name("skip_mempool")
.long("skip-mempool")
.help("Skip local mempool"),
);

#[cfg(unix)]
Expand Down Expand Up @@ -298,6 +312,31 @@ impl Config {
.takes_value(true),
);

#[cfg(feature = "silent-payments")]
let args = args
.arg(
Arg::with_name("sp_begin_height")
.long("sp-begin-height")
.help("Block height at which to begin scanning for silent payments")
.takes_value(true),
)
.arg(
Arg::with_name("sp_min_dust")
.long("sp-min-dust")
.help("Minimum dust value for silent payments")
.takes_value(true),
)
.arg(
Arg::with_name("sp_check_spends")
.long("sp-check-spends")
.help("Check spends of silent payments"),
)
.arg(
Arg::with_name("skip_tweaks")
.long("skip-tweaks")
.help("Skip tweaks indexing"),
);

let m = args.get_matches();

let network_name = m.value_of("network").unwrap_or("mainnet");
Expand Down Expand Up @@ -504,6 +543,12 @@ impl Config {
electrum_announce: m.is_present("electrum_announce"),
#[cfg(feature = "electrum-discovery")]
tor_proxy: m.value_of("tor_proxy").map(|s| s.parse().unwrap()),
sp_begin_height: m.value_of("sp_begin_height").map(|s| s.parse().unwrap()),
sp_min_dust: m.value_of("sp_min_dust").map(|s| s.parse().unwrap()),
sp_check_spends: m.is_present("sp_check_spends"),
skip_history: m.is_present("skip_history"),
skip_tweaks: m.is_present("skip_tweaks"),
skip_mempool: m.is_present("skip_mempool"),
};
eprintln!("{:?}", config);
config
Expand Down
5 changes: 3 additions & 2 deletions src/daemon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ fn block_from_value(value: Value) -> Result<Block> {
Ok(deserialize(&block_bytes).chain_err(|| format!("failed to parse block {}", block_hex))?)
}

fn tx_from_value(value: Value) -> Result<Transaction> {
pub fn tx_from_value(value: Value) -> Result<Transaction> {
let tx_hex = value.as_str().chain_err(|| "non-string tx")?;
let tx_bytes = Vec::from_hex(tx_hex).chain_err(|| "non-hex tx")?;
Ok(deserialize(&tx_bytes).chain_err(|| format!("failed to parse tx {}", tx_hex))?)
Expand Down Expand Up @@ -667,7 +667,8 @@ impl Daemon {
pub fn gettransaction_raw(
&self,
txid: &Txid,
blockhash: &BlockHash,
// WARN: gettransaction_raw with blockhash=None requires bitcoind with txindex=1
blockhash: Option<&BlockHash>,
verbose: bool,
) -> Result<Value> {
self.request("getrawtransaction", json!([txid, verbose, blockhash]))
Expand Down
Loading
Loading