From ef0fcb8ee9f01d07b09f9b606bcc71f91f674e50 Mon Sep 17 00:00:00 2001 From: Blake <0xblake.sg@gmail.com> Date: Fri, 10 Jul 2026 13:03:34 +0800 Subject: [PATCH] Fix: handle empty watchtower challenge txids --- circuits/operator-proof/host/src/lib.rs | 6 ++++- proof-builder-rpc/src/task/mod.rs | 32 +++++++++++++------------ 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/circuits/operator-proof/host/src/lib.rs b/circuits/operator-proof/host/src/lib.rs index 9c006875..73231f63 100644 --- a/circuits/operator-proof/host/src/lib.rs +++ b/circuits/operator-proof/host/src/lib.rs @@ -94,11 +94,15 @@ fn parse_indexed_watchtower_inputs( watchtower_challenge_txids: &str, watchtower_public_keys: &str, ) -> anyhow::Result<(Vec<(u16, Txid, PublicKey)>, Vec<[u8; 32]>)> { - let txids = watchtower_challenge_txids.split(',').collect::>(); let public_keys = watchtower_public_keys .split(',') .map(PublicKey::from_str) .collect::, _>>()?; + let txids = if watchtower_challenge_txids.trim().is_empty() { + vec![""; public_keys.len()] + } else { + watchtower_challenge_txids.split(',').collect::>() + }; anyhow::ensure!( txids.len() == public_keys.len(), "watchtower challenge txids and public keys must have equal lengths" diff --git a/proof-builder-rpc/src/task/mod.rs b/proof-builder-rpc/src/task/mod.rs index 949c9d49..a6f795f3 100644 --- a/proof-builder-rpc/src/task/mod.rs +++ b/proof-builder-rpc/src/task/mod.rs @@ -378,16 +378,13 @@ pub(crate) async fn fetch_on_demand_task( } } - // double check the committed block height is larger than all the watchtower challenge txns'. - match operator_committed_blockhash { - Some(ref hash) => match btc_client.get_block_by_hash(&BlockHash::from_str(hash)?).await { - Ok(Some(block)) => { - if block.bip34_block_height()? != largest_btc_block_height as u64 { - anyhow::bail!( - "Operator committed block {hash} is not confirmed yet, wait for the next round" - ); - } - } + let btc_proof_height = if is_watchtower { + largest_btc_block_height + } else { + let hash = operator_committed_blockhash.as_ref().unwrap(); + let committed_height = match btc_client.get_block_by_hash(&BlockHash::from_str(hash)?).await + { + Ok(Some(block)) => block.bip34_block_height()? as u32, Ok(None) => { tracing::warn!( "Operator committed block hash {hash} is not found in BTC, it might be mempool tx, wait for the next round" @@ -400,13 +397,18 @@ pub(crate) async fn fetch_on_demand_task( ); return Ok(None); } - }, - None => {} // skip for watchtowers + }; + if committed_height < largest_btc_block_height { + anyhow::bail!( + "operator committed block height {committed_height} is lower than challenge tx height {largest_btc_block_height}" + ); + } + committed_height }; let header_chain_input_proof = match storage_processor .find_long_running_task_proof_including_block_number( - largest_btc_block_height as i64, + btc_proof_height as i64, HeaderChainProofBuilder::name(), ) .await? @@ -415,7 +417,7 @@ pub(crate) async fn fetch_on_demand_task( None => { tracing::warn!( "Header chain proof is not ready for block: {}, proof not ready", - largest_btc_block_height + btc_proof_height ); return Ok(None); } @@ -466,7 +468,7 @@ pub(crate) async fn fetch_on_demand_task( // commit chain let commit_chain_input_proof = match storage_processor .find_long_running_task_proof_including_block_number( - largest_btc_block_height as i64, + btc_proof_height as i64, CommitChainProofBuilder::name(), ) .await?