From 6205994aa372b33dcf0a5428abe6fe7616220c04 Mon Sep 17 00:00:00 2001 From: Blake Date: Mon, 20 Apr 2026 21:17:21 +0800 Subject: [PATCH 1/3] Select the largest UTXO for bank address in tests --- crates/bitvm2-ga/src/tests.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/crates/bitvm2-ga/src/tests.rs b/crates/bitvm2-ga/src/tests.rs index 4a254c18..77991eae 100644 --- a/crates/bitvm2-ga/src/tests.rs +++ b/crates/bitvm2-ga/src/tests.rs @@ -1449,11 +1449,13 @@ mod tests { let esplora = get_esplora_client().await; let bank_address = node_p2wsh_address(network, &bank_keypair().public_key().into()); let utxos = esplora.get_address_utxo(bank_address.clone()).await.unwrap(); - let utxo = if utxos.is_empty() { - panic!("No UTXOs found for bank address"); - } else { - utxos[0].clone() - }; + // select the largest amount of utxo + let utxo = utxos + .into_iter() + .max_by_key(|utxo| utxo.value) + .expect("No utxo found for bank_address") + .clone(); + let msg = b"test OP_RETURN with more than 80 bytes.\n\"A purely peer-to-peer version of electronic cash would allow online payments to be sent directly from one party to another without going through a financial institution. Digital signatures provide part of the solution, but the main benefits are lost if a trusted third party is still required to prevent double-spending.We propose a solution to the double-spending problem using a peer-to-peer network.The network timestamps transactions by hashing them into an ongoing chain of hash-based proof-of-work, forming a record that cannot be changed without redoing the proof-of-work. The longest chain not only serves as proof of the sequence of events witnessed, but proof that it came from the largest pool of CPU power. As long as a majority of CPU power is controlled by nodes that are not cooperating to attack the network, they'll generate the longest chain and outpace attackers. The network itself requires minimal structure. Messages are broadcast on a best effort basis, and nodes can leave and rejoin the network at will, accepting the longest proof-of-work chain as proof of what happened while they were gone.\""; // let msg = b"short OP_RETURN message"; let opreturn_script = script! { From ca8ff7867e905086f52da9b3fef4923e52682dc5 Mon Sep 17 00:00:00 2001 From: Blake Date: Mon, 20 Apr 2026 23:01:57 +0800 Subject: [PATCH 2/3] Remove dynamic peg_btc_address retrieval from the event watcher scheduled task. --- crates/client/src/graphs/graph_query.rs | 13 ++++-- node/src/main.rs | 5 ++- node/src/scheduled_tasks/event_watch_task.rs | 46 ++++++++++---------- 3 files changed, 35 insertions(+), 29 deletions(-) diff --git a/crates/client/src/graphs/graph_query.rs b/crates/client/src/graphs/graph_query.rs index 0f9d8bde..8b11b810 100644 --- a/crates/client/src/graphs/graph_query.rs +++ b/crates/client/src/graphs/graph_query.rs @@ -14,24 +14,31 @@ pub struct TheGraphConfig { pub event_entities: Vec, } +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SwapConfig { + #[serde(flatten)] + pub graph_config: TheGraphConfig, + pub peg_btc_address: Address, +} + #[derive(Debug, Clone, Serialize, Deserialize, Display)] pub enum WatchEventConfig { Gateway(TheGraphConfig), - Swap(TheGraphConfig), + Swap(SwapConfig), } impl WatchEventConfig { pub fn get_watch_events_len(&self) -> usize { match self { WatchEventConfig::Gateway(config) => config.event_entities.len(), - WatchEventConfig::Swap(config) => config.event_entities.len(), + WatchEventConfig::Swap(config) => config.graph_config.event_entities.len(), } } pub fn get_watch_contract(&self) -> Address { match self { WatchEventConfig::Gateway(config) => config.address, - WatchEventConfig::Swap(config) => config.address, + WatchEventConfig::Swap(config) => config.graph_config.address, } } pub fn get_watch_contract_type(&self) -> WatchContractType { diff --git a/node/src/main.rs b/node/src/main.rs index a360ba8f..9945701f 100644 --- a/node/src/main.rs +++ b/node/src/main.rs @@ -204,8 +204,8 @@ async fn main() -> Result<(), Box> { // if actor == Actor::Committee || actor == Actor::Operator { let cancel_token_clone = cancellation_token.clone(); task_handles.push(tokio::spawn(async move { - let goat_client = - Arc::new(GOATClient::new(goat_config_from_env().await, get_goat_network())); + let goat_init_config = goat_config_from_env().await; + let goat_client = Arc::new(GOATClient::new(goat_init_config.clone(), get_goat_network())); let btc_client = Arc::new(BTCClient::new(get_network(), get_btc_url_from_env().as_deref())); match run_watch_event_task( actor_clone2, @@ -214,6 +214,7 @@ async fn main() -> Result<(), Box> { goat_client, 5, cancel_token_clone, + goat_init_config, ) .await { diff --git a/node/src/scheduled_tasks/event_watch_task.rs b/node/src/scheduled_tasks/event_watch_task.rs index 484106c4..c0ed4e33 100644 --- a/node/src/scheduled_tasks/event_watch_task.rs +++ b/node/src/scheduled_tasks/event_watch_task.rs @@ -22,15 +22,15 @@ use bitcoin::{Address, Amount, OutPoint, Txid}; use bitvm2_lib::actors::Actor; use bitvm2_lib::types::UserInfo; use client::btc_chain::BTCClient; -use client::goat_chain::GOATClient; +use client::goat_chain::{GOATClient, GoatInitConfig}; use client::graphs::GraphQueryClient; use client::graphs::graph_query::{ BlockRange, BridgeInEvent, BridgeInRequestEvent, CancelWithdrawEvent, CommitteeResponseEvent, GatewayEventEntity, InitWithdrawEvent, PostGraphDataEvent, ProceedWithdrawEvent, - SwapClaimEvent, SwapEventEntity, SwapInitializeEvent, SwapRefundEvent, TheGraphConfig, - UserGraphWithdrawEvent, WatchContractType, WatchEventConfig, WithdrawDisprovedEvent, - WithdrawHappyEvent, WithdrawPathsEvent, WithdrawUnhappyEvent, get_bridge_out_events_query, - get_gateway_events_query, + SwapClaimEvent, SwapConfig, SwapEventEntity, SwapInitializeEvent, SwapRefundEvent, + TheGraphConfig, UserGraphWithdrawEvent, WatchContractType, WatchEventConfig, + WithdrawDisprovedEvent, WithdrawHappyEvent, WithdrawPathsEvent, WithdrawUnhappyEvent, + get_bridge_out_events_query, get_gateway_events_query, }; use goat::transactions::base::Input; use secp256k1::XOnlyPublicKey; @@ -81,11 +81,12 @@ pub async fn fetch_and_handle_block_range_events<'a>( goat_client.clone(), client, storage_processor, - &config.address, - &config.the_graph_url, - &config.event_entities, + &config.graph_config.address, + &config.graph_config.the_graph_url, + &config.graph_config.event_entities, from_height, to_height, + config.peg_btc_address, ) .await?; } @@ -220,8 +221,8 @@ pub async fn fetch_and_handle_bridge_out_events<'a>( event_entities: &[SwapEventEntity], from_height: i64, to_height: i64, + gateway_peg_btc_address: EvmAddress, ) -> anyhow::Result<()> { - let gateway_peg_btc_address = get_gateway_peg_btc_address().await?; let query_res = client .execute_query( graph_url, @@ -846,13 +847,6 @@ async fn handle_swap_refund_events<'a>( Ok(()) } -async fn get_gateway_peg_btc_address() -> anyhow::Result { - env::goat_config_from_env() - .await - .peg_btc_address - .ok_or(anyhow::anyhow!("failed to get gateway pegBTC contract address")) -} - async fn is_gateway_peg_btc_swap_instance( storage_processor: &mut StorageProcessor<'_>, instance_id: &Uuid, @@ -1176,6 +1170,7 @@ pub async fn run_watch_event_task( goat_client: Arc, interval: u64, cancellation_token: CancellationToken, + goat_init_config: GoatInitConfig, ) -> anyhow::Result { let gateway_contract: EvmAddress = get_goat_address_from_env(ENV_GOAT_GATEWAY_CONTRACT_ADDRESS) .ok_or(anyhow::anyhow!("need to set gateway contract address"))?; @@ -1200,14 +1195,17 @@ pub async fn run_watch_event_task( GatewayEventEntity::PostGraphDatas, ], }), - WatchEventConfig::Swap(TheGraphConfig { - address: swap_contract, - the_graph_url: get_goat_swap_the_graph_urls_from_env(), - event_entities: vec![ - SwapEventEntity::Initializes, - SwapEventEntity::Claims, - SwapEventEntity::Refunds, - ], + WatchEventConfig::Swap(SwapConfig { + graph_config: TheGraphConfig { + address: swap_contract, + the_graph_url: get_goat_swap_the_graph_urls_from_env(), + event_entities: vec![ + SwapEventEntity::Initializes, + SwapEventEntity::Claims, + SwapEventEntity::Refunds, + ], + }, + peg_btc_address: goat_init_config.peg_btc_address.unwrap(), }), ], ), From e0a96672cac112c8c23212084dcd56dba2305b57 Mon Sep 17 00:00:00 2001 From: Blake Date: Fri, 24 Apr 2026 16:12:44 +0800 Subject: [PATCH 3/3] chores --- crates/bitvm2-ga/src/tests.rs | 3 +-- node/src/scheduled_tasks/event_watch_task.rs | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/bitvm2-ga/src/tests.rs b/crates/bitvm2-ga/src/tests.rs index 77991eae..0d5867a8 100644 --- a/crates/bitvm2-ga/src/tests.rs +++ b/crates/bitvm2-ga/src/tests.rs @@ -1453,8 +1453,7 @@ mod tests { let utxo = utxos .into_iter() .max_by_key(|utxo| utxo.value) - .expect("No utxo found for bank_address") - .clone(); + .expect("No utxo found for bank_address"); let msg = b"test OP_RETURN with more than 80 bytes.\n\"A purely peer-to-peer version of electronic cash would allow online payments to be sent directly from one party to another without going through a financial institution. Digital signatures provide part of the solution, but the main benefits are lost if a trusted third party is still required to prevent double-spending.We propose a solution to the double-spending problem using a peer-to-peer network.The network timestamps transactions by hashing them into an ongoing chain of hash-based proof-of-work, forming a record that cannot be changed without redoing the proof-of-work. The longest chain not only serves as proof of the sequence of events witnessed, but proof that it came from the largest pool of CPU power. As long as a majority of CPU power is controlled by nodes that are not cooperating to attack the network, they'll generate the longest chain and outpace attackers. The network itself requires minimal structure. Messages are broadcast on a best effort basis, and nodes can leave and rejoin the network at will, accepting the longest proof-of-work chain as proof of what happened while they were gone.\""; // let msg = b"short OP_RETURN message"; diff --git a/node/src/scheduled_tasks/event_watch_task.rs b/node/src/scheduled_tasks/event_watch_task.rs index c0ed4e33..ed58abe7 100644 --- a/node/src/scheduled_tasks/event_watch_task.rs +++ b/node/src/scheduled_tasks/event_watch_task.rs @@ -1205,7 +1205,9 @@ pub async fn run_watch_event_task( SwapEventEntity::Refunds, ], }, - peg_btc_address: goat_init_config.peg_btc_address.unwrap(), + peg_btc_address: goat_init_config.peg_btc_address.expect( + "peg_btc_address must be set (requires GOAT_GATEWAY_CONTRACT_ADDRESS)", + ), }), ], ),