Skip to content

Use verify_transaction_inclusion_v2 with coinbase merkle proof#32

Open
olga24912 wants to merge 15 commits into
omni-mainfrom
tx64
Open

Use verify_transaction_inclusion_v2 with coinbase merkle proof#32
olga24912 wants to merge 15 commits into
omni-mainfrom
tx64

Conversation

@olga24912
Copy link
Copy Markdown

Replace verify_transaction_inclusion with verify_transaction_inclusion_v2 across all bridge verification flows (deposit, withdraw, active UTXO management)

See Near-One/btc-light-client-contract#139

Comment thread contracts/satoshi-bridge/src/btc_light_client/deposit.rs Outdated
Comment thread contracts/satoshi-bridge/src/btc_light_client/mod.rs Outdated
Comment thread contracts/satoshi-bridge/src/btc_light_client/mod.rs Outdated
Comment thread contracts/satoshi-bridge/src/api/bridge.rs
Comment thread Cargo.lock
Comment thread contracts/satoshi-bridge/src/refund.rs
Comment thread contracts/satoshi-bridge/src/btc_light_client/mod.rs
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the Satoshi Bridge’s Bitcoin transaction verification flows to support verify_transaction_inclusion_v2, which includes coinbase merkle proof data for stronger inclusion verification. It introduces a shared TxInclusionProof input shape and wires it through deposit/withdraw/active-UTXO-management/refund verification paths, along with test and mock light-client updates.

Changes:

  • Add TxInclusionProof and new *_v2 bridge entrypoints that accept a nested proof object including coinbase proof fields.
  • Update the bridge’s BTC light client integration to call verify_transaction_inclusion_v2 when coinbase proof is provided, falling back to v1 otherwise.
  • Extend workspace tests and the mock BTC light client contract to exercise/enable the v2 verification path.

Reviewed changes

Copilot reviewed 13 out of 14 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
contracts/satoshi-bridge/src/lib.rs Introduces TxInclusionProof used by v2 APIs.
contracts/satoshi-bridge/src/btc_light_client/mod.rs Adds v2 proof args + external interface and routes calls to v2 when coinbase proof exists.
contracts/satoshi-bridge/src/api/bridge.rs Adds verify_deposit_v2, safe_verify_deposit_v2, verify_withdraw_v2, verify_active_utxo_management_v2; refactors legacy methods and updates refund finalize signature.
contracts/satoshi-bridge/src/btc_light_client/deposit.rs Refactors deposit verification into reusable entry helpers; plumbs optional coinbase proof through verification.
contracts/satoshi-bridge/src/btc_light_client/withdraw.rs Adds an internal “entry” helper to reuse logic and support v2 coinbase proof.
contracts/satoshi-bridge/src/btc_light_client/active_utxo_management.rs Adds an internal “entry” helper and keeps active UTXO management verification compatible with v2 proofs.
contracts/satoshi-bridge/src/refund.rs Switches refund verification to use TxInclusionProof and v2 inclusion verification; uses Base64VecU8 for tx bytes.
contracts/satoshi-bridge/tests/setup/context.rs Adds v2 test helpers and updates refund helper argument shape to include nested proof.
contracts/satoshi-bridge/tests/test_satoshi_bridge.rs Adds tests covering v2 deposit/safe-deposit/withdraw and a (currently non-asserting) v2 active UTXO management test.
contracts/mock-btc-light-client/src/lib.rs Adds mock implementation for verify_transaction_inclusion_v2.
contracts/satoshi-bridge/release_notes.md Notes the v2 inclusion verification addition for version 0.9.0.
contracts/satoshi-bridge/Cargo.toml Bumps satoshi-bridge version to 0.9.0.
contracts/mock-btc-light-client/Cargo.toml Bumps mock-btc-light-client version to 0.2.0.
Cargo.lock Updates locked versions for the bumped crates.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +3288 to +3296
// verify_active_utxo_management_v2 with non-existent tx_id
check!(
print "verify_active_utxo_management_v2"
context.verify_active_utxo_management_v2(
"relayer",
"non_existent_tx_id",
mock_proof()
)
);
Copy link

Copilot AI May 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test_verify_active_utxo_management_v2 doesn't assert anything: it uses check!(print ...), which only prints logs/errors and will pass even if the call fails or succeeds unexpectedly. Convert this into an actual assertion (e.g., assert the expected failure message like "BTC pending info not exist", or create a pending active UTXO management flow and assert a successful v2 verification).

