Crash fixes, reorg handling, and sync performance improvements
Some checks failed
Rust / Build on macOS-latest (push) Has been cancelled
Rust / Build on ubuntu-16.04 (push) Has been cancelled
Rust / Build on windows-latest (push) Has been cancelled
Rust / Linux ARMv7 (push) Has been cancelled
Rust / Linux ARM64 (push) Has been cancelled
Rust / Build on ubuntu-latest (push) Has been cancelled

- Fix FFI panics with catch_unwind and safe CString construction
- Handle poisoned mutex/RwLock after prior panics instead of crashing
- Fix empty block list panics in clear_blocks and invalidate_block
- Reuse Tokio runtime across block fetch batches to reduce overhead
- Add fetch_blocks_with_runtime for caller-managed runtime lifecycle
- Update branding, dependencies, and checkpoints for DragonX
This commit is contained in:
2026-03-21 03:55:18 -05:00
parent 505fac6b6e
commit a6a80dc224
34 changed files with 14509 additions and 14481 deletions

View File

@@ -155,15 +155,12 @@ where F : Fn(&[u8], u64) {
pub fn fetch_blocks<F : 'static + std::marker::Send>(uri: &http::Uri, start_height: u64, end_height: u64, no_cert: bool, pool: ThreadPool, c: F) -> Result<(), String> pub fn fetch_blocks<F : 'static + std::marker::Send>(uri: &http::Uri, start_height: u64, end_height: u64, no_cert: bool, pool: ThreadPool, c: F) -> Result<(), String>
where F : Fn(&[u8], u64) { where F : Fn(&[u8], u64) {
let mut rt = tokio::runtime::Runtime::new().map_err(|e| format!("Error creating runtime {:?}", e))?;
fetch_blocks_with_runtime(&mut rt, uri, start_height, end_height, no_cert, pool, c)
}
let mut rt = match tokio::runtime::Runtime::new() { pub fn fetch_blocks_with_runtime<F : 'static + std::marker::Send>(rt: &mut tokio::runtime::Runtime, uri: &http::Uri, start_height: u64, end_height: u64, no_cert: bool, pool: ThreadPool, c: F) -> Result<(), String>
Ok(r) => r, where F : Fn(&[u8], u64) {
Err(e) => {
let es = format!("Error creating runtime {:?}", e);
error!("{}", es);
return Err(es);
}
};
match rt.block_on(get_block_range(uri, start_height, end_height, no_cert, pool, c)) { match rt.block_on(get_block_range(uri, start_height, end_height, no_cert, pool, c)) {
Ok(o) => Ok(o), Ok(o) => Ok(o),

View File

@@ -1323,6 +1323,10 @@ pub fn start_mempool_monitor(lc: Arc<LightClient>) -> Result<(), String> {
// Create a new threadpool (upto 8, atleast 2 threads) to scan with // Create a new threadpool (upto 8, atleast 2 threads) to scan with
let pool = ThreadPool::new(max(2, min(8, num_cpus::get()))); let pool = ThreadPool::new(max(2, min(8, num_cpus::get())));
// Create a single Tokio runtime for all block fetches to avoid per-batch overhead
let mut rt = tokio::runtime::Runtime::new()
.map_err(|e| format!("Error creating runtime: {:?}", e))?;
// Fetch CompactBlocks in increments // Fetch CompactBlocks in increments
let mut pass = 0; let mut pass = 0;
loop { loop {
@@ -1359,7 +1363,7 @@ pub fn start_mempool_monitor(lc: Arc<LightClient>) -> Result<(), String> {
let last_invalid_height = Arc::new(AtomicI32::new(0)); let last_invalid_height = Arc::new(AtomicI32::new(0));
let last_invalid_height_inner = last_invalid_height.clone(); let last_invalid_height_inner = last_invalid_height.clone();
let tpool = pool.clone(); let tpool = pool.clone();
fetch_blocks(&self.get_server_uri(), start_height, end_height, self.config.no_cert_verification, pool.clone(), fetch_blocks_with_runtime(&mut rt, &self.get_server_uri(), start_height, end_height, self.config.no_cert_verification, pool.clone(),
move |encoded_block: &[u8], height: u64| { move |encoded_block: &[u8], height: u64| {
// Process the block only if there were no previous errors // Process the block only if there were no previous errors
if last_invalid_height_inner.load(Ordering::SeqCst) > 0 { if last_invalid_height_inner.load(Ordering::SeqCst) > 0 {

View File

@@ -746,14 +746,29 @@ impl LightWallet {
/// After this, the wallet's initial state will need to be set /// After this, the wallet's initial state will need to be set
/// and the wallet will need to be rescanned /// and the wallet will need to be rescanned
pub fn clear_blocks(&self) { pub fn clear_blocks(&self) {
self.blocks.write().unwrap().clear(); match self.blocks.write() {
self.txs.write().unwrap().clear(); Ok(mut b) => b.clear(),
self.mempool_txs.write().unwrap().clear(); Err(p) => p.into_inner().clear(),
self.incoming_mempool_txs.write().unwrap().clear(); };
match self.txs.write() {
Ok(mut t) => t.clear(),
Err(p) => p.into_inner().clear(),
};
match self.mempool_txs.write() {
Ok(mut m) => m.clear(),
Err(p) => p.into_inner().clear(),
};
match self.incoming_mempool_txs.write() {
Ok(mut m) => m.clear(),
Err(p) => p.into_inner().clear(),
};
} }
pub fn set_initial_block(&self, height: i32, hash: &str, sapling_tree: &str) -> bool { pub fn set_initial_block(&self, height: i32, hash: &str, sapling_tree: &str) -> bool {
let mut blocks = self.blocks.write().unwrap(); let mut blocks = match self.blocks.write() {
Ok(b) => b,
Err(p) => p.into_inner(),
};
if !blocks.is_empty() { if !blocks.is_empty() {
return false; return false;
} }
@@ -1677,9 +1692,15 @@ pub fn scan_full_mempool_tx(&self, tx: &Transaction, height: i32, _datetime: u64
// First remove the blocks // First remove the blocks
{ {
let mut blks = self.blocks.write().unwrap(); let mut blks = match self.blocks.write() {
Ok(b) => b,
Err(p) => p.into_inner(),
};
while blks.last().unwrap().height >= at_height { while let Some(last) = blks.last() {
if last.height < at_height {
break;
}
blks.pop(); blks.pop();
num_invalidated += 1; num_invalidated += 1;
} }
@@ -1687,7 +1708,10 @@ pub fn scan_full_mempool_tx(&self, tx: &Transaction, height: i32, _datetime: u64
// Next, remove entire transactions // Next, remove entire transactions
{ {
let mut txs = self.txs.write().unwrap(); let mut txs = match self.txs.write() {
Ok(t) => t,
Err(p) => p.into_inner(),
};
let txids_to_remove = txs.values() let txids_to_remove = txs.values()
.filter_map(|wtx| if wtx.block >= at_height {Some(wtx.txid.clone())} else {None}) .filter_map(|wtx| if wtx.block >= at_height {Some(wtx.txid.clone())} else {None})
.collect::<HashSet<TxId>>(); .collect::<HashSet<TxId>>();
@@ -1716,7 +1740,10 @@ pub fn scan_full_mempool_tx(&self, tx: &Transaction, height: i32, _datetime: u64
// Of the notes that still remain, unroll the witness. // Of the notes that still remain, unroll the witness.
// Remove `num_invalidated` items from the witness // Remove `num_invalidated` items from the witness
{ {
let mut txs = self.txs.write().unwrap(); let mut txs = match self.txs.write() {
Ok(t) => t,
Err(p) => p.into_inner(),
};
// Trim all witnesses for the invalidated blocks // Trim all witnesses for the invalidated blocks
for tx in txs.values_mut() { for tx in txs.values_mut() {