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
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:
@@ -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),
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
Reference in New Issue
Block a user