Suggested change
// verify_active_utxo_management_v2 with non-existent tx_id
check!(
print "verify_active_utxo_management_v2"
context.verify_active_utxo_management_v2(
"relayer",
"non_existent_tx_id",
mock_proof()
)
);
// verify_active_utxo_management_v2 with non-existent tx_id must fail.
let result = context
.verify_active_utxo_management_v2("relayer", "non_existent_tx_id", mock_proof())
.await;
match result {
Ok(outcome) => {
let failures = outcome.receipt_failures();
assert!(
!failures.is_empty(),
"verify_active_utxo_management_v2 should fail for non-existent tx_id"
);
let failure_text = format!("{:?}", failures);
assert!(
failure_text.contains("BTC pending info not exist"),
"expected missing pending info failure, got: {failure_text}"
);
}
Err(err) => {
let err_text = format!("{err:?}");
assert!(
err_text.contains("BTC pending info not exist"),
"expected missing pending info failure, got: {err_text}"
);
}
}

Copilot uses AI. Check for mistakes.
Comment on lines 463 to 470
pub fn request_refund(
&mut self,
deposit_msg: DepositMsg,
refund_address: String,
tx_bytes: Vec<u8>,
tx_bytes: Base64VecU8,
vout: usize,
tx_block_blockhash: String,
tx_index: u64,
merkle_proof: Vec<String>,
proof: TxInclusionProof,
gas_fee: Option<U128>,
Copy link

Copilot AI May 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

request_refund signature now takes proof: TxInclusionProof, but the doc comment above still documents tx_block_blockhash, tx_index, and merkle_proof as separate parameters (and doesn't mention coinbase fields). Please update the doc comment to match the new proof argument shape.

Copilot uses AI. Check for mistakes.
Comment on lines 541 to +552
/// Verify that the refund BTC transaction has been confirmed on the Bitcoin network.
/// Cleans up the `BTCPendingInfo` after successful verification.
///
/// # Arguments
///
/// * `tx_id` - Transaction ID of the confirmed refund transaction.
/// * `tx_block_blockhash` - Block hash containing the transaction.
/// * `tx_index` - Transaction index within the block.
/// * `merkle_proof` - Merkle proof for Light Client verification.
#[trusted_relayer]
#[pause(except(roles(Role::DAO)))]
pub fn verify_refund_finalize(
&mut self,
tx_id: String,
tx_block_blockhash: String,
tx_index: u64,
merkle_proof: Vec<String>,
) -> Promise {
pub fn verify_refund_finalize(&mut self, tx_id: String, proof: TxInclusionProof) -> Promise {
Copy link

Copilot AI May 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

verify_refund_finalize now accepts proof: TxInclusionProof, but the doc comment still describes tx_block_blockhash, tx_index, and merkle_proof as separate arguments. Please update the docs to describe the proof object (including coinbase fields) instead.

Copilot uses AI. Check for mistakes.
balance: transaction.output()[vout].value.to_sat(),
};
let tx_id = transaction.compute_txid().to_string();
let utxo_storage_key = generate_utxo_storage_key(tx_id.clone(), vout.try_into().unwrap());
Copy link

Copilot AI May 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

internal_safe_verify_deposit_entry uses vout.try_into().unwrap() when building the utxo_storage_key, which will panic with a generic message if vout doesn't fit into the expected integer type. For consistency with internal_verify_deposit_entry (and to make failures easier to debug), prefer unwrap_or_else(|_| env::panic_str("vout overflow")) or similar.

Suggested change
let utxo_storage_key = generate_utxo_storage_key(tx_id.clone(), vout.try_into().unwrap());
let utxo_storage_key = generate_utxo_storage_key(
tx_id.clone(),
vout
.try_into()
.unwrap_or_else(|_| env::panic_str("vout overflow")),
);

Copilot uses AI. Check for mistakes.
Comment on lines +957 to +966
self.get_account_by_name(user)
.call(self.bridge_contract.id(), "safe_verify_deposit_v2")
.args_json(json!({
"deposit_msg": deposit_msg,
"tx_bytes": Base64VecU8(tx_bytes),
"vout": vout,
"proof": proof,
}))
.deposit(NearToken::from_near(1))
.max_gas()
Copy link

Copilot AI May 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

safe_verify_deposit_v2 attaches NearToken::from_near(1), which is far above the contract’s required storage deposit (required_balance_for_safe_deposit() is ~millinear-scale). Attaching an oversized deposit can skew balances across tests and makes it harder to reason about refunds; consider attaching the minimal required amount (or querying required_balance_for_safe_deposit in the test context).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants