From d6740303c4202c4291b853c22a6c4c81859279cb Mon Sep 17 00:00:00 2001 From: Vaibhav Date: Wed, 28 Jun 2023 01:09:57 +0530 Subject: [PATCH 01/26] feat: add submit-signed-psbt --- proto/api/bria.proto | 10 +++++++++ src/api/server/mod.rs | 32 +++++++++++++++++++++++++++ src/app/error.rs | 28 +++++++++++++++++++----- src/app/mod.rs | 41 +++++++++++++++++++++++++++++++++++ src/cli/api_client.rs | 19 ++++++++++++++++ src/cli/mod.rs | 29 +++++++++++++++++++++++++ src/signing_session/entity.rs | 19 ++++++++++++++-- 7 files changed, 170 insertions(+), 8 deletions(-) diff --git a/proto/api/bria.proto b/proto/api/bria.proto index 1cbeb555..52610504 100644 --- a/proto/api/bria.proto +++ b/proto/api/bria.proto @@ -15,6 +15,8 @@ service BriaService { rpc ListXpubs (ListXpubsRequest) returns(ListXpubsResponse) {} rpc SetSignerConfig (SetSignerConfigRequest) returns (SetSignerConfigResponse) {} + rpc SubmitSignedPsbt (SubmitSignedPsbtRequest) returns (SubmitSignedPsbtResponse) {} + rpc CreateWallet (CreateWalletRequest) returns (CreateWalletResponse) {} rpc ListWallets (ListWalletsRequest) returns (ListWalletsResponse) {} rpc GetWalletBalanceSummary (GetWalletBalanceSummaryRequest) returns (GetWalletBalanceSummaryResponse) {} @@ -104,6 +106,14 @@ message BitcoindSignerConfig { message SetSignerConfigResponse {} +message SubmitSignedPsbtRequest { + string batch_id = 1; + string xpub_id = 2; + string signed_psbt = 3; +} + +message SubmitSignedPsbtResponse {} + message KeychainConfig { message Wpkh { string xpub = 1; diff --git a/src/api/server/mod.rs b/src/api/server/mod.rs index 86bdafcc..d622d755 100644 --- a/src/api/server/mod.rs +++ b/src/api/server/mod.rs @@ -163,6 +163,38 @@ impl BriaService for Bria { .await } + #[instrument(name = "bria.submit_signed_psbt", skip_all, fields(error, error.level, error.message), err)] + async fn submit_signed_psbt( + &self, + request: Request, + ) -> Result, Status> { + crate::tracing::record_error(|| async move { + extract_tracing(&request); + let key = extract_api_token(&request)?; + let profile = self.app.authenticate(key).await?; + let request = request.into_inner(); + let SubmitSignedPsbtRequest { + batch_id, + xpub_id, + signed_psbt, + } = request; + self.app + .submit_signed_psbt( + profile, + batch_id + .parse() + .map_err(ApplicationError::CouldNotParseIncomingUuid)?, + xpub_id + .parse() + .map_err(ApplicationError::CouldNotParseIncomingXpubId)?, + signed_psbt, + ) + .await?; + Ok(Response::new(SubmitSignedPsbtResponse {})) + }) + .await + } + #[instrument(name = "bria.create_wallet", skip_all, fields(error, error.level, error.message), err)] async fn create_wallet( &self, diff --git a/src/app/error.rs b/src/app/error.rs index 8672d62a..fd4a4791 100644 --- a/src/app/error.rs +++ b/src/app/error.rs @@ -1,12 +1,22 @@ use thiserror::Error; use crate::{ - address::error::AddressError, batch::error::BatchError, bdk::error::BdkError, - descriptor::error::DescriptorError, fees::error::FeeEstimationError, job::error::JobError, - ledger::error::LedgerError, outbox::error::OutboxError, payout::error::PayoutError, - payout_queue::error::PayoutQueueError, primitives::PayoutDestination, - profile::error::ProfileError, signing_session::error::SigningSessionError, - utxo::error::UtxoError, wallet::error::WalletError, xpub::error::XPubError, + address::error::AddressError, + batch::error::BatchError, + bdk::error::BdkError, + descriptor::error::DescriptorError, + fees::error::FeeEstimationError, + job::error::JobError, + ledger::error::LedgerError, + outbox::error::OutboxError, + payout::error::PayoutError, + payout_queue::error::PayoutQueueError, + primitives::{bitcoin, PayoutDestination}, + profile::error::ProfileError, + signing_session::error::SigningSessionError, + utxo::error::UtxoError, + wallet::error::WalletError, + xpub::error::XPubError, }; #[derive(Error, Debug)] @@ -51,6 +61,12 @@ pub enum ApplicationError { CouldNotParseIncomingMetadata(serde_json::Error), #[error("CouldNotParseIncomingUuid: {0}")] CouldNotParseIncomingUuid(uuid::Error), + #[error("CouldNotParseIncomingXpubId: {0}")] + CouldNotParseIncomingXpubId(::Err), #[error("DestinationBlocked - sending to '{0}' is prohibited")] DestinationBlocked(PayoutDestination), + #[error("Session not found for batch id: {0}")] + SessionNotFoundForBatch(String), + #[error("Session not found for xpub id: {0}")] + SessionNotFoundForXPubId(String), } diff --git a/src/app/mod.rs b/src/app/mod.rs index 7ce5131f..5d18b63b 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -205,6 +205,47 @@ impl App { Ok(()) } + #[instrument(name = "app.submit_signed_psbt", skip(self), err)] + pub async fn submit_signed_psbt( + &self, + profile: Profile, + batch_id: BatchId, + xpub_id: XPubId, + signed_psbt: String, + ) -> Result<(), ApplicationError> { + use std::str::FromStr; + let parsed_psbt = bitcoin::psbt::PartiallySignedTransaction::from_str(&signed_psbt) + .expect("psbt should parse"); + let mut tx = self.pool.begin().await?; + let mut sessions = if let Some(batch_session) = self + .signing_sessions + .list_for_batch(profile.account_id, batch_id) + .await? + { + batch_session.xpub_sessions + } else { + return Err(ApplicationError::SessionNotFoundForBatch( + batch_id.clone().to_string(), + )); + }; + let session = sessions.get_mut(&xpub_id).ok_or_else(|| { + ApplicationError::SessionNotFoundForXPubId(xpub_id.clone().to_string()) + })?; + + session.manually_signed_complete(parsed_psbt); + self.signing_sessions + .update_sessions(&mut tx, &sessions) + .await?; + let batch_ids = self + .signing_sessions + .list_batch_ids_for(&mut tx, profile.account_id, xpub_id) + .await?; + + job::spawn_all_batch_signings(tx, batch_ids.into_iter().map(|b| (profile.account_id, b))) + .await?; + Ok(()) + } + #[instrument(name = "app.create_wpkh_wallet", skip(self), err)] pub async fn create_wpkh_wallet( &self, diff --git a/src/cli/api_client.rs b/src/cli/api_client.rs index df248619..d9edeb56 100644 --- a/src/cli/api_client.rs +++ b/src/cli/api_client.rs @@ -139,6 +139,25 @@ impl ApiClient { output_json(response) } + pub async fn submit_signed_psbt( + &self, + batch_id: String, + xpub_id: String, + psbt: String, + ) -> anyhow::Result<()> { + let request = tonic::Request::new(proto::SubmitSignedPsbtRequest { + batch_id, + xpub_id, + signed_psbt: psbt, + }); + let response = self + .connect() + .await? + .submit_signed_psbt(self.inject_auth_token(request)?) + .await?; + output_json(response) + } + pub async fn create_wallet( &self, name: String, diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 71c1277b..74f50141 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -165,6 +165,25 @@ enum Command { #[clap(subcommand)] command: SetSignerConfigCommand, }, + /// Submit a signed psbt + SubmitSignedPsbt { + #[clap( + short, + long, + value_parser, + default_value = "http://localhost:2742", + env = "BRIA_API_URL" + )] + url: Option, + #[clap(env = "BRIA_API_KEY", default_value = "")] + api_key: String, + #[clap(short, long)] + batch_id: String, + #[clap(short, long)] + xpub_id: String, + #[clap(short, long)] + psbt: String, + }, /// Create a wallet from imported xpubs CreateWallet { #[clap( @@ -695,6 +714,16 @@ pub async fn run() -> anyhow::Result<()> { let client = api_client(cli.bria_home, url, api_key); client.set_signer_config(xpub, command).await?; } + Command::SubmitSignedPsbt { + url, + api_key, + batch_id, + xpub_id, + psbt, + } => { + let client = api_client(cli.bria_home, url, api_key); + client.submit_signed_psbt(batch_id, xpub_id, psbt).await?; + } Command::CreateWallet { url, api_key, diff --git a/src/signing_session/entity.rs b/src/signing_session/entity.rs index 19753e72..6a5da2ba 100644 --- a/src/signing_session/entity.rs +++ b/src/signing_session/entity.rs @@ -23,6 +23,9 @@ pub enum SigningSessionEvent { SigningAttemptFailed { reason: SigningFailureReason, }, + ManuallySignedCompleted { + signed_psbt: psbt::PartiallySignedTransaction, + }, RemoteSigningCompleted { signed_psbt: psbt::PartiallySignedTransaction, }, @@ -58,6 +61,11 @@ impl SigningSession { .push(SigningSessionEvent::RemoteSigningCompleted { signed_psbt }) } + pub fn manually_signed_complete(&mut self, signed_psbt: psbt::PartiallySignedTransaction) { + self.events + .push(SigningSessionEvent::ManuallySignedCompleted { signed_psbt }) + } + pub fn is_completed(&self) -> bool { self.signed_psbt().is_some() } @@ -65,8 +73,12 @@ impl SigningSession { pub fn signed_psbt(&self) -> Option<&psbt::PartiallySignedTransaction> { let mut ret = None; for event in self.events.iter() { - if let SigningSessionEvent::RemoteSigningCompleted { signed_psbt } = event { - ret = Some(signed_psbt); + match event { + SigningSessionEvent::RemoteSigningCompleted { signed_psbt } + | SigningSessionEvent::ManuallySignedCompleted { signed_psbt } => { + ret = Some(signed_psbt); + } + _ => (), } } ret @@ -93,6 +105,9 @@ impl SigningSession { ret = match event { SigningSessionEvent::SigningAttemptFailed { .. } => SigningSessionState::Failed, SigningSessionEvent::RemoteSigningCompleted { .. } => SigningSessionState::Complete, + SigningSessionEvent::ManuallySignedCompleted { .. } => { + SigningSessionState::Complete + } _ => ret, }; } From 48ea1008cf0b7d04cb51d2d12e140705234692ac Mon Sep 17 00:00:00 2001 From: Vaibhav Date: Wed, 28 Jun 2023 14:39:33 +0530 Subject: [PATCH 02/26] chore: some refactoring --- proto/api/bria.proto | 2 +- src/api/server/mod.rs | 10 +++++----- src/app/error.rs | 6 ++++-- src/app/mod.rs | 46 ++++++++++++++++++++----------------------- src/cli/api_client.rs | 8 ++++---- src/cli/mod.rs | 12 ++++++----- 6 files changed, 42 insertions(+), 42 deletions(-) diff --git a/proto/api/bria.proto b/proto/api/bria.proto index 52610504..af972c9a 100644 --- a/proto/api/bria.proto +++ b/proto/api/bria.proto @@ -108,7 +108,7 @@ message SetSignerConfigResponse {} message SubmitSignedPsbtRequest { string batch_id = 1; - string xpub_id = 2; + string xpub_ref = 2; string signed_psbt = 3; } diff --git a/src/api/server/mod.rs b/src/api/server/mod.rs index d622d755..36529f8b 100644 --- a/src/api/server/mod.rs +++ b/src/api/server/mod.rs @@ -175,7 +175,7 @@ impl BriaService for Bria { let request = request.into_inner(); let SubmitSignedPsbtRequest { batch_id, - xpub_id, + xpub_ref, signed_psbt, } = request; self.app @@ -184,10 +184,10 @@ impl BriaService for Bria { batch_id .parse() .map_err(ApplicationError::CouldNotParseIncomingUuid)?, - xpub_id - .parse() - .map_err(ApplicationError::CouldNotParseIncomingXpubId)?, - signed_psbt, + xpub_ref, + signed_psbt + .parse::() + .map_err(ApplicationError::CouldNotParseIncomingPsbt)?, ) .await?; Ok(Response::new(SubmitSignedPsbtResponse {})) diff --git a/src/app/error.rs b/src/app/error.rs index fd4a4791..4d7c1df0 100644 --- a/src/app/error.rs +++ b/src/app/error.rs @@ -66,7 +66,9 @@ pub enum ApplicationError { #[error("DestinationBlocked - sending to '{0}' is prohibited")] DestinationBlocked(PayoutDestination), #[error("Session not found for batch id: {0}")] - SessionNotFoundForBatch(String), + SessionNotFoundForBatchId(crate::primitives::BatchId), #[error("Session not found for xpub id: {0}")] - SessionNotFoundForXPubId(String), + SessionNotFoundForXPubId(crate::primitives::XPubId), + #[error("Could not parse incoming psbt: {0}")] + CouldNotParseIncomingPsbt(bitcoin::psbt::PsbtParseError), } diff --git a/src/app/mod.rs b/src/app/mod.rs index 5d18b63b..37792321 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -210,39 +210,35 @@ impl App { &self, profile: Profile, batch_id: BatchId, - xpub_id: XPubId, - signed_psbt: String, + xpub_ref: String, + signed_psbt: bitcoin::psbt::PartiallySignedTransaction, ) -> Result<(), ApplicationError> { - use std::str::FromStr; - let parsed_psbt = bitcoin::psbt::PartiallySignedTransaction::from_str(&signed_psbt) - .expect("psbt should parse"); - let mut tx = self.pool.begin().await?; - let mut sessions = if let Some(batch_session) = self + let xpub = self + .xpubs + .find_from_ref( + profile.account_id, + xpub_ref + .parse::() + .expect("ref should always parse"), + ) + .await?; + let xpub_id = xpub.id(); + let mut sessions = self .signing_sessions .list_for_batch(profile.account_id, batch_id) .await? - { - batch_session.xpub_sessions - } else { - return Err(ApplicationError::SessionNotFoundForBatch( - batch_id.clone().to_string(), - )); - }; - let session = sessions.get_mut(&xpub_id).ok_or_else(|| { - ApplicationError::SessionNotFoundForXPubId(xpub_id.clone().to_string()) - })?; + .ok_or(ApplicationError::SessionNotFoundForBatchId(batch_id))? + .xpub_sessions; + let session = sessions + .get_mut(&xpub_id) + .ok_or_else(|| ApplicationError::SessionNotFoundForXPubId(xpub_id))?; - session.manually_signed_complete(parsed_psbt); + let mut tx = self.pool.begin().await?; + session.manually_signed_complete(signed_psbt); self.signing_sessions .update_sessions(&mut tx, &sessions) .await?; - let batch_ids = self - .signing_sessions - .list_batch_ids_for(&mut tx, profile.account_id, xpub_id) - .await?; - - job::spawn_all_batch_signings(tx, batch_ids.into_iter().map(|b| (profile.account_id, b))) - .await?; + job::spawn_all_batch_signings(tx, std::iter::once((profile.account_id, batch_id))).await?; Ok(()) } diff --git a/src/cli/api_client.rs b/src/cli/api_client.rs index d9edeb56..3c3e3e21 100644 --- a/src/cli/api_client.rs +++ b/src/cli/api_client.rs @@ -142,13 +142,13 @@ impl ApiClient { pub async fn submit_signed_psbt( &self, batch_id: String, - xpub_id: String, - psbt: String, + xpub_ref: String, + signed_psbt: String, ) -> anyhow::Result<()> { let request = tonic::Request::new(proto::SubmitSignedPsbtRequest { batch_id, - xpub_id, - signed_psbt: psbt, + xpub_ref, + signed_psbt, }); let response = self .connect() diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 74f50141..42e9a773 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -180,9 +180,9 @@ enum Command { #[clap(short, long)] batch_id: String, #[clap(short, long)] - xpub_id: String, + xpub_ref: String, #[clap(short, long)] - psbt: String, + signed_psbt: String, }, /// Create a wallet from imported xpubs CreateWallet { @@ -718,11 +718,13 @@ pub async fn run() -> anyhow::Result<()> { url, api_key, batch_id, - xpub_id, - psbt, + xpub_ref, + signed_psbt, } => { let client = api_client(cli.bria_home, url, api_key); - client.submit_signed_psbt(batch_id, xpub_id, psbt).await?; + client + .submit_signed_psbt(batch_id, xpub_ref, signed_psbt) + .await?; } Command::CreateWallet { url, From 76aaf27a50d1be16b25cf4f6903214d30f1418b7 Mon Sep 17 00:00:00 2001 From: Vaibhav Date: Wed, 28 Jun 2023 15:17:10 +0530 Subject: [PATCH 03/26] chore: remove redundant clone --- src/api/server/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/server/mod.rs b/src/api/server/mod.rs index 36529f8b..82e902af 100644 --- a/src/api/server/mod.rs +++ b/src/api/server/mod.rs @@ -396,7 +396,7 @@ impl BriaService for Bria { .app .find_address_by_external_id(profile, external_id) .await?; - let wallet_id = address.wallet_id.clone().to_string(); + let wallet_id = address.wallet_id.to_string(); let proto_address: proto::WalletAddress = proto::WalletAddress::from(address); Ok(Response::new(FindAddressByExternalIdResponse { wallet_id, From 27715aecbb1daa46c3eb90987db0212db840259c Mon Sep 17 00:00:00 2001 From: Vaibhav Date: Wed, 28 Jun 2023 19:13:48 +0530 Subject: [PATCH 04/26] chore: add error for missing sig and witness --- src/app/error.rs | 4 ++++ src/app/mod.rs | 8 ++++++++ src/signing_session/entity.rs | 1 + 3 files changed, 13 insertions(+) diff --git a/src/app/error.rs b/src/app/error.rs index 4d7c1df0..b2909c33 100644 --- a/src/app/error.rs +++ b/src/app/error.rs @@ -71,4 +71,8 @@ pub enum ApplicationError { SessionNotFoundForXPubId(crate::primitives::XPubId), #[error("Could not parse incoming psbt: {0}")] CouldNotParseIncomingPsbt(bitcoin::psbt::PsbtParseError), + #[error("Signed Tx does not contain script sig")] + SignedTxDoesNotContainScriptSig, + #[error("Signed Tx does not contain script witness")] + SignedTxDoesNotContainScriptWitness, } diff --git a/src/app/mod.rs b/src/app/mod.rs index 37792321..3a5d35f0 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -223,6 +223,14 @@ impl App { ) .await?; let xpub_id = xpub.id(); + for txin in &signed_psbt.unsigned_tx.input { + if txin.script_sig.is_empty() { + return Err(ApplicationError::SignedTxDoesNotContainScriptSig); + } + if txin.witness.is_empty() { + return Err(ApplicationError::SignedTxDoesNotContainScriptWitness); + } + } let mut sessions = self .signing_sessions .list_for_batch(profile.account_id, batch_id) diff --git a/src/signing_session/entity.rs b/src/signing_session/entity.rs index 6a5da2ba..0293c53a 100644 --- a/src/signing_session/entity.rs +++ b/src/signing_session/entity.rs @@ -93,6 +93,7 @@ impl SigningSession { ret = match event { SigningSessionEvent::SigningAttemptFailed { reason } => Some(reason), SigningSessionEvent::RemoteSigningCompleted { .. } => None, + SigningSessionEvent::ManuallySignedCompleted { .. } => None, _ => ret, }; } From 875cd85479672d5c97ccf210272d78f88387fdca Mon Sep 17 00:00:00 2001 From: Vaibhav Date: Thu, 29 Jun 2023 16:54:33 +0530 Subject: [PATCH 05/26] chore: add psbt_validator and corresponding tests --- src/app/error.rs | 10 ++++++---- src/app/mod.rs | 14 +++++--------- src/wallet/mod.rs | 1 + src/wallet/psbt_validator.rs | 21 +++++++++++++++++++++ tests/psbt_validator.rs | 30 ++++++++++++++++++++++++++++++ 5 files changed, 63 insertions(+), 13 deletions(-) create mode 100644 src/wallet/psbt_validator.rs create mode 100644 tests/psbt_validator.rs diff --git a/src/app/error.rs b/src/app/error.rs index b2909c33..d70e99cb 100644 --- a/src/app/error.rs +++ b/src/app/error.rs @@ -65,14 +65,16 @@ pub enum ApplicationError { CouldNotParseIncomingXpubId(::Err), #[error("DestinationBlocked - sending to '{0}' is prohibited")] DestinationBlocked(PayoutDestination), - #[error("Session not found for batch id: {0}")] - SessionNotFoundForBatchId(crate::primitives::BatchId), - #[error("Session not found for xpub id: {0}")] - SessionNotFoundForXPubId(crate::primitives::XPubId), + #[error("Signing Session not found for batch id: {0}")] + SigningSessionNotFoundForBatchId(crate::primitives::BatchId), + #[error("Signing Session not found for xpub id: {0}")] + SigningSessionNotFoundForXPubId(crate::primitives::XPubId), #[error("Could not parse incoming psbt: {0}")] CouldNotParseIncomingPsbt(bitcoin::psbt::PsbtParseError), #[error("Signed Tx does not contain script sig")] SignedTxDoesNotContainScriptSig, #[error("Signed Tx does not contain script witness")] SignedTxDoesNotContainScriptWitness, + #[error("Submitted Psbt is not valid")] + SubmittedPsbtIsNotValid, } diff --git a/src/app/mod.rs b/src/app/mod.rs index 3a5d35f0..83b242dd 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -223,23 +223,19 @@ impl App { ) .await?; let xpub_id = xpub.id(); - for txin in &signed_psbt.unsigned_tx.input { - if txin.script_sig.is_empty() { - return Err(ApplicationError::SignedTxDoesNotContainScriptSig); - } - if txin.witness.is_empty() { - return Err(ApplicationError::SignedTxDoesNotContainScriptWitness); - } + let xpub = xpub.value; + if !psbt_validator::validate_psbt(&signed_psbt, xpub) { + return Err(ApplicationError::SubmittedPsbtIsNotValid); } let mut sessions = self .signing_sessions .list_for_batch(profile.account_id, batch_id) .await? - .ok_or(ApplicationError::SessionNotFoundForBatchId(batch_id))? + .ok_or(ApplicationError::SigningSessionNotFoundForBatchId(batch_id))? .xpub_sessions; let session = sessions .get_mut(&xpub_id) - .ok_or_else(|| ApplicationError::SessionNotFoundForXPubId(xpub_id))?; + .ok_or_else(|| ApplicationError::SigningSessionNotFoundForXPubId(xpub_id))?; let mut tx = self.pool.begin().await?; session.manually_signed_complete(signed_psbt); diff --git a/src/wallet/mod.rs b/src/wallet/mod.rs index 52b9fdf3..f4a6bb5c 100644 --- a/src/wallet/mod.rs +++ b/src/wallet/mod.rs @@ -4,6 +4,7 @@ mod entity; pub mod error; mod keychain; mod psbt_builder; +pub mod psbt_validator; mod repo; pub use balance::*; diff --git a/src/wallet/psbt_validator.rs b/src/wallet/psbt_validator.rs new file mode 100644 index 00000000..f0c51a71 --- /dev/null +++ b/src/wallet/psbt_validator.rs @@ -0,0 +1,21 @@ +use bdk::bitcoin::psbt; + +use std::collections::HashSet; + +use crate::xpub::XPub; + +pub fn validate_psbt(psbt: &psbt::PartiallySignedTransaction, xpub: XPub) -> bool { + let set: HashSet<_> = psbt + .inputs + .iter() + .flat_map(|inp| &inp.bip32_derivation) + .filter_map(|(pk, (fingerprint, _))| { + (fingerprint == &xpub.inner().parent_fingerprint).then_some(pk) + }) + .collect(); + + psbt.inputs + .iter() + .flat_map(|inp| &inp.partial_sigs) + .any(|(pk, _)| set.contains(&pk.inner)) +} diff --git a/tests/psbt_validator.rs b/tests/psbt_validator.rs new file mode 100644 index 00000000..8150545c --- /dev/null +++ b/tests/psbt_validator.rs @@ -0,0 +1,30 @@ +use bdk::bitcoin; + +use bria::wallet::psbt_validator; +use bria::xpub::*; + +#[tokio::test] +async fn psbt_validation_fails_when_no_signature_found() -> anyhow::Result<()> { + let xpub = XPub::try_from(("tpubDCr5twyowBZhQZEdAXWeJgZtKZgGbKSY4Co55hgw551xCZtHk5fWw9EyGKDBE6cSZPzc4QWR4NyZAeuZDKvRHpQmch78CKwLSy8FEhbvBeR", Some("m/84h/0h/0h"))).unwrap(); + let unsigned_psbt = "cHNidP8BAHEBAAAAAQXU7rw5wiONrLs8zEBacpUPaeCbbFvUGt+ZGhYXNAeIAQAAAAD+////ArN3fQEAAAAAFgAUV69hkddpchM/Kdbp6TUN+rIcmr7AaHgEAAAAABYAFFPOvhKDbGzCHM0LNEHgSPJjuf7RzQAAAAABAHECAAAAAU9hZA8fbnJG2yVoilG86fTB2OL1IqrvPQA9NlBtWiQnAAAAAAD9////AvwFECQBAAAAFgAUzLEhaay70eCwLvJFdjkvtol3NW8A4fUFAAAAABYAFDBOCTOounYzbvGLZnREjy6LIYleyAAAAAEBHwDh9QUAAAAAFgAUME4JM6i6djNu8YtmdESPLoshiV4BAwQBAAAAIgYD5r7WIWyxhitgzbBviYDuNdIi5MFngT7p77MpjifMr1oYb9vpm1QAAIAAAACAAAAAgAAAAAAAAAAAACICA/rQ0V1BsVPLAcQg2Hztdzw16PuDuhOzci1DnSHfjcpBGG/b6ZtUAACAAAAAgAAAAIABAAAAEAAAAAAA".parse::().unwrap(); + assert!(!psbt_validator::validate_psbt(&unsigned_psbt, xpub)); + Ok(()) +} + +#[tokio::test] +async fn psbt_validation_passes_when_psbt_has_signature_corresponding_to_xpub() -> anyhow::Result<()> +{ + let xpub = XPub::try_from(("tpubDCr5twyowBZhQZEdAXWeJgZtKZgGbKSY4Co55hgw551xCZtHk5fWw9EyGKDBE6cSZPzc4QWR4NyZAeuZDKvRHpQmch78CKwLSy8FEhbvBeR", Some("m/84h/0h/0h"))).unwrap(); + let signed_psbt = "cHNidP8BAHEBAAAAAW4QOT19+Uo9u6t7aDKmPXO/3w/xngnKmx9dTVANte9UAAAAAAD+////AuBwcgAAAAAAFgAUiMb1OtZlnYl675jK0AyiiKL9aDaTb4MFAAAAABYAFCZ1Q/XoJGSYzKxIS4BxneQgcF76zQAAAAABAN4CAAAAAAEBaptFtxfQBPJQn8F4EEXhoFdO4e4iMPviJ1CzgYJfbiIAAAAAAP3///8CAOH1BQAAAAAWABQwTgkzqLp2M27xi2Z0RI8uiyGJXvwFECQBAAAAFgAUTee+ueYwAcnhDxp0DTYDR1ZkGJ8CRzBEAiAvABR181UCFonR47sNobPua6tPN2eaQPeuD1hXlt1hRgIgTTA2C0YDhXKnbyYlBqeNqAxrEFezQ2qkI9ua7vaGf2gBIQKjUJi5wYVZ2EWXNdIeJcVp4wIdRh2+hiBhJHc7ZA9gL8gAAAABAR8A4fUFAAAAABYAFDBOCTOounYzbvGLZnREjy6LIYleIgID5r7WIWyxhitgzbBviYDuNdIi5MFngT7p77MpjifMr1pHMEQCIHoaBu0iBiJ2ZoggAPvO5AXQ+l3WoxRc5x/ppIyNX93lAiA878wEcBTYNS8igFYy/m8RyiN0RR60Y3VNCeiqMxDyewEBAwQBAAAAIgYD5r7WIWyxhitgzbBviYDuNdIi5MFngT7p77MpjifMr1oYb9vpm1QAAIAAAACAAAAAgAAAAAAAAAAAAAAiAgO+qPqnLtz1qY0jb2Xn1qppkA8Fo4g2wjaVQhzw9d2r4hhv2+mbVAAAgAAAAIAAAACAAQAAAAMAAAAA".parse::().unwrap(); + assert!(psbt_validator::validate_psbt(&signed_psbt, xpub)); + Ok(()) +} + +#[tokio::test] +async fn psbt_validation_fails_when_psbt_does_have_signature_corresponding_to_xpub( +) -> anyhow::Result<()> { + let xpub = XPub::try_from(("tpubDD4vFnWuTMEcZiaaZPgvzeGyMzWe6qHW8gALk5Md9kutDvtdDjYFwzauEFFRHgov8pAwup5jX88j5YFyiACsPf3pqn5hBjvuTLRAseaJ6b4", Some("m/84h/0h/0h"))).unwrap(); + let signed_psbt = "cHNidP8BAHEBAAAAAW4QOT19+Uo9u6t7aDKmPXO/3w/xngnKmx9dTVANte9UAAAAAAD+////AuBwcgAAAAAAFgAUiMb1OtZlnYl675jK0AyiiKL9aDaTb4MFAAAAABYAFCZ1Q/XoJGSYzKxIS4BxneQgcF76zQAAAAABAN4CAAAAAAEBaptFtxfQBPJQn8F4EEXhoFdO4e4iMPviJ1CzgYJfbiIAAAAAAP3///8CAOH1BQAAAAAWABQwTgkzqLp2M27xi2Z0RI8uiyGJXvwFECQBAAAAFgAUTee+ueYwAcnhDxp0DTYDR1ZkGJ8CRzBEAiAvABR181UCFonR47sNobPua6tPN2eaQPeuD1hXlt1hRgIgTTA2C0YDhXKnbyYlBqeNqAxrEFezQ2qkI9ua7vaGf2gBIQKjUJi5wYVZ2EWXNdIeJcVp4wIdRh2+hiBhJHc7ZA9gL8gAAAABAR8A4fUFAAAAABYAFDBOCTOounYzbvGLZnREjy6LIYleIgID5r7WIWyxhitgzbBviYDuNdIi5MFngT7p77MpjifMr1pHMEQCIHoaBu0iBiJ2ZoggAPvO5AXQ+l3WoxRc5x/ppIyNX93lAiA878wEcBTYNS8igFYy/m8RyiN0RR60Y3VNCeiqMxDyewEBAwQBAAAAIgYD5r7WIWyxhitgzbBviYDuNdIi5MFngT7p77MpjifMr1oYb9vpm1QAAIAAAACAAAAAgAAAAAAAAAAAAAAiAgO+qPqnLtz1qY0jb2Xn1qppkA8Fo4g2wjaVQhzw9d2r4hhv2+mbVAAAgAAAAIAAAACAAQAAAAMAAAAA".parse::().unwrap(); + assert!(!psbt_validator::validate_psbt(&signed_psbt, xpub)); + Ok(()) +} From 88bf7125004e80e2a8f60a92f9670066927ac21a Mon Sep 17 00:00:00 2001 From: Vaibhav Date: Thu, 29 Jun 2023 16:56:24 +0530 Subject: [PATCH 06/26] chore: remove redundant errors --- src/app/error.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/app/error.rs b/src/app/error.rs index d70e99cb..99a52391 100644 --- a/src/app/error.rs +++ b/src/app/error.rs @@ -71,10 +71,6 @@ pub enum ApplicationError { SigningSessionNotFoundForXPubId(crate::primitives::XPubId), #[error("Could not parse incoming psbt: {0}")] CouldNotParseIncomingPsbt(bitcoin::psbt::PsbtParseError), - #[error("Signed Tx does not contain script sig")] - SignedTxDoesNotContainScriptSig, - #[error("Signed Tx does not contain script witness")] - SignedTxDoesNotContainScriptWitness, #[error("Submitted Psbt is not valid")] SubmittedPsbtIsNotValid, } From 2584ef5dd65f19f9303e64ab7b622a863895339e Mon Sep 17 00:00:00 2001 From: Vaibhav Date: Thu, 29 Jun 2023 18:01:43 +0530 Subject: [PATCH 07/26] chore: address pr reviews --- src/app/mod.rs | 2 +- src/signing_session/entity.rs | 12 ++++++------ src/wallet/psbt_validator.rs | 26 ++++++++++++++++++++++++++ tests/psbt_validator.rs | 30 ------------------------------ 4 files changed, 33 insertions(+), 37 deletions(-) delete mode 100644 tests/psbt_validator.rs diff --git a/src/app/mod.rs b/src/app/mod.rs index 83b242dd..c2472561 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -238,7 +238,7 @@ impl App { .ok_or_else(|| ApplicationError::SigningSessionNotFoundForXPubId(xpub_id))?; let mut tx = self.pool.begin().await?; - session.manually_signed_complete(signed_psbt); + session.submit_externally_signed_psbt(signed_psbt); self.signing_sessions .update_sessions(&mut tx, &sessions) .await?; diff --git a/src/signing_session/entity.rs b/src/signing_session/entity.rs index 0293c53a..1add14a8 100644 --- a/src/signing_session/entity.rs +++ b/src/signing_session/entity.rs @@ -23,7 +23,7 @@ pub enum SigningSessionEvent { SigningAttemptFailed { reason: SigningFailureReason, }, - ManuallySignedCompleted { + ExternallySignedPsbtSubmitted { signed_psbt: psbt::PartiallySignedTransaction, }, RemoteSigningCompleted { @@ -61,9 +61,9 @@ impl SigningSession { .push(SigningSessionEvent::RemoteSigningCompleted { signed_psbt }) } - pub fn manually_signed_complete(&mut self, signed_psbt: psbt::PartiallySignedTransaction) { + pub fn submit_externally_signed_psbt(&mut self, signed_psbt: psbt::PartiallySignedTransaction) { self.events - .push(SigningSessionEvent::ManuallySignedCompleted { signed_psbt }) + .push(SigningSessionEvent::ExternallySignedPsbtSubmitted { signed_psbt }) } pub fn is_completed(&self) -> bool { @@ -75,7 +75,7 @@ impl SigningSession { for event in self.events.iter() { match event { SigningSessionEvent::RemoteSigningCompleted { signed_psbt } - | SigningSessionEvent::ManuallySignedCompleted { signed_psbt } => { + | SigningSessionEvent::ExternallySignedPsbtSubmitted { signed_psbt } => { ret = Some(signed_psbt); } _ => (), @@ -93,7 +93,7 @@ impl SigningSession { ret = match event { SigningSessionEvent::SigningAttemptFailed { reason } => Some(reason), SigningSessionEvent::RemoteSigningCompleted { .. } => None, - SigningSessionEvent::ManuallySignedCompleted { .. } => None, + SigningSessionEvent::ExternallySignedPsbtSubmitted { .. } => None, _ => ret, }; } @@ -106,7 +106,7 @@ impl SigningSession { ret = match event { SigningSessionEvent::SigningAttemptFailed { .. } => SigningSessionState::Failed, SigningSessionEvent::RemoteSigningCompleted { .. } => SigningSessionState::Complete, - SigningSessionEvent::ManuallySignedCompleted { .. } => { + SigningSessionEvent::ExternallySignedPsbtSubmitted { .. } => { SigningSessionState::Complete } _ => ret, diff --git a/src/wallet/psbt_validator.rs b/src/wallet/psbt_validator.rs index f0c51a71..b062648a 100644 --- a/src/wallet/psbt_validator.rs +++ b/src/wallet/psbt_validator.rs @@ -19,3 +19,29 @@ pub fn validate_psbt(psbt: &psbt::PartiallySignedTransaction, xpub: XPub) -> boo .flat_map(|inp| &inp.partial_sigs) .any(|(pk, _)| set.contains(&pk.inner)) } + +#[cfg(test)] +mod tests { + pub use super::*; + + #[test] + fn psbt_validation_fails_when_no_signature_found() { + let xpub = XPub::try_from(("tpubDCr5twyowBZhQZEdAXWeJgZtKZgGbKSY4Co55hgw551xCZtHk5fWw9EyGKDBE6cSZPzc4QWR4NyZAeuZDKvRHpQmch78CKwLSy8FEhbvBeR", Some("m/84h/0h/0h"))).unwrap(); + let unsigned_psbt = "cHNidP8BAHEBAAAAAQXU7rw5wiONrLs8zEBacpUPaeCbbFvUGt+ZGhYXNAeIAQAAAAD+////ArN3fQEAAAAAFgAUV69hkddpchM/Kdbp6TUN+rIcmr7AaHgEAAAAABYAFFPOvhKDbGzCHM0LNEHgSPJjuf7RzQAAAAABAHECAAAAAU9hZA8fbnJG2yVoilG86fTB2OL1IqrvPQA9NlBtWiQnAAAAAAD9////AvwFECQBAAAAFgAUzLEhaay70eCwLvJFdjkvtol3NW8A4fUFAAAAABYAFDBOCTOounYzbvGLZnREjy6LIYleyAAAAAEBHwDh9QUAAAAAFgAUME4JM6i6djNu8YtmdESPLoshiV4BAwQBAAAAIgYD5r7WIWyxhitgzbBviYDuNdIi5MFngT7p77MpjifMr1oYb9vpm1QAAIAAAACAAAAAgAAAAAAAAAAAACICA/rQ0V1BsVPLAcQg2Hztdzw16PuDuhOzci1DnSHfjcpBGG/b6ZtUAACAAAAAgAAAAIABAAAAEAAAAAAA".parse::().unwrap(); + assert!(!validate_psbt(&unsigned_psbt, xpub)); + } + + #[test] + fn psbt_validation_passes_when_psbt_has_signature_corresponding_to_xpub() { + let xpub = XPub::try_from(("tpubDCr5twyowBZhQZEdAXWeJgZtKZgGbKSY4Co55hgw551xCZtHk5fWw9EyGKDBE6cSZPzc4QWR4NyZAeuZDKvRHpQmch78CKwLSy8FEhbvBeR", Some("m/84h/0h/0h"))).unwrap(); + let signed_psbt = "cHNidP8BAHEBAAAAAW4QOT19+Uo9u6t7aDKmPXO/3w/xngnKmx9dTVANte9UAAAAAAD+////AuBwcgAAAAAAFgAUiMb1OtZlnYl675jK0AyiiKL9aDaTb4MFAAAAABYAFCZ1Q/XoJGSYzKxIS4BxneQgcF76zQAAAAABAN4CAAAAAAEBaptFtxfQBPJQn8F4EEXhoFdO4e4iMPviJ1CzgYJfbiIAAAAAAP3///8CAOH1BQAAAAAWABQwTgkzqLp2M27xi2Z0RI8uiyGJXvwFECQBAAAAFgAUTee+ueYwAcnhDxp0DTYDR1ZkGJ8CRzBEAiAvABR181UCFonR47sNobPua6tPN2eaQPeuD1hXlt1hRgIgTTA2C0YDhXKnbyYlBqeNqAxrEFezQ2qkI9ua7vaGf2gBIQKjUJi5wYVZ2EWXNdIeJcVp4wIdRh2+hiBhJHc7ZA9gL8gAAAABAR8A4fUFAAAAABYAFDBOCTOounYzbvGLZnREjy6LIYleIgID5r7WIWyxhitgzbBviYDuNdIi5MFngT7p77MpjifMr1pHMEQCIHoaBu0iBiJ2ZoggAPvO5AXQ+l3WoxRc5x/ppIyNX93lAiA878wEcBTYNS8igFYy/m8RyiN0RR60Y3VNCeiqMxDyewEBAwQBAAAAIgYD5r7WIWyxhitgzbBviYDuNdIi5MFngT7p77MpjifMr1oYb9vpm1QAAIAAAACAAAAAgAAAAAAAAAAAAAAiAgO+qPqnLtz1qY0jb2Xn1qppkA8Fo4g2wjaVQhzw9d2r4hhv2+mbVAAAgAAAAIAAAACAAQAAAAMAAAAA".parse::().unwrap(); + assert!(validate_psbt(&signed_psbt, xpub)); + } + + #[test] + fn psbt_validation_fails_when_psbt_does_have_signature_corresponding_to_xpub() { + let xpub = XPub::try_from(("tpubDD4vFnWuTMEcZiaaZPgvzeGyMzWe6qHW8gALk5Md9kutDvtdDjYFwzauEFFRHgov8pAwup5jX88j5YFyiACsPf3pqn5hBjvuTLRAseaJ6b4", Some("m/84h/0h/0h"))).unwrap(); + let signed_psbt = "cHNidP8BAHEBAAAAAW4QOT19+Uo9u6t7aDKmPXO/3w/xngnKmx9dTVANte9UAAAAAAD+////AuBwcgAAAAAAFgAUiMb1OtZlnYl675jK0AyiiKL9aDaTb4MFAAAAABYAFCZ1Q/XoJGSYzKxIS4BxneQgcF76zQAAAAABAN4CAAAAAAEBaptFtxfQBPJQn8F4EEXhoFdO4e4iMPviJ1CzgYJfbiIAAAAAAP3///8CAOH1BQAAAAAWABQwTgkzqLp2M27xi2Z0RI8uiyGJXvwFECQBAAAAFgAUTee+ueYwAcnhDxp0DTYDR1ZkGJ8CRzBEAiAvABR181UCFonR47sNobPua6tPN2eaQPeuD1hXlt1hRgIgTTA2C0YDhXKnbyYlBqeNqAxrEFezQ2qkI9ua7vaGf2gBIQKjUJi5wYVZ2EWXNdIeJcVp4wIdRh2+hiBhJHc7ZA9gL8gAAAABAR8A4fUFAAAAABYAFDBOCTOounYzbvGLZnREjy6LIYleIgID5r7WIWyxhitgzbBviYDuNdIi5MFngT7p77MpjifMr1pHMEQCIHoaBu0iBiJ2ZoggAPvO5AXQ+l3WoxRc5x/ppIyNX93lAiA878wEcBTYNS8igFYy/m8RyiN0RR60Y3VNCeiqMxDyewEBAwQBAAAAIgYD5r7WIWyxhitgzbBviYDuNdIi5MFngT7p77MpjifMr1oYb9vpm1QAAIAAAACAAAAAgAAAAAAAAAAAAAAiAgO+qPqnLtz1qY0jb2Xn1qppkA8Fo4g2wjaVQhzw9d2r4hhv2+mbVAAAgAAAAIAAAACAAQAAAAMAAAAA".parse::().unwrap(); + assert!(!validate_psbt(&signed_psbt, xpub)); + } +} diff --git a/tests/psbt_validator.rs b/tests/psbt_validator.rs deleted file mode 100644 index 8150545c..00000000 --- a/tests/psbt_validator.rs +++ /dev/null @@ -1,30 +0,0 @@ -use bdk::bitcoin; - -use bria::wallet::psbt_validator; -use bria::xpub::*; - -#[tokio::test] -async fn psbt_validation_fails_when_no_signature_found() -> anyhow::Result<()> { - let xpub = XPub::try_from(("tpubDCr5twyowBZhQZEdAXWeJgZtKZgGbKSY4Co55hgw551xCZtHk5fWw9EyGKDBE6cSZPzc4QWR4NyZAeuZDKvRHpQmch78CKwLSy8FEhbvBeR", Some("m/84h/0h/0h"))).unwrap(); - let unsigned_psbt = "cHNidP8BAHEBAAAAAQXU7rw5wiONrLs8zEBacpUPaeCbbFvUGt+ZGhYXNAeIAQAAAAD+////ArN3fQEAAAAAFgAUV69hkddpchM/Kdbp6TUN+rIcmr7AaHgEAAAAABYAFFPOvhKDbGzCHM0LNEHgSPJjuf7RzQAAAAABAHECAAAAAU9hZA8fbnJG2yVoilG86fTB2OL1IqrvPQA9NlBtWiQnAAAAAAD9////AvwFECQBAAAAFgAUzLEhaay70eCwLvJFdjkvtol3NW8A4fUFAAAAABYAFDBOCTOounYzbvGLZnREjy6LIYleyAAAAAEBHwDh9QUAAAAAFgAUME4JM6i6djNu8YtmdESPLoshiV4BAwQBAAAAIgYD5r7WIWyxhitgzbBviYDuNdIi5MFngT7p77MpjifMr1oYb9vpm1QAAIAAAACAAAAAgAAAAAAAAAAAACICA/rQ0V1BsVPLAcQg2Hztdzw16PuDuhOzci1DnSHfjcpBGG/b6ZtUAACAAAAAgAAAAIABAAAAEAAAAAAA".parse::().unwrap(); - assert!(!psbt_validator::validate_psbt(&unsigned_psbt, xpub)); - Ok(()) -} - -#[tokio::test] -async fn psbt_validation_passes_when_psbt_has_signature_corresponding_to_xpub() -> anyhow::Result<()> -{ - let xpub = XPub::try_from(("tpubDCr5twyowBZhQZEdAXWeJgZtKZgGbKSY4Co55hgw551xCZtHk5fWw9EyGKDBE6cSZPzc4QWR4NyZAeuZDKvRHpQmch78CKwLSy8FEhbvBeR", Some("m/84h/0h/0h"))).unwrap(); - let signed_psbt = "cHNidP8BAHEBAAAAAW4QOT19+Uo9u6t7aDKmPXO/3w/xngnKmx9dTVANte9UAAAAAAD+////AuBwcgAAAAAAFgAUiMb1OtZlnYl675jK0AyiiKL9aDaTb4MFAAAAABYAFCZ1Q/XoJGSYzKxIS4BxneQgcF76zQAAAAABAN4CAAAAAAEBaptFtxfQBPJQn8F4EEXhoFdO4e4iMPviJ1CzgYJfbiIAAAAAAP3///8CAOH1BQAAAAAWABQwTgkzqLp2M27xi2Z0RI8uiyGJXvwFECQBAAAAFgAUTee+ueYwAcnhDxp0DTYDR1ZkGJ8CRzBEAiAvABR181UCFonR47sNobPua6tPN2eaQPeuD1hXlt1hRgIgTTA2C0YDhXKnbyYlBqeNqAxrEFezQ2qkI9ua7vaGf2gBIQKjUJi5wYVZ2EWXNdIeJcVp4wIdRh2+hiBhJHc7ZA9gL8gAAAABAR8A4fUFAAAAABYAFDBOCTOounYzbvGLZnREjy6LIYleIgID5r7WIWyxhitgzbBviYDuNdIi5MFngT7p77MpjifMr1pHMEQCIHoaBu0iBiJ2ZoggAPvO5AXQ+l3WoxRc5x/ppIyNX93lAiA878wEcBTYNS8igFYy/m8RyiN0RR60Y3VNCeiqMxDyewEBAwQBAAAAIgYD5r7WIWyxhitgzbBviYDuNdIi5MFngT7p77MpjifMr1oYb9vpm1QAAIAAAACAAAAAgAAAAAAAAAAAAAAiAgO+qPqnLtz1qY0jb2Xn1qppkA8Fo4g2wjaVQhzw9d2r4hhv2+mbVAAAgAAAAIAAAACAAQAAAAMAAAAA".parse::().unwrap(); - assert!(psbt_validator::validate_psbt(&signed_psbt, xpub)); - Ok(()) -} - -#[tokio::test] -async fn psbt_validation_fails_when_psbt_does_have_signature_corresponding_to_xpub( -) -> anyhow::Result<()> { - let xpub = XPub::try_from(("tpubDD4vFnWuTMEcZiaaZPgvzeGyMzWe6qHW8gALk5Md9kutDvtdDjYFwzauEFFRHgov8pAwup5jX88j5YFyiACsPf3pqn5hBjvuTLRAseaJ6b4", Some("m/84h/0h/0h"))).unwrap(); - let signed_psbt = "cHNidP8BAHEBAAAAAW4QOT19+Uo9u6t7aDKmPXO/3w/xngnKmx9dTVANte9UAAAAAAD+////AuBwcgAAAAAAFgAUiMb1OtZlnYl675jK0AyiiKL9aDaTb4MFAAAAABYAFCZ1Q/XoJGSYzKxIS4BxneQgcF76zQAAAAABAN4CAAAAAAEBaptFtxfQBPJQn8F4EEXhoFdO4e4iMPviJ1CzgYJfbiIAAAAAAP3///8CAOH1BQAAAAAWABQwTgkzqLp2M27xi2Z0RI8uiyGJXvwFECQBAAAAFgAUTee+ueYwAcnhDxp0DTYDR1ZkGJ8CRzBEAiAvABR181UCFonR47sNobPua6tPN2eaQPeuD1hXlt1hRgIgTTA2C0YDhXKnbyYlBqeNqAxrEFezQ2qkI9ua7vaGf2gBIQKjUJi5wYVZ2EWXNdIeJcVp4wIdRh2+hiBhJHc7ZA9gL8gAAAABAR8A4fUFAAAAABYAFDBOCTOounYzbvGLZnREjy6LIYleIgID5r7WIWyxhitgzbBviYDuNdIi5MFngT7p77MpjifMr1pHMEQCIHoaBu0iBiJ2ZoggAPvO5AXQ+l3WoxRc5x/ppIyNX93lAiA878wEcBTYNS8igFYy/m8RyiN0RR60Y3VNCeiqMxDyewEBAwQBAAAAIgYD5r7WIWyxhitgzbBviYDuNdIi5MFngT7p77MpjifMr1oYb9vpm1QAAIAAAACAAAAAgAAAAAAAAAAAAAAiAgO+qPqnLtz1qY0jb2Xn1qppkA8Fo4g2wjaVQhzw9d2r4hhv2+mbVAAAgAAAAIAAAACAAQAAAAMAAAAA".parse::().unwrap(); - assert!(!psbt_validator::validate_psbt(&signed_psbt, xpub)); - Ok(()) -} From d917a6deacade52a1e249f7839a6ec61039e7cda Mon Sep 17 00:00:00 2001 From: Vaibhav Date: Fri, 30 Jun 2023 17:51:46 +0530 Subject: [PATCH 08/26] feat: add support for sorted_multisig --- proto/api/bria.proto | 5 ++ src/api/server/mod.rs | 10 +++ src/app/mod.rs | 26 +++++++ src/cli/mod.rs | 12 ++++ src/job/batch_signing.rs | 64 ++++++----------- src/wallet/keychain/config.rs | 31 ++++++++ tests/e2e/helpers.bash | 22 ++++++ tests/e2e/multisig_payout.bats | 125 +++++++++++++++++++++++++++++++++ 8 files changed, 254 insertions(+), 41 deletions(-) create mode 100644 tests/e2e/multisig_payout.bats diff --git a/proto/api/bria.proto b/proto/api/bria.proto index af972c9a..ef1d9087 100644 --- a/proto/api/bria.proto +++ b/proto/api/bria.proto @@ -123,9 +123,14 @@ message KeychainConfig { string external = 1; string internal = 2; } + message SortedMultisig { + repeated string xpubs = 1; + uint32 threshold = 2; + } oneof config { Wpkh wpkh = 1; Descriptors descriptors = 2; + SortedMultisig sorted_multisig = 3; } } diff --git a/src/api/server/mod.rs b/src/api/server/mod.rs index 82e902af..7a87c2c2 100644 --- a/src/api/server/mod.rs +++ b/src/api/server/mod.rs @@ -232,6 +232,16 @@ impl BriaService for Bria { .create_descriptors_wallet(profile, name, external, internal) .await? } + Some(KeychainConfig { + config: + Some(keychain_config::Config::SortedMultisig( + keychain_config::SortedMultisig { + xpubs, + threshold, + })), + }) => { + self.app.create_sorted_multisig_wallet(profile, name, xpubs, threshold).await? + } _ => { return Err(Status::invalid_argument("invalid keychain config")); } diff --git a/src/app/mod.rs b/src/app/mod.rs index c2472561..5b7cd9cf 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -283,6 +283,32 @@ impl App { self.create_wallet(profile, wallet_name, keychain).await } + #[instrument(name = "app.create_sortedmulti_wallet", skip(self), err)] + pub async fn create_sorted_multisig_wallet( + &self, + profile: Profile, + wallet_name: String, + xpubs: Vec, + threshold: u32, + ) -> Result<(WalletId, Vec), ApplicationError> { + let xpub_values: Vec = futures::future::try_join_all( + xpubs + .iter() + .map(|xpub| { + xpub.parse::() + .expect("xpub_ref should always parse") + }) + .map(|xpub_ref| self.xpubs.find_from_ref(profile.account_id, xpub_ref)), + ) + .await? + .into_iter() + .map(|xpub| xpub.value) + .collect(); + + let keychain = KeychainConfig::sorted_multisig(xpub_values, threshold); + self.create_wallet(profile, wallet_name, keychain).await + } + async fn create_wallet( &self, profile: Profile, diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 42e9a773..30b0d9f3 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -572,6 +572,12 @@ enum CreateWalletCommand { #[clap(short, long)] change_descriptor: String, }, + SortedMultisig { + #[clap(short, long, num_args(2..) )] + xpub: Vec, + #[clap(short, long)] + threshold: u32, + }, } #[derive(Subcommand)] @@ -1155,6 +1161,12 @@ impl From for crate::api::proto::keychain_config::Config { external: descriptor, internal: change_descriptor, }), + CreateWalletCommand::SortedMultisig { xpub, threshold } => { + Config::SortedMultisig(SortedMultisig { + xpubs: xpub, + threshold, + }) + } } } } diff --git a/src/job/batch_signing.rs b/src/job/batch_signing.rs index baae768f..8fd25f2d 100644 --- a/src/job/batch_signing.rs +++ b/src/job/batch_signing.rs @@ -33,8 +33,6 @@ pub async fn execute( xpubs: XPubs, signer_encryption_config: SignerEncryptionConfig, ) -> Result<(BatchSigningData, bool), JobError> { - let mut stalled = false; - let mut last_err = None; let mut current_keychain = None; let (mut sessions, mut account_xpub_cache) = if let Some(batch_session) = signing_sessions .list_for_batch(data.account_id, data.batch_id) @@ -94,14 +92,12 @@ pub async fn execute( Ok(Some(client)) => client, Ok(None) => { session.attempt_failed(SigningFailureReason::SignerConfigMissing); - stalled = true; tracing::warn!("signer_config_missing"); continue; } Err(err) => { session.attempt_failed(&err); tracing::error!("{}", err.to_string()); - last_err = Some(err); continue; } }; @@ -112,7 +108,6 @@ pub async fn execute( Err(err) => { session.attempt_failed(&err); tracing::error!("{}", err.to_string()); - last_err = Some(err); continue; } } @@ -123,42 +118,29 @@ pub async fn execute( signing_sessions.update_sessions(&mut tx, &sessions).await?; tx.commit().await?; } - - tracing::Span::current().record("stalled", stalled); - if let Some(err) = last_err { - return Err(err.into()); - } else if stalled { - return Ok((data, false)); - } - let mut sessions = sessions.into_values(); - let mut first_psbt = sessions - .next() - .and_then(|s| s.signed_psbt().cloned()) - .ok_or(JobError::PsbtMissingInSigningSessions)?; - for s in sessions { - first_psbt.combine( - s.signed_psbt() - .ok_or(JobError::PsbtMissingInSigningSessions)? - .clone(), - )?; - } - - if current_keychain.is_none() { - let batch = batches.find_by_id(data.account_id, data.batch_id).await?; - let span = tracing::Span::current(); - span.record("txid", &tracing::field::display(batch.bitcoin_tx_id)); - let wallet_id = batch.wallet_summaries.into_keys().next().unwrap(); - let wallet = wallets.find_by_id(wallet_id).await?; - current_keychain = Some(wallet.current_keychain_wallet(&pool)); + if let Some(mut first_signed_psbt) = sessions.find_map(|s| s.signed_psbt().cloned()) { + sessions.for_each(|s| { + if let Some(psbt) = s.signed_psbt() { + let _ = first_signed_psbt.combine(psbt.clone()); + } + }); + if current_keychain.is_none() { + let batch = batches.find_by_id(data.account_id, data.batch_id).await?; + let span = tracing::Span::current(); + span.record("txid", &tracing::field::display(batch.bitcoin_tx_id)); + let wallet_id = batch.wallet_summaries.into_keys().next().unwrap(); + let wallet = wallets.find_by_id(wallet_id).await?; + current_keychain = Some(wallet.current_keychain_wallet(&pool)); + } + let tx = current_keychain + .unwrap() + .finalize_psbt(first_signed_psbt) + .await? + .extract_tx(); + batches.set_signed_tx(data.batch_id, tx).await?; + Ok((data, true)) + } else { + Ok((data, false)) } - - let tx = current_keychain - .unwrap() - .finalize_psbt(first_psbt) - .await? - .extract_tx(); - batches.set_signed_tx(data.batch_id, tx).await?; - - Ok((data, true)) } diff --git a/src/wallet/keychain/config.rs b/src/wallet/keychain/config.rs index a715ec0d..88bde70a 100644 --- a/src/wallet/keychain/config.rs +++ b/src/wallet/keychain/config.rs @@ -14,6 +14,10 @@ pub enum KeychainConfig { internal: ExtendedDescriptor, external: ExtendedDescriptor, }, + SortedMultisig { + xpub: Vec, + threshold: u32, + }, } impl KeychainConfig { @@ -21,6 +25,10 @@ impl KeychainConfig { Self::Wpkh { xpub } } + pub fn sorted_multisig(xpub: Vec, threshold: u32) -> Self { + Self::SortedMultisig { xpub, threshold } + } + pub fn xpubs(&self) -> Vec { match self { Self::Wpkh { xpub } => vec![xpub.clone()], @@ -38,6 +46,7 @@ impl KeychainConfig { }); ret.into_values().collect() } + Self::SortedMultisig { xpub, .. } => xpub.clone(), } } @@ -47,6 +56,17 @@ impl KeychainConfig { .parse() .expect("Couldn't create internal wpkh descriptor"), Self::Descriptors { external, .. } => external.clone(), + Self::SortedMultisig { xpub, threshold } => { + let keys = xpub + .iter() + .map(|xpub| format!("{}/0/*", xpub)) + .collect::>(); + let keys = keys.join(","); + println!("{}", keys); + format!("wsh(sortedmulti({},{}))", threshold, keys) + .parse() + .expect("Couldn't create external sorted multisig descriptor") + } } } @@ -56,6 +76,16 @@ impl KeychainConfig { .parse() .expect("Couldn't create internal wpkh descriptor"), Self::Descriptors { internal, .. } => internal.clone(), + Self::SortedMultisig { xpub, threshold } => { + let keys = xpub + .iter() + .map(|xpub| format!("{}/1/*", xpub)) + .collect::>(); + let keys = keys.join(","); + format!("wsh(sortedmulti({},{}))", threshold, keys) + .parse() + .expect("Couldn't create internal sorted multisig descriptor") + } } } } @@ -73,6 +103,7 @@ impl TryFrom<(&str, &str)> for KeychainConfig { { return Err(crate::wallet::error::WalletError::UnsupportedPubKeyType); } + Ok(Self::Descriptors { internal, external }) } } diff --git a/tests/e2e/helpers.bash b/tests/e2e/helpers.bash index 5b9dd007..a3d1428c 100644 --- a/tests/e2e/helpers.bash +++ b/tests/e2e/helpers.bash @@ -139,6 +139,28 @@ bria_lnd_init() { echo "Bria Initialization Complete" } +bria_multisig_init() { + if [[ "${BRIA_CONFIG}" == "docker" ]]; then + retry 10 1 bria_cmd admin bootstrap + else + bria_cmd admin bootstrap + fi + + bria_cmd admin create-account -n default + if [[ "${BRIA_CONFIG}" == "docker" ]]; then + retry 10 1 bria_cmd import-xpub -n key1 -x tpubDCr5twyowBZhQZEdAXWeJgZtKZgGbKSY4Co55hgw551xCZtHk5fWw9EyGKDBE6cSZPzc4QWR4NyZAeuZDKvRHpQmch78CKwLSy8FEhbvBeR -d m/84h/0h/0h + retry 10 1 bria_cmd import-xpub -n key2 -x tpubDDDDGYiFda8HfJRc2AHFJDxVzzEtBPrKsbh35EaW2UGd5qfzrF2G87ewAgeeRyHEz4iB3kvhAYW1sH6dpLepTkFUzAktumBN8AXeXWE9nd1 -d m/84h/0h/0h + retry 10 1 bria_cmd create-wallet -n default sorted-multisig -x key1 key2 -t 1 + else + bria_cmd import-xpub -n key1 -x tpubDCr5twyowBZhQZEdAXWeJgZtKZgGbKSY4Co55hgw551xCZtHk5fWw9EyGKDBE6cSZPzc4QWR4NyZAeuZDKvRHpQmch78CKwLSy8FEhbvBeR -d m/84h/0h/0h + bria_cmd import-xpub -n key2 -x tpubDDDDGYiFda8HfJRc2AHFJDxVzzEtBPrKsbh35EaW2UGd5qfzrF2G87ewAgeeRyHEz4iB3kvhAYW1sH6dpLepTkFUzAktumBN8AXeXWE9nd1 -d m/84h/0h/0h + bria_cmd create-wallet -n default sorted-multisig -x key1 key2 -t 1 + fi + + echo "Bria Initialization Complete" +} + + # Run the given command in the background. Useful for starting a # node and then moving on with commands that exercise it for the diff --git a/tests/e2e/multisig_payout.bats b/tests/e2e/multisig_payout.bats new file mode 100644 index 00000000..f129646d --- /dev/null +++ b/tests/e2e/multisig_payout.bats @@ -0,0 +1,125 @@ +#!/usr/bin/env bats + +load "helpers" + +setup_file() { + restart_bitcoin_stack + reset_pg + bitcoind_init + start_daemon + bria_multisig_init +} + +teardown_file() { + stop_daemon +} + +@test "multisig_payout: Fund an address and see if the balance is reflected" { + bria_address=$(bria_cmd new-address -w default | jq -r '.address') + if [ -z "$bria_address" ]; then + echo "Failed to get a new address" + exit 1 + fi + + bitcoin_cli -regtest sendtoaddress ${bria_address} 1 + bitcoin_cli -regtest sendtoaddress ${bria_address} 1 + + for i in {1..30}; do + n_utxos=$(bria_cmd list-utxos -w default | jq '.keychains[0].utxos | length') + [[ "${n_utxos}" == "2" ]] && break + sleep 1 + done + cache_default_wallet_balance + [[ $(cached_encumbered_fees) != 0 ]] || exit 1 + [[ $(cached_pending_income) == 200000000 ]] || exit 1; +} + +@test "mutlisig_payout: Create payout queue and have two queued payouts on it" { + bria_cmd create-payout-queue --name high --interval-trigger 5 + bria_cmd submit-payout --wallet default --queue-name high --destination bcrt1q208tuy5rd3kvy8xdpv6yrczg7f3mnlk3lql7ej --amount 75000000 + bria_cmd submit-payout --wallet default --queue-name high --destination bcrt1q3rr02wkkvkwcj7h0nr9dqr9z3z3066pktat7kv --amount 75000000 --metadata '{"foo":{"bar":"baz"}}' + + n_payouts=$(bria_cmd list-payouts -w default | jq '.payouts | length') + [[ "${n_payouts}" == "2" ]] || exit 1 + batch_id=$(bria_cmd list-payouts -w default | jq '.payouts[0].batchId') + [[ "${batch_id}" == "null" ]] || exit 1 + cache_default_wallet_balance + [[ $(cached_encumbered_outgoing) == 150000000 && $(cached_pending_outgoing) == 0 ]] || exit 1 +} + +@test "multisig_payout: Settling income means batch is created" { + bitcoin_cli -generate 20 + + for i in {1..30}; do + utxo_height=$(bria_cmd list-utxos -w default | jq '.keychains[0].utxos[0].blockHeight') + [[ "${utxo_height}" != "null" ]] && break; + sleep 1 + done + cache_default_wallet_balance + [[ $(cached_pending_income) == 0 ]] || exit 1 + + for i in {1..20}; do + batch_id=$(bria_cmd list-payouts -w default | jq -r '.payouts[0].batchId') + [[ "${batch_id}" != "null" ]] && break + sleep 1 + done + [[ "${batch_id}" != "null" ]] || exit 1 + for i in {1..60}; do + cache_default_wallet_balance + [[ $(cached_pending_outgoing) == 150000000 ]] && break; + sleep 1 + done + + [[ $(cached_pending_outgoing) == 150000000 ]] || exit 1 + [[ $(cached_pending_fees) != 0 ]] || exit 1 + [[ $(cached_encumbered_fees) == 0 ]] || exit 1 +} + +@test "multisig_payout: Add signing config to complete payout" { + batch_id=$(bria_cmd list-payouts -w default | jq -r '.payouts[0].batchId') + for i in {1..20}; do + signing_failure_reason=$(bria_cmd get-batch -b "${batch_id}" | jq -r '.signingSessions[0].failureReason') + [[ "${signing_failure_reason}" == "SignerConfigMissing" ]] && break + sleep 1 + done + + [[ "${signing_failure_reason}" == "SignerConfigMissing" ]] || exit 1 + + cache_default_wallet_balance + [[ $(cached_pending_income) == 0 ]] || exit 1 + + bria_cmd set-signer-config \ + --xpub "68bfb290" bitcoind \ + --endpoint "${BITCOIND_SIGNER_ENDPOINT}" \ + --rpc-user "rpcuser" \ + --rpc-password "rpcpassword" + + for i in {1..20}; do + signing_status=$(bria_cmd list-signing-sessions -b "${batch_id}" | jq -r '.sessions[0].state') + [[ "${signing_status}" == "Complete" ]] && break + sleep 1 + done + if [[ "${signing_status}" != "Complete" ]]; then + signing_failure_reason=$(bria_cmd list-signing-sessions -b "${batch_id}" | jq -r '.sessions[0].failureReason') + echo "signing_status: ${signing_status}" + echo "signing_failure_reason: ${signing_failure_reason}" + fi + + for i in {1..20}; do + cache_default_wallet_balance + [[ $(cached_pending_income) != 0 ]] && break; + sleep 1 + done + + [[ $(cached_pending_income) != 0 ]] || exit 1 + [[ $(cached_current_settled) == 0 ]] || exit 1 + bitcoin_cli -generate 2 + + for i in {1..20}; do + cache_default_wallet_balance + [[ $(cached_current_settled) != 0 ]] && break; + sleep 1 + done + + [[ $(cached_current_settled) != 0 ]] || exit 1; +} From 04e40485b190a83e494dab293285e41ef4a34a03 Mon Sep 17 00:00:00 2001 From: Vaibhav Date: Fri, 30 Jun 2023 18:15:09 +0530 Subject: [PATCH 09/26] chore: fix naming --- src/app/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/mod.rs b/src/app/mod.rs index 5b7cd9cf..ba4432d7 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -283,7 +283,7 @@ impl App { self.create_wallet(profile, wallet_name, keychain).await } - #[instrument(name = "app.create_sortedmulti_wallet", skip(self), err)] + #[instrument(name = "app.create_sorted_multisig_wallet", skip(self), err)] pub async fn create_sorted_multisig_wallet( &self, profile: Profile, From 01398e4e914c96d1d1c17f29da3bfdc101b14d05 Mon Sep 17 00:00:00 2001 From: Vaibhav Date: Sat, 1 Jul 2023 00:39:44 +0530 Subject: [PATCH 10/26] chore: address pr reviews --- src/api/server/convert.rs | 12 ++++++++++++ src/app/error.rs | 2 -- src/cli/mod.rs | 2 +- src/job/batch_signing.rs | 26 ++++++++++++++++++++------ 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/api/server/convert.rs b/src/api/server/convert.rs index f8fc6ee9..e4cd6a23 100644 --- a/src/api/server/convert.rs +++ b/src/api/server/convert.rs @@ -597,6 +597,18 @@ impl From for tonic::Status { ApplicationError::DestinationBlocked(_) => { tonic::Status::permission_denied(err.to_string()) } + ApplicationError::SigningSessionNotFoundForBatchId(_) => { + tonic::Status::not_found(err.to_string()) + } + ApplicationError::SigningSessionNotFoundForXPubId(_) => { + tonic::Status::not_found(err.to_string()) + } + ApplicationError::SubmittedPsbtIsNotValid => { + tonic::Status::invalid_argument(err.to_string()) + } + ApplicationError::CouldNotParseIncomingPsbt(_) => { + tonic::Status::invalid_argument(err.to_string()) + } _ => tonic::Status::internal(err.to_string()), } } diff --git a/src/app/error.rs b/src/app/error.rs index 99a52391..1ca49a5a 100644 --- a/src/app/error.rs +++ b/src/app/error.rs @@ -61,8 +61,6 @@ pub enum ApplicationError { CouldNotParseIncomingMetadata(serde_json::Error), #[error("CouldNotParseIncomingUuid: {0}")] CouldNotParseIncomingUuid(uuid::Error), - #[error("CouldNotParseIncomingXpubId: {0}")] - CouldNotParseIncomingXpubId(::Err), #[error("DestinationBlocked - sending to '{0}' is prohibited")] DestinationBlocked(PayoutDestination), #[error("Signing Session not found for batch id: {0}")] diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 30b0d9f3..76d36bf9 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -573,7 +573,7 @@ enum CreateWalletCommand { change_descriptor: String, }, SortedMultisig { - #[clap(short, long, num_args(2..) )] + #[clap(short, long, num_args(2..=15) )] xpub: Vec, #[clap(short, long)] threshold: u32, diff --git a/src/job/batch_signing.rs b/src/job/batch_signing.rs index 8fd25f2d..bb865717 100644 --- a/src/job/batch_signing.rs +++ b/src/job/batch_signing.rs @@ -33,6 +33,8 @@ pub async fn execute( xpubs: XPubs, signer_encryption_config: SignerEncryptionConfig, ) -> Result<(BatchSigningData, bool), JobError> { + let mut stalled = false; + let mut last_err = None; let mut current_keychain = None; let (mut sessions, mut account_xpub_cache) = if let Some(batch_session) = signing_sessions .list_for_batch(data.account_id, data.batch_id) @@ -92,12 +94,14 @@ pub async fn execute( Ok(Some(client)) => client, Ok(None) => { session.attempt_failed(SigningFailureReason::SignerConfigMissing); + stalled = true; tracing::warn!("signer_config_missing"); continue; } Err(err) => { session.attempt_failed(&err); tracing::error!("{}", err.to_string()); + last_err = Some(err); continue; } }; @@ -108,6 +112,7 @@ pub async fn execute( Err(err) => { session.attempt_failed(&err); tracing::error!("{}", err.to_string()); + last_err = Some(err); continue; } } @@ -133,13 +138,22 @@ pub async fn execute( let wallet = wallets.find_by_id(wallet_id).await?; current_keychain = Some(wallet.current_keychain_wallet(&pool)); } - let tx = current_keychain - .unwrap() + match current_keychain + .expect("keychain should always exist") .finalize_psbt(first_signed_psbt) - .await? - .extract_tx(); - batches.set_signed_tx(data.batch_id, tx).await?; - Ok((data, true)) + .await + { + Ok(finalized_psbt) => { + let tx = finalized_psbt.extract_tx(); + batches.set_signed_tx(data.batch_id, tx).await?; + Ok((data, true)) + } + Err(err) => match last_err { + Some(e) => Err(e.into()), + None if stalled => Ok((data, false)), + None => Err(err.into()), + }, + } } else { Ok((data, false)) } From d94e4b1e2b70b8cd1757494437994f47a48ffbc2 Mon Sep 17 00:00:00 2001 From: bodymindarts Date: Fri, 30 Jun 2023 21:18:40 +0200 Subject: [PATCH 11/26] refactor: flatten match in batch_signing --- src/job/batch_signing.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/job/batch_signing.rs b/src/job/batch_signing.rs index bb865717..4d6dc9f7 100644 --- a/src/job/batch_signing.rs +++ b/src/job/batch_signing.rs @@ -125,11 +125,11 @@ pub async fn execute( } let mut sessions = sessions.into_values(); if let Some(mut first_signed_psbt) = sessions.find_map(|s| s.signed_psbt().cloned()) { - sessions.for_each(|s| { + for s in sessions { if let Some(psbt) = s.signed_psbt() { let _ = first_signed_psbt.combine(psbt.clone()); } - }); + } if current_keychain.is_none() { let batch = batches.find_by_id(data.account_id, data.batch_id).await?; let span = tracing::Span::current(); @@ -138,21 +138,21 @@ pub async fn execute( let wallet = wallets.find_by_id(wallet_id).await?; current_keychain = Some(wallet.current_keychain_wallet(&pool)); } - match current_keychain - .expect("keychain should always exist") - .finalize_psbt(first_signed_psbt) - .await - { - Ok(finalized_psbt) => { + match ( + current_keychain + .expect("keychain should always exist") + .finalize_psbt(first_signed_psbt) + .await, + last_err, + ) { + (Ok(finalized_psbt), _) => { let tx = finalized_psbt.extract_tx(); batches.set_signed_tx(data.batch_id, tx).await?; Ok((data, true)) } - Err(err) => match last_err { - Some(e) => Err(e.into()), - None if stalled => Ok((data, false)), - None => Err(err.into()), - }, + (_, Some(e)) => Err(e.into()), + _ if stalled => Ok((data, false)), + (Err(err), _) => Err(err.into()), } } else { Ok((data, false)) From 326a5858a632bcb13aa9ede44f6475665c834449 Mon Sep 17 00:00:00 2001 From: Vaibhav Date: Mon, 3 Jul 2023 12:48:28 +0530 Subject: [PATCH 12/26] chore: add e2e test for multisig signing --- .../bitcoind_multisig_signer_descriptors.json | 1 + tests/e2e/multisig_payout.bats | 59 ++++++++++--------- 2 files changed, 33 insertions(+), 27 deletions(-) create mode 100644 tests/e2e/bitcoind_multisig_signer_descriptors.json diff --git a/tests/e2e/bitcoind_multisig_signer_descriptors.json b/tests/e2e/bitcoind_multisig_signer_descriptors.json new file mode 100644 index 00000000..8fd0d47a --- /dev/null +++ b/tests/e2e/bitcoind_multisig_signer_descriptors.json @@ -0,0 +1 @@ +[{"active":true,"desc":"wsh(sortedmulti(1,[186ad0c4/48h/1h/0h/2h]tprv8hSFJixpqu9HoqftuhrSgZ2GQhn2vHpt4xvWSwHsUdgV2xuMFygngWVF8kxdGr983KngUHsuw3onLZZCivCHRg398cVd65TQxe8mjd467Qz/0/*,[72d14a88/48h/1h/0h/2h]tpubDF2UP3xmRcJoi5LDYZKVoUj6MsaUrcPiTgV7Q2b8eWtnSsM3EhFeszEiG9iTU7Gixzym4a1F2T6gSp59y7iZrtTKZRAw6fqzbevphHxBzGz/0/*))#gm0myh0z","timestamp":0},{"active":true,"desc":"wsh(sortedmulti(1,[186ad0c4/48h/1h/0h/2h]tprv8hSFJixpqu9HoqftuhrSgZ2GQhn2vHpt4xvWSwHsUdgV2xuMFygngWVF8kxdGr983KngUHsuw3onLZZCivCHRg398cVd65TQxe8mjd467Qz/1/*,[72d14a88/48h/1h/0h/2h]tpubDF2UP3xmRcJoi5LDYZKVoUj6MsaUrcPiTgV7Q2b8eWtnSsM3EhFeszEiG9iTU7Gixzym4a1F2T6gSp59y7iZrtTKZRAw6fqzbevphHxBzGz/1/*))#3gul2y6h","internal":true,"timestamp":0}] diff --git a/tests/e2e/multisig_payout.bats b/tests/e2e/multisig_payout.bats index f129646d..4cb9ac30 100644 --- a/tests/e2e/multisig_payout.bats +++ b/tests/e2e/multisig_payout.bats @@ -5,9 +5,9 @@ load "helpers" setup_file() { restart_bitcoin_stack reset_pg - bitcoind_init + bitcoind_init multisig start_daemon - bria_multisig_init + bria_init multisig } teardown_file() { @@ -15,7 +15,8 @@ teardown_file() { } @test "multisig_payout: Fund an address and see if the balance is reflected" { - bria_address=$(bria_cmd new-address -w default | jq -r '.address') + bria_address=$(bria_cmd new-address -w multisig | jq -r '.address') + if [ -z "$bria_address" ]; then echo "Failed to get a new address" exit 1 @@ -25,25 +26,27 @@ teardown_file() { bitcoin_cli -regtest sendtoaddress ${bria_address} 1 for i in {1..30}; do - n_utxos=$(bria_cmd list-utxos -w default | jq '.keychains[0].utxos | length') + n_utxos=$(bria_cmd list-utxos -w multisig | jq '.keychains[0].utxos | length') [[ "${n_utxos}" == "2" ]] && break sleep 1 done - cache_default_wallet_balance + + cache_wallet_balance multisig [[ $(cached_encumbered_fees) != 0 ]] || exit 1 [[ $(cached_pending_income) == 200000000 ]] || exit 1; } @test "mutlisig_payout: Create payout queue and have two queued payouts on it" { bria_cmd create-payout-queue --name high --interval-trigger 5 - bria_cmd submit-payout --wallet default --queue-name high --destination bcrt1q208tuy5rd3kvy8xdpv6yrczg7f3mnlk3lql7ej --amount 75000000 - bria_cmd submit-payout --wallet default --queue-name high --destination bcrt1q3rr02wkkvkwcj7h0nr9dqr9z3z3066pktat7kv --amount 75000000 --metadata '{"foo":{"bar":"baz"}}' + bria_cmd submit-payout --wallet multisig --queue-name high --destination bcrt1q208tuy5rd3kvy8xdpv6yrczg7f3mnlk3lql7ej --amount 75000000 + bria_cmd submit-payout --wallet multisig --queue-name high --destination bcrt1q3rr02wkkvkwcj7h0nr9dqr9z3z3066pktat7kv --amount 75000000 --metadata '{"foo":{"bar":"baz"}}' - n_payouts=$(bria_cmd list-payouts -w default | jq '.payouts | length') + n_payouts=$(bria_cmd list-payouts -w multisig | jq '.payouts | length') [[ "${n_payouts}" == "2" ]] || exit 1 - batch_id=$(bria_cmd list-payouts -w default | jq '.payouts[0].batchId') + batch_id=$(bria_cmd list-payouts -w multisig | jq '.payouts[0].batchId') [[ "${batch_id}" == "null" ]] || exit 1 - cache_default_wallet_balance + + cache_wallet_balance multisig [[ $(cached_encumbered_outgoing) == 150000000 && $(cached_pending_outgoing) == 0 ]] || exit 1 } @@ -51,21 +54,23 @@ teardown_file() { bitcoin_cli -generate 20 for i in {1..30}; do - utxo_height=$(bria_cmd list-utxos -w default | jq '.keychains[0].utxos[0].blockHeight') + utxo_height=$(bria_cmd list-utxos -w multisig | jq '.keychains[0].utxos[0].blockHeight') [[ "${utxo_height}" != "null" ]] && break; sleep 1 done - cache_default_wallet_balance + + cache_wallet_balance multisig [[ $(cached_pending_income) == 0 ]] || exit 1 for i in {1..20}; do - batch_id=$(bria_cmd list-payouts -w default | jq -r '.payouts[0].batchId') + batch_id=$(bria_cmd list-payouts -w multisig | jq -r '.payouts[0].batchId') [[ "${batch_id}" != "null" ]] && break sleep 1 done + [[ "${batch_id}" != "null" ]] || exit 1 for i in {1..60}; do - cache_default_wallet_balance + cache_wallet_balance multisig [[ $(cached_pending_outgoing) == 150000000 ]] && break; sleep 1 done @@ -75,8 +80,9 @@ teardown_file() { [[ $(cached_encumbered_fees) == 0 ]] || exit 1 } -@test "multisig_payout: Add signing config to complete payout" { - batch_id=$(bria_cmd list-payouts -w default | jq -r '.payouts[0].batchId') +@test "multisig_payout: Signing unsigned psbt and submitting signed psbt" { + batch_id=$(bria_cmd list-payouts -w multisig | jq -r '.payouts[0].batchId') + for i in {1..20}; do signing_failure_reason=$(bria_cmd get-batch -b "${batch_id}" | jq -r '.signingSessions[0].failureReason') [[ "${signing_failure_reason}" == "SignerConfigMissing" ]] && break @@ -85,28 +91,27 @@ teardown_file() { [[ "${signing_failure_reason}" == "SignerConfigMissing" ]] || exit 1 - cache_default_wallet_balance + cache_wallet_balance multisig [[ $(cached_pending_income) == 0 ]] || exit 1 - bria_cmd set-signer-config \ - --xpub "68bfb290" bitcoind \ - --endpoint "${BITCOIND_SIGNER_ENDPOINT}" \ - --rpc-user "rpcuser" \ - --rpc-password "rpcpassword" - + unsigned_psbt=$(bria_cmd get-batch -b "${batch_id}" | jq -r '.unsignedPsbt') + signed_psbt=$(bitcoin_signer_cli walletprocesspsbt "${unsigned_psbt}" true ALL true | jq -r '.psbt') + bria_cmd submit-signed-psbt -b "${batch_id}" -x key1 -s "${signed_psbt}" + for i in {1..20}; do - signing_status=$(bria_cmd list-signing-sessions -b "${batch_id}" | jq -r '.sessions[0].state') + signing_status=$(bria_cmd get-batch -b "${batch_id}" | jq -r '.sessions[0].state') [[ "${signing_status}" == "Complete" ]] && break sleep 1 done + if [[ "${signing_status}" != "Complete" ]]; then - signing_failure_reason=$(bria_cmd list-signing-sessions -b "${batch_id}" | jq -r '.sessions[0].failureReason') + signing_failure_reason=$(bria_cmd get-batch -b "${batch_id}" | jq -r '.signingSessions[0].failureReason') echo "signing_status: ${signing_status}" echo "signing_failure_reason: ${signing_failure_reason}" fi for i in {1..20}; do - cache_default_wallet_balance + cache_wallet_balance multisig [[ $(cached_pending_income) != 0 ]] && break; sleep 1 done @@ -116,7 +121,7 @@ teardown_file() { bitcoin_cli -generate 2 for i in {1..20}; do - cache_default_wallet_balance + cache_wallet_balance multisig [[ $(cached_current_settled) != 0 ]] && break; sleep 1 done From f00063222ff58b61037bbf2f221ec042f3aab6db Mon Sep 17 00:00:00 2001 From: Vaibhav Date: Mon, 3 Jul 2023 12:50:42 +0530 Subject: [PATCH 13/26] chore: parameterize functions --- tests/e2e/bitcoind_sync.bats | 26 +++++++------- tests/e2e/helpers.bash | 70 +++++++++++++++++++----------------- tests/e2e/lnd_sync.bats | 20 +++++------ tests/e2e/outbox.bats | 8 ++--- tests/e2e/payout.bats | 22 ++++++------ 5 files changed, 76 insertions(+), 70 deletions(-) diff --git a/tests/e2e/bitcoind_sync.bats b/tests/e2e/bitcoind_sync.bats index 8c78fa54..8e11d7a9 100644 --- a/tests/e2e/bitcoind_sync.bats +++ b/tests/e2e/bitcoind_sync.bats @@ -5,9 +5,9 @@ load "helpers" setup_file() { restart_bitcoin_stack reset_pg - bitcoind_init + bitcoind_init default start_daemon - bria_init + bria_init default } teardown_file() { @@ -34,7 +34,7 @@ teardown_file() { bitcoin_cli -regtest sendtoaddress ${bitcoind_signer_address} 1 for i in {1..30}; do - cache_default_wallet_balance + cache_wallet_balance default [[ $(cached_pending_income) == 100000000 ]] && break sleep 1 done @@ -51,7 +51,7 @@ teardown_file() { bitcoin_cli -generate 2 for i in {1..30}; do - cache_default_wallet_balance + cache_wallet_balance default [[ $(cached_current_settled) == 100000000 ]] && break sleep 1 done @@ -68,7 +68,7 @@ teardown_file() { bitcoind_address=$(bitcoin_cli -regtest getnewaddress) bitcoin_signer_cli -regtest sendtoaddress "${bitcoind_address}" 0.5 for i in {1..30}; do - cache_default_wallet_balance + cache_wallet_balance default [[ $(cached_pending_outgoing) == 50000000 ]] && break sleep 1 done @@ -84,7 +84,7 @@ teardown_file() { bitcoin_cli -generate 1 for i in {1..30}; do - cache_default_wallet_balance + cache_wallet_balance default [[ $(cached_current_settled) != 0 ]] && break sleep 1 done @@ -119,7 +119,7 @@ teardown_file() { ${bitcoind_address} for i in {1..30}; do - cache_default_wallet_balance + cache_wallet_balance default [[ $(cached_pending_outgoing) == 210000000 ]] && break sleep 1 done @@ -128,7 +128,7 @@ teardown_file() { bitcoin_cli -generate 2 for i in {1..30}; do - cache_default_wallet_balance + cache_wallet_balance default [[ $(cached_pending_outgoing) == 0 ]] && break sleep 1 done @@ -142,13 +142,13 @@ teardown_file() { } @test "bitcoind_signer_sync: Can sweep all" { - cache_default_wallet_balance + cache_wallet_balance default [[ $(cached_current_settled) != 0 ]] || exit 1 bitcoind_address=$(bitcoin_cli -regtest getnewaddress) bitcoin_signer_cli -named sendall recipients="[\"${bitcoind_address}\"]" fee_rate=1 for i in {1..10}; do - cache_default_wallet_balance + cache_wallet_balance default [[ $(cached_current_settled) == 0 ]] \ && [[ $(cached_pending_outgoing) != 0 ]] \ && break @@ -160,7 +160,7 @@ teardown_file() { bitcoin_cli -generate 1 for i in {1..30}; do - cache_default_wallet_balance + cache_wallet_balance default [[ $(cached_pending_outgoing) == 0 ]] \ && [[ $(cached_encumbered_fees) == 0 ]] \ && break @@ -186,7 +186,7 @@ teardown_file() { ${bitcoind_address} for i in {1..30}; do - cache_default_wallet_balance + cache_wallet_balance default [[ $(cached_pending_outgoing) == 60000000 ]] && break sleep 1 done @@ -195,7 +195,7 @@ teardown_file() { bitcoin_cli -generate 2 for i in {1..30}; do - cache_default_wallet_balance + cache_wallet_balance default [[ $(cached_pending_outgoing) == 0 ]] && break sleep 1 done diff --git a/tests/e2e/helpers.bash b/tests/e2e/helpers.bash index a3d1428c..009f964c 100644 --- a/tests/e2e/helpers.bash +++ b/tests/e2e/helpers.bash @@ -17,8 +17,9 @@ bria_cmd() { ${bria_location} $@ } -cache_default_wallet_balance() { - balance=$(bria_cmd wallet-balance -w default) +cache_wallet_balance() { + local wallet_name="${1}" + balance=$(bria_cmd wallet-balance -w "${wallet_name}") } cached_pending_income() { @@ -95,11 +96,18 @@ restart_bitcoin_stack() { } bitcoind_init() { - bitcoin_cli createwallet "default" || true - bitcoin_cli -generate 200 + local wallet="${1}" - bitcoin_signer_cli createwallet "default" || true - bitcoin_signer_cli -rpcwallet=default importdescriptors "$(cat ${REPO_ROOT}/tests/e2e/bitcoind_signer_descriptors.json)" + bitcoin_cli createwallet "default" || true + bitcoin_cli generatetoaddress 200 "$(bitcoin_cli getnewaddress)" + + if [[ "${wallet}" == "default" ]]; then + bitcoin_signer_cli createwallet "default" || true + bitcoin_signer_cli -rpcwallet=default importdescriptors "$(cat ${REPO_ROOT}/tests/e2e/bitcoind_signer_descriptors.json)" + elif [[ "${wallet}" == "multisig" ]]; then + bitcoin_signer_cli createwallet "multisig" || true + bitcoin_signer_cli -rpcwallet=multisig importdescriptors "$(cat ${REPO_ROOT}/tests/e2e/bitcoind_multisig_signer_descriptors.json)" + fi } start_daemon() { @@ -114,6 +122,8 @@ stop_daemon() { } bria_init() { + local wallet_type="${1}" + if [[ "${BRIA_CONFIG}" == "docker" ]]; then retry 10 1 bria_cmd admin bootstrap else @@ -121,10 +131,28 @@ bria_init() { fi bria_cmd admin create-account -n default - if [[ "${BRIA_CONFIG}" == "docker" ]]; then - retry 10 1 bria_cmd create-wallet -n default descriptors -d "wpkh([6f2fa1b2/84'/0'/0']tpubDDDDGYiFda8HfJRc2AHFJDxVzzEtBPrKsbh35EaW2UGd5qfzrF2G87ewAgeeRyHEz4iB3kvhAYW1sH6dpLepTkFUzAktumBN8AXeXWE9nd1/0/*)#l6n08zmr" -c "wpkh([6f2fa1b2/84'/0'/0']tpubDDDDGYiFda8HfJRc2AHFJDxVzzEtBPrKsbh35EaW2UGd5qfzrF2G87ewAgeeRyHEz4iB3kvhAYW1sH6dpLepTkFUzAktumBN8AXeXWE9nd1/1/*)#wwkw6htm" - else - bria_cmd create-wallet -n default descriptors -d "wpkh([6f2fa1b2/84'/0'/0']tpubDDDDGYiFda8HfJRc2AHFJDxVzzEtBPrKsbh35EaW2UGd5qfzrF2G87ewAgeeRyHEz4iB3kvhAYW1sH6dpLepTkFUzAktumBN8AXeXWE9nd1/0/*)#l6n08zmr" -c "wpkh([6f2fa1b2/84'/0'/0']tpubDDDDGYiFda8HfJRc2AHFJDxVzzEtBPrKsbh35EaW2UGd5qfzrF2G87ewAgeeRyHEz4iB3kvhAYW1sH6dpLepTkFUzAktumBN8AXeXWE9nd1/1/*)#wwkw6htm" + + if [[ "${wallet_type}" == "default" ]]; then + if [[ "${BRIA_CONFIG}" == "docker" ]]; then + retry 10 1 bria_cmd create-wallet -n default descriptors -d "wpkh([6f2fa1b2/84'/0'/0']tpubDDDDGYiFda8HfJRc2AHFJDxVzzEtBPrKsbh35EaW2UGd5qfzrF2G87ewAgeeRyHEz4iB3kvhAYW1sH6dpLepTkFUzAktumBN8AXeXWE9nd1/0/*)#l6n08zmr" \ + -c "wpkh([6f2fa1b2/84'/0'/0']tpubDDDDGYiFda8HfJRc2AHFJDxVzzEtBPrKsbh35EaW2UGd5qfzrF2G87ewAgeeRyHEz4iB3kvhAYW1sH6dpLepTkFUzAktumBN8AXeXWE9nd1/1/*)#wwkw6htm" + else + bria_cmd create-wallet -n default descriptors -d "wpkh([6f2fa1b2/84'/0'/0']tpubDDDDGYiFda8HfJRc2AHFJDxVzzEtBPrKsbh35EaW2UGd5qfzrF2G87ewAgeeRyHEz4iB3kvhAYW1sH6dpLepTkFUzAktumBN8AXeXWE9nd1/0/*)#l6n08zmr" \ + -c "wpkh([6f2fa1b2/84'/0'/0']tpubDDDDGYiFda8HfJRc2AHFJDxVzzEtBPrKsbh35EaW2UGd5qfzrF2G87ewAgeeRyHEz4iB3kvhAYW1sH6dpLepTkFUzAktumBN8AXeXWE9nd1/1/*)#wwkw6htm" + fi + elif [[ "${wallet_type}" == "multisig" ]]; then + local key1="tpubDE8HT914zGpxhJhgoMX35xgNyjHy5d1neGXHjTLAtuUssTA7tNWNs177JsFPbJwD5FBXCHJYbwUC9AzSEpYHC4hKgaCvZyZTuCbWfNUWXoM" + local key2="tpubDF2UP3xmRcJoi5LDYZKVoUj6MsaUrcPiTgV7Q2b8eWtnSsM3EhFeszEiG9iTU7Gixzym4a1F2T6gSp59y7iZrtTKZRAw6fqzbevphHxBzGz" + + if [[ "${BRIA_CONFIG}" == "docker" ]]; then + retry 10 1 bria_cmd import-xpub -x "${key1}" -n key1 -d m/48h/1h/0h/2h + bria_cmd import-xpub -x "${key2}" -n key2 -d m/48h/1h/0h/2h + bria_cmd create-wallet -n multisig sorted-multisig -x key1 key2 -t 1 + else + bria_cmd import-xpub -x "${key1}" -n key1 -d m/48h/1h/0h/2h + bria_cmd import-xpub -x "${key2}" -n key2 -d m/48h/1h/0h/2h + bria_cmd create-wallet -n multisig sorted-multisig -x key1 key2 -t 1 + fi fi echo "Bria Initialization Complete" @@ -139,28 +167,6 @@ bria_lnd_init() { echo "Bria Initialization Complete" } -bria_multisig_init() { - if [[ "${BRIA_CONFIG}" == "docker" ]]; then - retry 10 1 bria_cmd admin bootstrap - else - bria_cmd admin bootstrap - fi - - bria_cmd admin create-account -n default - if [[ "${BRIA_CONFIG}" == "docker" ]]; then - retry 10 1 bria_cmd import-xpub -n key1 -x tpubDCr5twyowBZhQZEdAXWeJgZtKZgGbKSY4Co55hgw551xCZtHk5fWw9EyGKDBE6cSZPzc4QWR4NyZAeuZDKvRHpQmch78CKwLSy8FEhbvBeR -d m/84h/0h/0h - retry 10 1 bria_cmd import-xpub -n key2 -x tpubDDDDGYiFda8HfJRc2AHFJDxVzzEtBPrKsbh35EaW2UGd5qfzrF2G87ewAgeeRyHEz4iB3kvhAYW1sH6dpLepTkFUzAktumBN8AXeXWE9nd1 -d m/84h/0h/0h - retry 10 1 bria_cmd create-wallet -n default sorted-multisig -x key1 key2 -t 1 - else - bria_cmd import-xpub -n key1 -x tpubDCr5twyowBZhQZEdAXWeJgZtKZgGbKSY4Co55hgw551xCZtHk5fWw9EyGKDBE6cSZPzc4QWR4NyZAeuZDKvRHpQmch78CKwLSy8FEhbvBeR -d m/84h/0h/0h - bria_cmd import-xpub -n key2 -x tpubDDDDGYiFda8HfJRc2AHFJDxVzzEtBPrKsbh35EaW2UGd5qfzrF2G87ewAgeeRyHEz4iB3kvhAYW1sH6dpLepTkFUzAktumBN8AXeXWE9nd1 -d m/84h/0h/0h - bria_cmd create-wallet -n default sorted-multisig -x key1 key2 -t 1 - fi - - echo "Bria Initialization Complete" -} - - # Run the given command in the background. Useful for starting a # node and then moving on with commands that exercise it for the diff --git a/tests/e2e/lnd_sync.bats b/tests/e2e/lnd_sync.bats index 33259122..35e990a3 100644 --- a/tests/e2e/lnd_sync.bats +++ b/tests/e2e/lnd_sync.bats @@ -5,7 +5,7 @@ load "helpers" setup_file() { restart_bitcoin_stack reset_pg - bitcoind_init + bitcoind_init default start_daemon bria_lnd_init } @@ -34,7 +34,7 @@ teardown_file() { bitcoin_cli -regtest sendtoaddress ${lnd_address} 1 for i in {1..30}; do - cache_default_wallet_balance + cache_wallet_balance default [[ $(cached_pending_income) == 100000000 ]] && break sleep 1 done @@ -51,7 +51,7 @@ teardown_file() { bitcoin_cli -generate 2 for i in {1..30}; do - cache_default_wallet_balance + cache_wallet_balance default [[ $(cached_current_settled) == 100000000 ]] && break sleep 1 done @@ -68,7 +68,7 @@ teardown_file() { bitcoind_address=$(bitcoin_cli -regtest getnewaddress) lnd_cli sendcoins --addr=${bitcoind_address} --amt=50000000 for i in {1..30}; do - cache_default_wallet_balance + cache_wallet_balance default [[ $(cached_pending_outgoing) == 50000000 ]] && break sleep 1 done @@ -84,7 +84,7 @@ teardown_file() { bitcoin_cli -generate 1 for i in {1..30}; do - cache_default_wallet_balance + cache_wallet_balance default [[ $(cached_current_settled) != 0 ]] && break sleep 1 done @@ -111,7 +111,7 @@ teardown_file() { lnd_cli sendcoins --addr=${bitcoind_address} --amt=210000000 --min_confs 0 for i in {1..30}; do - cache_default_wallet_balance + cache_wallet_balance default [[ $(cached_pending_outgoing) == 210000000 ]] && break sleep 1 done @@ -120,7 +120,7 @@ teardown_file() { bitcoin_cli -generate 2 for i in {1..30}; do - cache_default_wallet_balance + cache_wallet_balance default [[ $(cached_pending_outgoing) == 0 ]] && break sleep 1 done @@ -135,7 +135,7 @@ teardown_file() { bitcoin_cli -generate 1 for i in {1..30}; do - cache_default_wallet_balance + cache_wallet_balance default [[ $(cached_encumbered_fees) == 0 ]] && break sleep 1 done @@ -150,7 +150,7 @@ teardown_file() { lnd_cli sendcoins --addr=${bitcoind_address} --amt=60000000 --min_confs 0 for i in {1..30}; do - cache_default_wallet_balance + cache_wallet_balance default [[ $(cached_pending_outgoing) == 60000000 ]] && break sleep 1 done @@ -159,7 +159,7 @@ teardown_file() { bitcoin_cli -generate 2 for i in {1..30}; do - cache_default_wallet_balance + cache_wallet_balance default [[ $(cached_pending_outgoing) == 0 ]] && break sleep 1 done diff --git a/tests/e2e/outbox.bats b/tests/e2e/outbox.bats index 4d831c90..7dee5b7d 100644 --- a/tests/e2e/outbox.bats +++ b/tests/e2e/outbox.bats @@ -5,9 +5,9 @@ load "helpers" setup_file() { restart_bitcoin_stack reset_pg - bitcoind_init + bitcoind_init default start_daemon - bria_init + bria_init default } teardown_file() { @@ -24,7 +24,7 @@ teardown_file() { done event=$(bria_cmd watch-events -a 0 -o | jq -r '.payload.utxoDetected') [ "$event" != "null" ] || exit 1 - cache_default_wallet_balance + cache_wallet_balance default [[ $(cached_pending_income) == 100000000 ]] || exit 1; restart_bitcoin_stack @@ -33,7 +33,7 @@ teardown_file() { event=$(bria_cmd watch-events -a 1 -o | jq -r '.payload.utxoDropped') [ "$event" != "null" ] || exit 1 - cache_default_wallet_balance + cache_wallet_balance default [[ $(cached_pending_income) == 0 ]] || exit 1; } diff --git a/tests/e2e/payout.bats b/tests/e2e/payout.bats index 8cd7d001..b846a52d 100644 --- a/tests/e2e/payout.bats +++ b/tests/e2e/payout.bats @@ -5,9 +5,9 @@ load "helpers" setup_file() { restart_bitcoin_stack reset_pg - bitcoind_init + bitcoind_init default start_daemon - bria_init + bria_init default } teardown_file() { @@ -29,7 +29,7 @@ teardown_file() { [[ "${n_utxos}" == "2" ]] && break sleep 1 done - cache_default_wallet_balance + cache_wallet_balance default [[ $(cached_encumbered_fees) != 0 ]] || exit 1 [[ $(cached_pending_income) == 200000000 ]] || exit 1; } @@ -43,7 +43,7 @@ teardown_file() { [[ "${n_payouts}" == "2" ]] || exit 1 batch_id=$(bria_cmd list-payouts -w default | jq '.payouts[0].batchId') [[ "${batch_id}" == "null" ]] || exit 1 - cache_default_wallet_balance + cache_wallet_balance default [[ $(cached_encumbered_outgoing) == 150000000 && $(cached_pending_outgoing) == 0 ]] || exit 1 } @@ -55,7 +55,7 @@ teardown_file() { [[ "${utxo_height}" != "null" ]] && break; sleep 1 done - cache_default_wallet_balance + cache_wallet_balance default [[ $(cached_pending_income) == 0 ]] || exit 1 for i in {1..20}; do @@ -65,7 +65,7 @@ teardown_file() { done [[ "${batch_id}" != "null" ]] || exit 1 for i in {1..60}; do - cache_default_wallet_balance + cache_wallet_balance default [[ $(cached_pending_outgoing) == 150000000 ]] && break; sleep 1 done @@ -85,7 +85,7 @@ teardown_file() { [[ "${signing_failure_reason}" == "SignerConfigMissing" ]] || exit 1 - cache_default_wallet_balance + cache_wallet_balance default [[ $(cached_pending_income) == 0 ]] || exit 1 bria_cmd set-signer-config \ @@ -95,18 +95,18 @@ teardown_file() { --rpc-password "rpcpassword" for i in {1..20}; do - signing_status=$(bria_cmd list-signing-sessions -b "${batch_id}" | jq -r '.sessions[0].state') + signing_status=$(bria_cmd get-batch -b "${batch_id}" | jq -r '.signingSessions[0].state') [[ "${signing_status}" == "Complete" ]] && break sleep 1 done if [[ "${signing_status}" != "Complete" ]]; then - signing_failure_reason=$(bria_cmd list-signing-sessions -b "${batch_id}" | jq -r '.sessions[0].failureReason') + signing_failure_reason=$(bria_cmd get-batch -b "${batch_id}" | jq -r '.signingSessions[0].failureReason') echo "signing_status: ${signing_status}" echo "signing_failure_reason: ${signing_failure_reason}" fi for i in {1..20}; do - cache_default_wallet_balance + cache_wallet_balance default [[ $(cached_pending_income) != 0 ]] && break; sleep 1 done @@ -116,7 +116,7 @@ teardown_file() { bitcoin_cli -generate 2 for i in {1..20}; do - cache_default_wallet_balance + cache_wallet_balance default [[ $(cached_current_settled) != 0 ]] && break; sleep 1 done From 52869ef3b2314878b781c6b26cc38e7c103177df Mon Sep 17 00:00:00 2001 From: Vaibhav Date: Mon, 3 Jul 2023 12:52:08 +0530 Subject: [PATCH 14/26] chore: change psbt_validator logic --- src/app/mod.rs | 8 +++-- src/wallet/psbt_validator.rs | 61 +++++++++++++++++------------------- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/src/app/mod.rs b/src/app/mod.rs index ba4432d7..f73ebc8d 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -223,8 +223,12 @@ impl App { ) .await?; let xpub_id = xpub.id(); - let xpub = xpub.value; - if !psbt_validator::validate_psbt(&signed_psbt, xpub) { + let unsigned_psbt = self + .batches + .find_by_id(profile.account_id, batch_id) + .await? + .unsigned_psbt; + if !psbt_validator::validate_psbt(&signed_psbt, &unsigned_psbt) { return Err(ApplicationError::SubmittedPsbtIsNotValid); } let mut sessions = self diff --git a/src/wallet/psbt_validator.rs b/src/wallet/psbt_validator.rs index b062648a..722490fb 100644 --- a/src/wallet/psbt_validator.rs +++ b/src/wallet/psbt_validator.rs @@ -1,47 +1,44 @@ use bdk::bitcoin::psbt; -use std::collections::HashSet; - -use crate::xpub::XPub; - -pub fn validate_psbt(psbt: &psbt::PartiallySignedTransaction, xpub: XPub) -> bool { - let set: HashSet<_> = psbt - .inputs - .iter() - .flat_map(|inp| &inp.bip32_derivation) - .filter_map(|(pk, (fingerprint, _))| { - (fingerprint == &xpub.inner().parent_fingerprint).then_some(pk) - }) - .collect(); - - psbt.inputs - .iter() - .flat_map(|inp| &inp.partial_sigs) - .any(|(pk, _)| set.contains(&pk.inner)) +pub fn validate_psbt( + signed_psbt: &psbt::PartiallySignedTransaction, + unsigned_psbt: &psbt::PartiallySignedTransaction, +) -> bool { + // this is a good enough check. if all the inputs have final_script_witness or final_script_sig + // it can be safe to assume that the psbt is valid. + // additional check now makes more sense since we are checking if both the unsigned and signed + // psbt have same unsigned_tx + // this also eliminates the need for xpub + + unsigned_psbt.unsigned_tx == signed_psbt.unsigned_tx + && signed_psbt + .inputs + .iter() + .all(|inp| inp.final_script_witness.is_some() || inp.final_script_sig.is_some()) } #[cfg(test)] -mod tests { - pub use super::*; +mod test { + use super::*; #[test] - fn psbt_validation_fails_when_no_signature_found() { - let xpub = XPub::try_from(("tpubDCr5twyowBZhQZEdAXWeJgZtKZgGbKSY4Co55hgw551xCZtHk5fWw9EyGKDBE6cSZPzc4QWR4NyZAeuZDKvRHpQmch78CKwLSy8FEhbvBeR", Some("m/84h/0h/0h"))).unwrap(); - let unsigned_psbt = "cHNidP8BAHEBAAAAAQXU7rw5wiONrLs8zEBacpUPaeCbbFvUGt+ZGhYXNAeIAQAAAAD+////ArN3fQEAAAAAFgAUV69hkddpchM/Kdbp6TUN+rIcmr7AaHgEAAAAABYAFFPOvhKDbGzCHM0LNEHgSPJjuf7RzQAAAAABAHECAAAAAU9hZA8fbnJG2yVoilG86fTB2OL1IqrvPQA9NlBtWiQnAAAAAAD9////AvwFECQBAAAAFgAUzLEhaay70eCwLvJFdjkvtol3NW8A4fUFAAAAABYAFDBOCTOounYzbvGLZnREjy6LIYleyAAAAAEBHwDh9QUAAAAAFgAUME4JM6i6djNu8YtmdESPLoshiV4BAwQBAAAAIgYD5r7WIWyxhitgzbBviYDuNdIi5MFngT7p77MpjifMr1oYb9vpm1QAAIAAAACAAAAAgAAAAAAAAAAAACICA/rQ0V1BsVPLAcQg2Hztdzw16PuDuhOzci1DnSHfjcpBGG/b6ZtUAACAAAAAgAAAAIABAAAAEAAAAAAA".parse::().unwrap(); - assert!(!validate_psbt(&unsigned_psbt, xpub)); + fn passes_if_correct_and_signed_psbt_passed() { + let signed_psbt = "cHNidP8BAH0BAAAAASNihqnLFfz7pHt1zDeB/iB7ku75Ah6EFaFhQZnbErt9AAAAAAD+////Ap13fQEAAAAAIgAgO37beKyitaViJwyjZ3oTIwdBU0JTbBRa32V1zvdifQzAaHgEAAAAABYAFFPOvhKDbGzCHM0LNEHgSPJjuf7RzQAAAAABAIkCAAAAAUxGIfiVmAY20gYMGPkMWDhNuf7xZOc3UutYyrXNRyY2AAAAAAD9////AgDh9QUAAAAAIgAgjoqVjwo7KNRKWUHLalHhejeEI0zUN3PteWscxop8ElYcBBAkAQAAACJRIM5ovh2uzu6dPIaxxMy66uvDCZUg1uNFd/ZG6kvgK5kzyAAAAAEBKwDh9QUAAAAAIgAgjoqVjwo7KNRKWUHLalHhejeEI0zUN3PteWscxop8ElYBCJIDAEcwRAIgGZdgjGq/M/51nE9WtP69BZBhQtho22JcoIQHSWEXI00CIA7/Mj5A906MFjd+sm+EawhjTALyR5jsPyT6Qa7TEJQDAUdRIQJQZ+FcB64peA2v9qxsxfxWZzNIJwIuTOwO4hzMTAOLSCECl48Dr84329WNBzLx9gXNhKrbpMfncXeFfKjrrNt6hoZSrgABAUdRIQJcOcC8y4Cq1oHFG9ZZErhw54kKafGsebNftiz5M6AuQyECyXb40F/RY1cHkPK7+PT6W4hVgJX7bUZHuE8jYBS+KyJSriICAlw5wLzLgKrWgcUb1lkSuHDniQpp8ax5s1+2LPkzoC5DHJhT3akwAACAAQAAgAAAAIACAACAAQAAAAAAAAAiAgLJdvjQX9FjVweQ8rv49PpbiFWAlfttRke4TyNgFL4rIhwd6KQcMAAAgAEAAIAAAACAAgAAgAEAAAAAAAAAAAA=".parse::().unwrap(); + let unsigned_psbt = "cHNidP8BAH0BAAAAASNihqnLFfz7pHt1zDeB/iB7ku75Ah6EFaFhQZnbErt9AAAAAAD+////Ap13fQEAAAAAIgAgO37beKyitaViJwyjZ3oTIwdBU0JTbBRa32V1zvdifQzAaHgEAAAAABYAFFPOvhKDbGzCHM0LNEHgSPJjuf7RzQAAAAABAPYCAAAAAAEBTEYh+JWYBjbSBgwY+QxYOE25/vFk5zdS61jKtc1HJjYAAAAAAP3///8CAOH1BQAAAAAiACCOipWPCjso1EpZQctqUeF6N4QjTNQ3c+15axzGinwSVhwEECQBAAAAIlEgzmi+Ha7O7p08hrHEzLrq68MJlSDW40V39kbqS+ArmTMCRzBEAiB5fcQ8lx7fp+Calgy7o9jQEsHEPho0zfP13TQsCC2/GgIgSL/zyp0nz5PzdMXxhgBJ59O2t7tUhAfKxBYtVjMYXR0BIQN39pz1kuRtgfVu5SMba1rXL5HXDIKq4/rq7I/342+/GsgAAAABASsA4fUFAAAAACIAII6KlY8KOyjUSllBy2pR4Xo3hCNM1Ddz7XlrHMaKfBJWAQMEAQAAAAEFR1EhAlBn4VwHril4Da/2rGzF/FZnM0gnAi5M7A7iHMxMA4tIIQKXjwOvzjfb1Y0HMvH2Bc2Eqtukx+dxd4V8qOus23qGhlKuIgYCUGfhXAeuKXgNr/asbMX8VmczSCcCLkzsDuIczEwDi0gcmFPdqTAAAIABAACAAAAAgAIAAIAAAAAAAAAAACIGApePA6/ON9vVjQcy8fYFzYSq26TH53F3hXyo66zbeoaGHB3opBwwAACAAQAAgAAAAIACAACAAAAAAAAAAAAAAQFHUSECXDnAvMuAqtaBxRvWWRK4cOeJCmnxrHmzX7Ys+TOgLkMhAsl2+NBf0WNXB5Dyu/j0+luIVYCV+21GR7hPI2AUvisiUq4iAgJcOcC8y4Cq1oHFG9ZZErhw54kKafGsebNftiz5M6AuQxyYU92pMAAAgAEAAIAAAACAAgAAgAEAAAAAAAAAIgICyXb40F/RY1cHkPK7+PT6W4hVgJX7bUZHuE8jYBS+KyIcHeikHDAAAIABAACAAAAAgAIAAIABAAAAAAAAAAAA".parse::().unwrap(); + assert!(validate_psbt(&signed_psbt, &unsigned_psbt)) } #[test] - fn psbt_validation_passes_when_psbt_has_signature_corresponding_to_xpub() { - let xpub = XPub::try_from(("tpubDCr5twyowBZhQZEdAXWeJgZtKZgGbKSY4Co55hgw551xCZtHk5fWw9EyGKDBE6cSZPzc4QWR4NyZAeuZDKvRHpQmch78CKwLSy8FEhbvBeR", Some("m/84h/0h/0h"))).unwrap(); - let signed_psbt = "cHNidP8BAHEBAAAAAW4QOT19+Uo9u6t7aDKmPXO/3w/xngnKmx9dTVANte9UAAAAAAD+////AuBwcgAAAAAAFgAUiMb1OtZlnYl675jK0AyiiKL9aDaTb4MFAAAAABYAFCZ1Q/XoJGSYzKxIS4BxneQgcF76zQAAAAABAN4CAAAAAAEBaptFtxfQBPJQn8F4EEXhoFdO4e4iMPviJ1CzgYJfbiIAAAAAAP3///8CAOH1BQAAAAAWABQwTgkzqLp2M27xi2Z0RI8uiyGJXvwFECQBAAAAFgAUTee+ueYwAcnhDxp0DTYDR1ZkGJ8CRzBEAiAvABR181UCFonR47sNobPua6tPN2eaQPeuD1hXlt1hRgIgTTA2C0YDhXKnbyYlBqeNqAxrEFezQ2qkI9ua7vaGf2gBIQKjUJi5wYVZ2EWXNdIeJcVp4wIdRh2+hiBhJHc7ZA9gL8gAAAABAR8A4fUFAAAAABYAFDBOCTOounYzbvGLZnREjy6LIYleIgID5r7WIWyxhitgzbBviYDuNdIi5MFngT7p77MpjifMr1pHMEQCIHoaBu0iBiJ2ZoggAPvO5AXQ+l3WoxRc5x/ppIyNX93lAiA878wEcBTYNS8igFYy/m8RyiN0RR60Y3VNCeiqMxDyewEBAwQBAAAAIgYD5r7WIWyxhitgzbBviYDuNdIi5MFngT7p77MpjifMr1oYb9vpm1QAAIAAAACAAAAAgAAAAAAAAAAAAAAiAgO+qPqnLtz1qY0jb2Xn1qppkA8Fo4g2wjaVQhzw9d2r4hhv2+mbVAAAgAAAAIAAAACAAQAAAAMAAAAA".parse::().unwrap(); - assert!(validate_psbt(&signed_psbt, xpub)); + fn fails_if_incorrect_and_signed_psbt_passed() { + let signed_psbt = "cHNidP8BAHEBAAAAAYbn7MxiehS1ZSM0EB5cRE9nSFCZmsSG1esfWwyuVz+GAAAAAAD+////ArN3fQEAAAAAFgAU/gKMRui+SfQrLooISrMz67mo2TDAaHgEAAAAABYAFFPOvhKDbGzCHM0LNEHgSPJjuf7RzQAAAAABAHECAAAAAUHSbz5JON/N5LECN+D4fkQ4ePau7Swxe/W6Abiyik7/AAAAAAD9////AgDh9QUAAAAAFgAUmtl/mRY8rv7U7qlTERct+67KKEL8BRAkAQAAABYAFNwYhIQ2+xR1XyFfuB0O8PfBJB0ayAAAAAEBHwDh9QUAAAAAFgAUmtl/mRY8rv7U7qlTERct+67KKEIBCGsCRzBEAiAbOAYSbHJagpdcvez9jSFo4tWsN/cFBi1RtRHwh11t/gIgZbnkC8tKwAUMrF+dGjI6w1iChJHwN+Cs2VVhqCuEyWoBIQOZcT3zA/OKNzoMwjrfDPXErOVu7/Tevy9zOUkioZCXbwAiAgNZOo5LB+cTuY4cZu9Oa+w14tqxpMhUdA8YDniI9uRBKhhvL6GyVAAAgAAAAIAAAACAAQAAAAAAAAAAAA==".parse::().unwrap(); + let unsigned_psbt = "cHNidP8BAH0BAAAAASNihqnLFfz7pHt1zDeB/iB7ku75Ah6EFaFhQZnbErt9AAAAAAD+////Ap13fQEAAAAAIgAgO37beKyitaViJwyjZ3oTIwdBU0JTbBRa32V1zvdifQzAaHgEAAAAABYAFFPOvhKDbGzCHM0LNEHgSPJjuf7RzQAAAAABAPYCAAAAAAEBTEYh+JWYBjbSBgwY+QxYOE25/vFk5zdS61jKtc1HJjYAAAAAAP3///8CAOH1BQAAAAAiACCOipWPCjso1EpZQctqUeF6N4QjTNQ3c+15axzGinwSVhwEECQBAAAAIlEgzmi+Ha7O7p08hrHEzLrq68MJlSDW40V39kbqS+ArmTMCRzBEAiB5fcQ8lx7fp+Calgy7o9jQEsHEPho0zfP13TQsCC2/GgIgSL/zyp0nz5PzdMXxhgBJ59O2t7tUhAfKxBYtVjMYXR0BIQN39pz1kuRtgfVu5SMba1rXL5HXDIKq4/rq7I/342+/GsgAAAABASsA4fUFAAAAACIAII6KlY8KOyjUSllBy2pR4Xo3hCNM1Ddz7XlrHMaKfBJWAQMEAQAAAAEFR1EhAlBn4VwHril4Da/2rGzF/FZnM0gnAi5M7A7iHMxMA4tIIQKXjwOvzjfb1Y0HMvH2Bc2Eqtukx+dxd4V8qOus23qGhlKuIgYCUGfhXAeuKXgNr/asbMX8VmczSCcCLkzsDuIczEwDi0gcmFPdqTAAAIABAACAAAAAgAIAAIAAAAAAAAAAACIGApePA6/ON9vVjQcy8fYFzYSq26TH53F3hXyo66zbeoaGHB3opBwwAACAAQAAgAAAAIACAACAAAAAAAAAAAAAAQFHUSECXDnAvMuAqtaBxRvWWRK4cOeJCmnxrHmzX7Ys+TOgLkMhAsl2+NBf0WNXB5Dyu/j0+luIVYCV+21GR7hPI2AUvisiUq4iAgJcOcC8y4Cq1oHFG9ZZErhw54kKafGsebNftiz5M6AuQxyYU92pMAAAgAEAAIAAAACAAgAAgAEAAAAAAAAAIgICyXb40F/RY1cHkPK7+PT6W4hVgJX7bUZHuE8jYBS+KyIcHeikHDAAAIABAACAAAAAgAIAAIABAAAAAAAAAAAA".parse::().unwrap(); + assert!(!validate_psbt(&signed_psbt, &unsigned_psbt)) } #[test] - fn psbt_validation_fails_when_psbt_does_have_signature_corresponding_to_xpub() { - let xpub = XPub::try_from(("tpubDD4vFnWuTMEcZiaaZPgvzeGyMzWe6qHW8gALk5Md9kutDvtdDjYFwzauEFFRHgov8pAwup5jX88j5YFyiACsPf3pqn5hBjvuTLRAseaJ6b4", Some("m/84h/0h/0h"))).unwrap(); - let signed_psbt = "cHNidP8BAHEBAAAAAW4QOT19+Uo9u6t7aDKmPXO/3w/xngnKmx9dTVANte9UAAAAAAD+////AuBwcgAAAAAAFgAUiMb1OtZlnYl675jK0AyiiKL9aDaTb4MFAAAAABYAFCZ1Q/XoJGSYzKxIS4BxneQgcF76zQAAAAABAN4CAAAAAAEBaptFtxfQBPJQn8F4EEXhoFdO4e4iMPviJ1CzgYJfbiIAAAAAAP3///8CAOH1BQAAAAAWABQwTgkzqLp2M27xi2Z0RI8uiyGJXvwFECQBAAAAFgAUTee+ueYwAcnhDxp0DTYDR1ZkGJ8CRzBEAiAvABR181UCFonR47sNobPua6tPN2eaQPeuD1hXlt1hRgIgTTA2C0YDhXKnbyYlBqeNqAxrEFezQ2qkI9ua7vaGf2gBIQKjUJi5wYVZ2EWXNdIeJcVp4wIdRh2+hiBhJHc7ZA9gL8gAAAABAR8A4fUFAAAAABYAFDBOCTOounYzbvGLZnREjy6LIYleIgID5r7WIWyxhitgzbBviYDuNdIi5MFngT7p77MpjifMr1pHMEQCIHoaBu0iBiJ2ZoggAPvO5AXQ+l3WoxRc5x/ppIyNX93lAiA878wEcBTYNS8igFYy/m8RyiN0RR60Y3VNCeiqMxDyewEBAwQBAAAAIgYD5r7WIWyxhitgzbBviYDuNdIi5MFngT7p77MpjifMr1oYb9vpm1QAAIAAAACAAAAAgAAAAAAAAAAAAAAiAgO+qPqnLtz1qY0jb2Xn1qppkA8Fo4g2wjaVQhzw9d2r4hhv2+mbVAAAgAAAAIAAAACAAQAAAAMAAAAA".parse::().unwrap(); - assert!(!validate_psbt(&signed_psbt, xpub)); + fn fails_if_unsigned_psbt_passed() { + let signed_psbt = "cHNidP8BAHEBAAAAAYbn7MxiehS1ZSM0EB5cRE9nSFCZmsSG1esfWwyuVz+GAAAAAAD+////ArN3fQEAAAAAFgAU/gKMRui+SfQrLooISrMz67mo2TDAaHgEAAAAABYAFFPOvhKDbGzCHM0LNEHgSPJjuf7RzQAAAAABAHECAAAAAUHSbz5JON/N5LECN+D4fkQ4ePau7Swxe/W6Abiyik7/AAAAAAD9////AgDh9QUAAAAAFgAUmtl/mRY8rv7U7qlTERct+67KKEL8BRAkAQAAABYAFNwYhIQ2+xR1XyFfuB0O8PfBJB0ayAAAAAEBHwDh9QUAAAAAFgAUmtl/mRY8rv7U7qlTERct+67KKEIBAwQBAAAAIgYDmXE98wPzijc6DMI63wz1xKzlbu/03r8vczlJIqGQl28Yby+hslQAAIAAAACAAAAAgAAAAAAAAAAAACICA1k6jksH5xO5jhxm705r7DXi2rGkyFR0DxgOeIj25EEqGG8vobJUAACAAAAAgAAAAIABAAAAAAAAAAAA".parse::().unwrap(); + let unsigned_psbt = "cHNidP8BAH0BAAAAASNihqnLFfz7pHt1zDeB/iB7ku75Ah6EFaFhQZnbErt9AAAAAAD+////Ap13fQEAAAAAIgAgO37beKyitaViJwyjZ3oTIwdBU0JTbBRa32V1zvdifQzAaHgEAAAAABYAFFPOvhKDbGzCHM0LNEHgSPJjuf7RzQAAAAABAPYCAAAAAAEBTEYh+JWYBjbSBgwY+QxYOE25/vFk5zdS61jKtc1HJjYAAAAAAP3///8CAOH1BQAAAAAiACCOipWPCjso1EpZQctqUeF6N4QjTNQ3c+15axzGinwSVhwEECQBAAAAIlEgzmi+Ha7O7p08hrHEzLrq68MJlSDW40V39kbqS+ArmTMCRzBEAiB5fcQ8lx7fp+Calgy7o9jQEsHEPho0zfP13TQsCC2/GgIgSL/zyp0nz5PzdMXxhgBJ59O2t7tUhAfKxBYtVjMYXR0BIQN39pz1kuRtgfVu5SMba1rXL5HXDIKq4/rq7I/342+/GsgAAAABASsA4fUFAAAAACIAII6KlY8KOyjUSllBy2pR4Xo3hCNM1Ddz7XlrHMaKfBJWAQMEAQAAAAEFR1EhAlBn4VwHril4Da/2rGzF/FZnM0gnAi5M7A7iHMxMA4tIIQKXjwOvzjfb1Y0HMvH2Bc2Eqtukx+dxd4V8qOus23qGhlKuIgYCUGfhXAeuKXgNr/asbMX8VmczSCcCLkzsDuIczEwDi0gcmFPdqTAAAIABAACAAAAAgAIAAIAAAAAAAAAAACIGApePA6/ON9vVjQcy8fYFzYSq26TH53F3hXyo66zbeoaGHB3opBwwAACAAQAAgAAAAIACAACAAAAAAAAAAAAAAQFHUSECXDnAvMuAqtaBxRvWWRK4cOeJCmnxrHmzX7Ys+TOgLkMhAsl2+NBf0WNXB5Dyu/j0+luIVYCV+21GR7hPI2AUvisiUq4iAgJcOcC8y4Cq1oHFG9ZZErhw54kKafGsebNftiz5M6AuQxyYU92pMAAAgAEAAIAAAACAAgAAgAEAAAAAAAAAIgICyXb40F/RY1cHkPK7+PT6W4hVgJX7bUZHuE8jYBS+KyIcHeikHDAAAIABAACAAAAAgAIAAIABAAAAAAAAAAAA".parse::().unwrap(); + assert!(!validate_psbt(&signed_psbt, &unsigned_psbt)) } } From d5436e2ccff073b500350ed37e22fce7629ac07b Mon Sep 17 00:00:00 2001 From: Vaibhav Date: Tue, 4 Jul 2023 12:31:22 +0530 Subject: [PATCH 15/26] chore: use lnd_key and improve validation logic --- src/app/mod.rs | 5 +- src/wallet/error.rs | 4 ++ src/wallet/psbt_validator.rs | 54 ++++++++++++++----- .../bitcoind_multisig_signer_descriptors.json | 2 +- tests/e2e/bitcoind_sync.bats | 26 ++++----- tests/e2e/helpers.bash | 18 ++++--- tests/e2e/lnd_sync.bats | 20 +++---- tests/e2e/multisig_payout.bats | 3 +- tests/e2e/outbox.bats | 8 +-- tests/e2e/payout.bats | 18 +++---- 10 files changed, 96 insertions(+), 62 deletions(-) diff --git a/src/app/mod.rs b/src/app/mod.rs index f73ebc8d..c6a5f13f 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -223,14 +223,13 @@ impl App { ) .await?; let xpub_id = xpub.id(); + let xpub = xpub.value; let unsigned_psbt = self .batches .find_by_id(profile.account_id, batch_id) .await? .unsigned_psbt; - if !psbt_validator::validate_psbt(&signed_psbt, &unsigned_psbt) { - return Err(ApplicationError::SubmittedPsbtIsNotValid); - } + psbt_validator::validate_psbt(&signed_psbt, xpub, &unsigned_psbt)?; let mut sessions = self .signing_sessions .list_for_batch(profile.account_id, batch_id) diff --git a/src/wallet/error.rs b/src/wallet/error.rs index e6391556..4b86108a 100644 --- a/src/wallet/error.rs +++ b/src/wallet/error.rs @@ -14,4 +14,8 @@ pub enum WalletError { UnsupportedPubKeyType, #[error("WalletError - BdkMiniscriptError: {0}")] BdkMiniscriptError(#[from] bdk::miniscript::Error), + #[error("WalletError - Submitted Psbt does not have valid signatures.")] + PsbtDoesNotHaveValidSignatures, + #[error("WalletError - Unsigned txn in signed and unsigned psbt don't match")] + UnsignedTxnMismatch, } diff --git a/src/wallet/psbt_validator.rs b/src/wallet/psbt_validator.rs index 722490fb..49bac862 100644 --- a/src/wallet/psbt_validator.rs +++ b/src/wallet/psbt_validator.rs @@ -1,20 +1,42 @@ use bdk::bitcoin::psbt; +use std::collections::HashSet; + +use crate::xpub::XPub; + +use super::error::WalletError; + pub fn validate_psbt( signed_psbt: &psbt::PartiallySignedTransaction, + xpub: XPub, unsigned_psbt: &psbt::PartiallySignedTransaction, -) -> bool { - // this is a good enough check. if all the inputs have final_script_witness or final_script_sig - // it can be safe to assume that the psbt is valid. - // additional check now makes more sense since we are checking if both the unsigned and signed - // psbt have same unsigned_tx - // this also eliminates the need for xpub - - unsigned_psbt.unsigned_tx == signed_psbt.unsigned_tx - && signed_psbt +) -> Result<(), WalletError> { + let set: HashSet<_> = signed_psbt + .inputs + .iter() + .flat_map(|inp| &inp.bip32_derivation) + .filter_map(|(pk, (fingerprint, _))| { + (fingerprint == &xpub.inner().parent_fingerprint).then_some(pk) + }) + .collect(); + + if unsigned_psbt.unsigned_tx != signed_psbt.unsigned_tx { + return Err(WalletError::UnsignedTxnMismatch); + } + + if !(signed_psbt + .inputs + .iter() + .all(|inp| inp.final_script_witness.is_some() || inp.final_script_sig.is_some()) + || signed_psbt .inputs .iter() - .all(|inp| inp.final_script_witness.is_some() || inp.final_script_sig.is_some()) + .flat_map(|inp| &inp.partial_sigs) + .any(|(pk, _)| set.contains(&pk.inner))) + { + return Err(WalletError::PsbtDoesNotHaveValidSignatures); + } + Ok(()) } #[cfg(test)] @@ -23,22 +45,28 @@ mod test { #[test] fn passes_if_correct_and_signed_psbt_passed() { + let xpub = XPub::try_from(("tpubDE8HT914zGpxhJhgoMX35xgNyjHy5d1neGXHjTLAtuUssTA7tNWNs177JsFPbJwD5FBXCHJYbwUC9AzSEpYHC4hKgaCvZyZTuCbWfNUWXoM", Some("m/48h/1h/0h/2h"))).unwrap(); let signed_psbt = "cHNidP8BAH0BAAAAASNihqnLFfz7pHt1zDeB/iB7ku75Ah6EFaFhQZnbErt9AAAAAAD+////Ap13fQEAAAAAIgAgO37beKyitaViJwyjZ3oTIwdBU0JTbBRa32V1zvdifQzAaHgEAAAAABYAFFPOvhKDbGzCHM0LNEHgSPJjuf7RzQAAAAABAIkCAAAAAUxGIfiVmAY20gYMGPkMWDhNuf7xZOc3UutYyrXNRyY2AAAAAAD9////AgDh9QUAAAAAIgAgjoqVjwo7KNRKWUHLalHhejeEI0zUN3PteWscxop8ElYcBBAkAQAAACJRIM5ovh2uzu6dPIaxxMy66uvDCZUg1uNFd/ZG6kvgK5kzyAAAAAEBKwDh9QUAAAAAIgAgjoqVjwo7KNRKWUHLalHhejeEI0zUN3PteWscxop8ElYBCJIDAEcwRAIgGZdgjGq/M/51nE9WtP69BZBhQtho22JcoIQHSWEXI00CIA7/Mj5A906MFjd+sm+EawhjTALyR5jsPyT6Qa7TEJQDAUdRIQJQZ+FcB64peA2v9qxsxfxWZzNIJwIuTOwO4hzMTAOLSCECl48Dr84329WNBzLx9gXNhKrbpMfncXeFfKjrrNt6hoZSrgABAUdRIQJcOcC8y4Cq1oHFG9ZZErhw54kKafGsebNftiz5M6AuQyECyXb40F/RY1cHkPK7+PT6W4hVgJX7bUZHuE8jYBS+KyJSriICAlw5wLzLgKrWgcUb1lkSuHDniQpp8ax5s1+2LPkzoC5DHJhT3akwAACAAQAAgAAAAIACAACAAQAAAAAAAAAiAgLJdvjQX9FjVweQ8rv49PpbiFWAlfttRke4TyNgFL4rIhwd6KQcMAAAgAEAAIAAAACAAgAAgAEAAAAAAAAAAAA=".parse::().unwrap(); let unsigned_psbt = "cHNidP8BAH0BAAAAASNihqnLFfz7pHt1zDeB/iB7ku75Ah6EFaFhQZnbErt9AAAAAAD+////Ap13fQEAAAAAIgAgO37beKyitaViJwyjZ3oTIwdBU0JTbBRa32V1zvdifQzAaHgEAAAAABYAFFPOvhKDbGzCHM0LNEHgSPJjuf7RzQAAAAABAPYCAAAAAAEBTEYh+JWYBjbSBgwY+QxYOE25/vFk5zdS61jKtc1HJjYAAAAAAP3///8CAOH1BQAAAAAiACCOipWPCjso1EpZQctqUeF6N4QjTNQ3c+15axzGinwSVhwEECQBAAAAIlEgzmi+Ha7O7p08hrHEzLrq68MJlSDW40V39kbqS+ArmTMCRzBEAiB5fcQ8lx7fp+Calgy7o9jQEsHEPho0zfP13TQsCC2/GgIgSL/zyp0nz5PzdMXxhgBJ59O2t7tUhAfKxBYtVjMYXR0BIQN39pz1kuRtgfVu5SMba1rXL5HXDIKq4/rq7I/342+/GsgAAAABASsA4fUFAAAAACIAII6KlY8KOyjUSllBy2pR4Xo3hCNM1Ddz7XlrHMaKfBJWAQMEAQAAAAEFR1EhAlBn4VwHril4Da/2rGzF/FZnM0gnAi5M7A7iHMxMA4tIIQKXjwOvzjfb1Y0HMvH2Bc2Eqtukx+dxd4V8qOus23qGhlKuIgYCUGfhXAeuKXgNr/asbMX8VmczSCcCLkzsDuIczEwDi0gcmFPdqTAAAIABAACAAAAAgAIAAIAAAAAAAAAAACIGApePA6/ON9vVjQcy8fYFzYSq26TH53F3hXyo66zbeoaGHB3opBwwAACAAQAAgAAAAIACAACAAAAAAAAAAAAAAQFHUSECXDnAvMuAqtaBxRvWWRK4cOeJCmnxrHmzX7Ys+TOgLkMhAsl2+NBf0WNXB5Dyu/j0+luIVYCV+21GR7hPI2AUvisiUq4iAgJcOcC8y4Cq1oHFG9ZZErhw54kKafGsebNftiz5M6AuQxyYU92pMAAAgAEAAIAAAACAAgAAgAEAAAAAAAAAIgICyXb40F/RY1cHkPK7+PT6W4hVgJX7bUZHuE8jYBS+KyIcHeikHDAAAIABAACAAAAAgAIAAIABAAAAAAAAAAAA".parse::().unwrap(); - assert!(validate_psbt(&signed_psbt, &unsigned_psbt)) + assert_eq!( + validate_psbt(&signed_psbt, xpub, &unsigned_psbt).unwrap(), + () + ); } #[test] fn fails_if_incorrect_and_signed_psbt_passed() { + let xpub = XPub::try_from(("tpubDE8HT914zGpxhJhgoMX35xgNyjHy5d1neGXHjTLAtuUssTA7tNWNs177JsFPbJwD5FBXCHJYbwUC9AzSEpYHC4hKgaCvZyZTuCbWfNUWXoM", Some("m/48h/1h/0h/2h"))).unwrap(); let signed_psbt = "cHNidP8BAHEBAAAAAYbn7MxiehS1ZSM0EB5cRE9nSFCZmsSG1esfWwyuVz+GAAAAAAD+////ArN3fQEAAAAAFgAU/gKMRui+SfQrLooISrMz67mo2TDAaHgEAAAAABYAFFPOvhKDbGzCHM0LNEHgSPJjuf7RzQAAAAABAHECAAAAAUHSbz5JON/N5LECN+D4fkQ4ePau7Swxe/W6Abiyik7/AAAAAAD9////AgDh9QUAAAAAFgAUmtl/mRY8rv7U7qlTERct+67KKEL8BRAkAQAAABYAFNwYhIQ2+xR1XyFfuB0O8PfBJB0ayAAAAAEBHwDh9QUAAAAAFgAUmtl/mRY8rv7U7qlTERct+67KKEIBCGsCRzBEAiAbOAYSbHJagpdcvez9jSFo4tWsN/cFBi1RtRHwh11t/gIgZbnkC8tKwAUMrF+dGjI6w1iChJHwN+Cs2VVhqCuEyWoBIQOZcT3zA/OKNzoMwjrfDPXErOVu7/Tevy9zOUkioZCXbwAiAgNZOo5LB+cTuY4cZu9Oa+w14tqxpMhUdA8YDniI9uRBKhhvL6GyVAAAgAAAAIAAAACAAQAAAAAAAAAAAA==".parse::().unwrap(); let unsigned_psbt = "cHNidP8BAH0BAAAAASNihqnLFfz7pHt1zDeB/iB7ku75Ah6EFaFhQZnbErt9AAAAAAD+////Ap13fQEAAAAAIgAgO37beKyitaViJwyjZ3oTIwdBU0JTbBRa32V1zvdifQzAaHgEAAAAABYAFFPOvhKDbGzCHM0LNEHgSPJjuf7RzQAAAAABAPYCAAAAAAEBTEYh+JWYBjbSBgwY+QxYOE25/vFk5zdS61jKtc1HJjYAAAAAAP3///8CAOH1BQAAAAAiACCOipWPCjso1EpZQctqUeF6N4QjTNQ3c+15axzGinwSVhwEECQBAAAAIlEgzmi+Ha7O7p08hrHEzLrq68MJlSDW40V39kbqS+ArmTMCRzBEAiB5fcQ8lx7fp+Calgy7o9jQEsHEPho0zfP13TQsCC2/GgIgSL/zyp0nz5PzdMXxhgBJ59O2t7tUhAfKxBYtVjMYXR0BIQN39pz1kuRtgfVu5SMba1rXL5HXDIKq4/rq7I/342+/GsgAAAABASsA4fUFAAAAACIAII6KlY8KOyjUSllBy2pR4Xo3hCNM1Ddz7XlrHMaKfBJWAQMEAQAAAAEFR1EhAlBn4VwHril4Da/2rGzF/FZnM0gnAi5M7A7iHMxMA4tIIQKXjwOvzjfb1Y0HMvH2Bc2Eqtukx+dxd4V8qOus23qGhlKuIgYCUGfhXAeuKXgNr/asbMX8VmczSCcCLkzsDuIczEwDi0gcmFPdqTAAAIABAACAAAAAgAIAAIAAAAAAAAAAACIGApePA6/ON9vVjQcy8fYFzYSq26TH53F3hXyo66zbeoaGHB3opBwwAACAAQAAgAAAAIACAACAAAAAAAAAAAAAAQFHUSECXDnAvMuAqtaBxRvWWRK4cOeJCmnxrHmzX7Ys+TOgLkMhAsl2+NBf0WNXB5Dyu/j0+luIVYCV+21GR7hPI2AUvisiUq4iAgJcOcC8y4Cq1oHFG9ZZErhw54kKafGsebNftiz5M6AuQxyYU92pMAAAgAEAAIAAAACAAgAAgAEAAAAAAAAAIgICyXb40F/RY1cHkPK7+PT6W4hVgJX7bUZHuE8jYBS+KyIcHeikHDAAAIABAACAAAAAgAIAAIABAAAAAAAAAAAA".parse::().unwrap(); - assert!(!validate_psbt(&signed_psbt, &unsigned_psbt)) + assert!(validate_psbt(&signed_psbt, xpub, &unsigned_psbt).is_err()); } #[test] fn fails_if_unsigned_psbt_passed() { + let xpub = XPub::try_from(("tpubDE8HT914zGpxhJhgoMX35xgNyjHy5d1neGXHjTLAtuUssTA7tNWNs177JsFPbJwD5FBXCHJYbwUC9AzSEpYHC4hKgaCvZyZTuCbWfNUWXoM", Some("m/48h/1h/0h/2h"))).unwrap(); let signed_psbt = "cHNidP8BAHEBAAAAAYbn7MxiehS1ZSM0EB5cRE9nSFCZmsSG1esfWwyuVz+GAAAAAAD+////ArN3fQEAAAAAFgAU/gKMRui+SfQrLooISrMz67mo2TDAaHgEAAAAABYAFFPOvhKDbGzCHM0LNEHgSPJjuf7RzQAAAAABAHECAAAAAUHSbz5JON/N5LECN+D4fkQ4ePau7Swxe/W6Abiyik7/AAAAAAD9////AgDh9QUAAAAAFgAUmtl/mRY8rv7U7qlTERct+67KKEL8BRAkAQAAABYAFNwYhIQ2+xR1XyFfuB0O8PfBJB0ayAAAAAEBHwDh9QUAAAAAFgAUmtl/mRY8rv7U7qlTERct+67KKEIBAwQBAAAAIgYDmXE98wPzijc6DMI63wz1xKzlbu/03r8vczlJIqGQl28Yby+hslQAAIAAAACAAAAAgAAAAAAAAAAAACICA1k6jksH5xO5jhxm705r7DXi2rGkyFR0DxgOeIj25EEqGG8vobJUAACAAAAAgAAAAIABAAAAAAAAAAAA".parse::().unwrap(); let unsigned_psbt = "cHNidP8BAH0BAAAAASNihqnLFfz7pHt1zDeB/iB7ku75Ah6EFaFhQZnbErt9AAAAAAD+////Ap13fQEAAAAAIgAgO37beKyitaViJwyjZ3oTIwdBU0JTbBRa32V1zvdifQzAaHgEAAAAABYAFFPOvhKDbGzCHM0LNEHgSPJjuf7RzQAAAAABAPYCAAAAAAEBTEYh+JWYBjbSBgwY+QxYOE25/vFk5zdS61jKtc1HJjYAAAAAAP3///8CAOH1BQAAAAAiACCOipWPCjso1EpZQctqUeF6N4QjTNQ3c+15axzGinwSVhwEECQBAAAAIlEgzmi+Ha7O7p08hrHEzLrq68MJlSDW40V39kbqS+ArmTMCRzBEAiB5fcQ8lx7fp+Calgy7o9jQEsHEPho0zfP13TQsCC2/GgIgSL/zyp0nz5PzdMXxhgBJ59O2t7tUhAfKxBYtVjMYXR0BIQN39pz1kuRtgfVu5SMba1rXL5HXDIKq4/rq7I/342+/GsgAAAABASsA4fUFAAAAACIAII6KlY8KOyjUSllBy2pR4Xo3hCNM1Ddz7XlrHMaKfBJWAQMEAQAAAAEFR1EhAlBn4VwHril4Da/2rGzF/FZnM0gnAi5M7A7iHMxMA4tIIQKXjwOvzjfb1Y0HMvH2Bc2Eqtukx+dxd4V8qOus23qGhlKuIgYCUGfhXAeuKXgNr/asbMX8VmczSCcCLkzsDuIczEwDi0gcmFPdqTAAAIABAACAAAAAgAIAAIAAAAAAAAAAACIGApePA6/ON9vVjQcy8fYFzYSq26TH53F3hXyo66zbeoaGHB3opBwwAACAAQAAgAAAAIACAACAAAAAAAAAAAAAAQFHUSECXDnAvMuAqtaBxRvWWRK4cOeJCmnxrHmzX7Ys+TOgLkMhAsl2+NBf0WNXB5Dyu/j0+luIVYCV+21GR7hPI2AUvisiUq4iAgJcOcC8y4Cq1oHFG9ZZErhw54kKafGsebNftiz5M6AuQxyYU92pMAAAgAEAAIAAAACAAgAAgAEAAAAAAAAAIgICyXb40F/RY1cHkPK7+PT6W4hVgJX7bUZHuE8jYBS+KyIcHeikHDAAAIABAACAAAAAgAIAAIABAAAAAAAAAAAA".parse::().unwrap(); - assert!(!validate_psbt(&signed_psbt, &unsigned_psbt)) + assert!(validate_psbt(&signed_psbt, xpub, &unsigned_psbt).is_err()); } } diff --git a/tests/e2e/bitcoind_multisig_signer_descriptors.json b/tests/e2e/bitcoind_multisig_signer_descriptors.json index 8fd0d47a..b6eaf040 100644 --- a/tests/e2e/bitcoind_multisig_signer_descriptors.json +++ b/tests/e2e/bitcoind_multisig_signer_descriptors.json @@ -1 +1 @@ -[{"active":true,"desc":"wsh(sortedmulti(1,[186ad0c4/48h/1h/0h/2h]tprv8hSFJixpqu9HoqftuhrSgZ2GQhn2vHpt4xvWSwHsUdgV2xuMFygngWVF8kxdGr983KngUHsuw3onLZZCivCHRg398cVd65TQxe8mjd467Qz/0/*,[72d14a88/48h/1h/0h/2h]tpubDF2UP3xmRcJoi5LDYZKVoUj6MsaUrcPiTgV7Q2b8eWtnSsM3EhFeszEiG9iTU7Gixzym4a1F2T6gSp59y7iZrtTKZRAw6fqzbevphHxBzGz/0/*))#gm0myh0z","timestamp":0},{"active":true,"desc":"wsh(sortedmulti(1,[186ad0c4/48h/1h/0h/2h]tprv8hSFJixpqu9HoqftuhrSgZ2GQhn2vHpt4xvWSwHsUdgV2xuMFygngWVF8kxdGr983KngUHsuw3onLZZCivCHRg398cVd65TQxe8mjd467Qz/1/*,[72d14a88/48h/1h/0h/2h]tpubDF2UP3xmRcJoi5LDYZKVoUj6MsaUrcPiTgV7Q2b8eWtnSsM3EhFeszEiG9iTU7Gixzym4a1F2T6gSp59y7iZrtTKZRAw6fqzbevphHxBzGz/1/*))#3gul2y6h","internal":true,"timestamp":0}] +[{"active":true,"desc":"wsh(sortedmulti(2,[186ad0c4/48h/1h/0h/2h]tprv8hSFJixpqu9HoqftuhrSgZ2GQhn2vHpt4xvWSwHsUdgV2xuMFygngWVF8kxdGr983KngUHsuw3onLZZCivCHRg398cVd65TQxe8mjd467Qz/0/*,[8df69d29/84h/0h/0h]tpubDD4vFnWuTMEcZiaaZPgvzeGyMzWe6qHW8gALk5Md9kutDvtdDjYFwzauEFFRHgov8pAwup5jX88j5YFyiACsPf3pqn5hBjvuTLRAseaJ6b4/0/*))#9rj4qzrz","timestamp":0},{"active":true,"desc":"wsh(sortedmulti(2,[186ad0c4/48h/1h/0h/2h]tprv8hSFJixpqu9HoqftuhrSgZ2GQhn2vHpt4xvWSwHsUdgV2xuMFygngWVF8kxdGr983KngUHsuw3onLZZCivCHRg398cVd65TQxe8mjd467Qz/1/*,[8df69d29/84h/0h/0h]tpubDD4vFnWuTMEcZiaaZPgvzeGyMzWe6qHW8gALk5Md9kutDvtdDjYFwzauEFFRHgov8pAwup5jX88j5YFyiACsPf3pqn5hBjvuTLRAseaJ6b4/1/*))#vt68gsll","internal":true,"timestamp":0}] diff --git a/tests/e2e/bitcoind_sync.bats b/tests/e2e/bitcoind_sync.bats index 8e11d7a9..2799c971 100644 --- a/tests/e2e/bitcoind_sync.bats +++ b/tests/e2e/bitcoind_sync.bats @@ -5,9 +5,9 @@ load "helpers" setup_file() { restart_bitcoin_stack reset_pg - bitcoind_init default + bitcoind_init start_daemon - bria_init default + bria_init } teardown_file() { @@ -34,7 +34,7 @@ teardown_file() { bitcoin_cli -regtest sendtoaddress ${bitcoind_signer_address} 1 for i in {1..30}; do - cache_wallet_balance default + cache_wallet_balance [[ $(cached_pending_income) == 100000000 ]] && break sleep 1 done @@ -51,7 +51,7 @@ teardown_file() { bitcoin_cli -generate 2 for i in {1..30}; do - cache_wallet_balance default + cache_wallet_balance [[ $(cached_current_settled) == 100000000 ]] && break sleep 1 done @@ -68,7 +68,7 @@ teardown_file() { bitcoind_address=$(bitcoin_cli -regtest getnewaddress) bitcoin_signer_cli -regtest sendtoaddress "${bitcoind_address}" 0.5 for i in {1..30}; do - cache_wallet_balance default + cache_wallet_balance [[ $(cached_pending_outgoing) == 50000000 ]] && break sleep 1 done @@ -84,7 +84,7 @@ teardown_file() { bitcoin_cli -generate 1 for i in {1..30}; do - cache_wallet_balance default + cache_wallet_balance [[ $(cached_current_settled) != 0 ]] && break sleep 1 done @@ -119,7 +119,7 @@ teardown_file() { ${bitcoind_address} for i in {1..30}; do - cache_wallet_balance default + cache_wallet_balance [[ $(cached_pending_outgoing) == 210000000 ]] && break sleep 1 done @@ -128,7 +128,7 @@ teardown_file() { bitcoin_cli -generate 2 for i in {1..30}; do - cache_wallet_balance default + cache_wallet_balance [[ $(cached_pending_outgoing) == 0 ]] && break sleep 1 done @@ -142,13 +142,13 @@ teardown_file() { } @test "bitcoind_signer_sync: Can sweep all" { - cache_wallet_balance default + cache_wallet_balance [[ $(cached_current_settled) != 0 ]] || exit 1 bitcoind_address=$(bitcoin_cli -regtest getnewaddress) bitcoin_signer_cli -named sendall recipients="[\"${bitcoind_address}\"]" fee_rate=1 for i in {1..10}; do - cache_wallet_balance default + cache_wallet_balance [[ $(cached_current_settled) == 0 ]] \ && [[ $(cached_pending_outgoing) != 0 ]] \ && break @@ -160,7 +160,7 @@ teardown_file() { bitcoin_cli -generate 1 for i in {1..30}; do - cache_wallet_balance default + cache_wallet_balance [[ $(cached_pending_outgoing) == 0 ]] \ && [[ $(cached_encumbered_fees) == 0 ]] \ && break @@ -186,7 +186,7 @@ teardown_file() { ${bitcoind_address} for i in {1..30}; do - cache_wallet_balance default + cache_wallet_balance [[ $(cached_pending_outgoing) == 60000000 ]] && break sleep 1 done @@ -195,7 +195,7 @@ teardown_file() { bitcoin_cli -generate 2 for i in {1..30}; do - cache_wallet_balance default + cache_wallet_balance [[ $(cached_pending_outgoing) == 0 ]] && break sleep 1 done diff --git a/tests/e2e/helpers.bash b/tests/e2e/helpers.bash index 009f964c..ff620069 100644 --- a/tests/e2e/helpers.bash +++ b/tests/e2e/helpers.bash @@ -6,6 +6,8 @@ if [[ "${BRIA_CONFIG}" == "docker" ]]; then COMPOSE_FILE_ARG="-f docker-compose.yml" fi BITCOIND_SIGNER_ENDPOINT="${BITCOIND_SIGNER_ENDPOINT:-https://localhost:18543}" +LND_HOST="${LND_HOST:-localhost}" +LND_ENDPOINT="https://${LND_HOST}:10009" SATS_IN_ONE_BTC=100000000 bria_cmd() { @@ -18,7 +20,7 @@ bria_cmd() { } cache_wallet_balance() { - local wallet_name="${1}" + local wallet_name="${1:-default}" balance=$(bria_cmd wallet-balance -w "${wallet_name}") } @@ -96,7 +98,7 @@ restart_bitcoin_stack() { } bitcoind_init() { - local wallet="${1}" + local wallet="${1:-default}" bitcoin_cli createwallet "default" || true bitcoin_cli generatetoaddress 200 "$(bitcoin_cli getnewaddress)" @@ -122,7 +124,7 @@ stop_daemon() { } bria_init() { - local wallet_type="${1}" + local wallet_type="${1:-default}" if [[ "${BRIA_CONFIG}" == "docker" ]]; then retry 10 1 bria_cmd admin bootstrap @@ -142,16 +144,16 @@ bria_init() { fi elif [[ "${wallet_type}" == "multisig" ]]; then local key1="tpubDE8HT914zGpxhJhgoMX35xgNyjHy5d1neGXHjTLAtuUssTA7tNWNs177JsFPbJwD5FBXCHJYbwUC9AzSEpYHC4hKgaCvZyZTuCbWfNUWXoM" - local key2="tpubDF2UP3xmRcJoi5LDYZKVoUj6MsaUrcPiTgV7Q2b8eWtnSsM3EhFeszEiG9iTU7Gixzym4a1F2T6gSp59y7iZrtTKZRAw6fqzbevphHxBzGz" + local key2="tpubDD4vFnWuTMEcZiaaZPgvzeGyMzWe6qHW8gALk5Md9kutDvtdDjYFwzauEFFRHgov8pAwup5jX88j5YFyiACsPf3pqn5hBjvuTLRAseaJ6b4" if [[ "${BRIA_CONFIG}" == "docker" ]]; then retry 10 1 bria_cmd import-xpub -x "${key1}" -n key1 -d m/48h/1h/0h/2h - bria_cmd import-xpub -x "${key2}" -n key2 -d m/48h/1h/0h/2h - bria_cmd create-wallet -n multisig sorted-multisig -x key1 key2 -t 1 + bria_cmd import-xpub -x "${key2}" -n key2 -d m/84h/0h/0h + bria_cmd create-wallet -n multisig sorted-multisig -x key1 lnd_key -t 1 else bria_cmd import-xpub -x "${key1}" -n key1 -d m/48h/1h/0h/2h - bria_cmd import-xpub -x "${key2}" -n key2 -d m/48h/1h/0h/2h - bria_cmd create-wallet -n multisig sorted-multisig -x key1 key2 -t 1 + bria_cmd import-xpub -x "${key2}" -n lnd_key -d m/84h/0h/0h + bria_cmd create-wallet -n multisig sorted-multisig -x key1 lnd_key -t 2 fi fi diff --git a/tests/e2e/lnd_sync.bats b/tests/e2e/lnd_sync.bats index 35e990a3..f6651fdb 100644 --- a/tests/e2e/lnd_sync.bats +++ b/tests/e2e/lnd_sync.bats @@ -5,7 +5,7 @@ load "helpers" setup_file() { restart_bitcoin_stack reset_pg - bitcoind_init default + bitcoind_init start_daemon bria_lnd_init } @@ -34,7 +34,7 @@ teardown_file() { bitcoin_cli -regtest sendtoaddress ${lnd_address} 1 for i in {1..30}; do - cache_wallet_balance default + cache_wallet_balance [[ $(cached_pending_income) == 100000000 ]] && break sleep 1 done @@ -51,7 +51,7 @@ teardown_file() { bitcoin_cli -generate 2 for i in {1..30}; do - cache_wallet_balance default + cache_wallet_balance [[ $(cached_current_settled) == 100000000 ]] && break sleep 1 done @@ -68,7 +68,7 @@ teardown_file() { bitcoind_address=$(bitcoin_cli -regtest getnewaddress) lnd_cli sendcoins --addr=${bitcoind_address} --amt=50000000 for i in {1..30}; do - cache_wallet_balance default + cache_wallet_balance [[ $(cached_pending_outgoing) == 50000000 ]] && break sleep 1 done @@ -84,7 +84,7 @@ teardown_file() { bitcoin_cli -generate 1 for i in {1..30}; do - cache_wallet_balance default + cache_wallet_balance [[ $(cached_current_settled) != 0 ]] && break sleep 1 done @@ -111,7 +111,7 @@ teardown_file() { lnd_cli sendcoins --addr=${bitcoind_address} --amt=210000000 --min_confs 0 for i in {1..30}; do - cache_wallet_balance default + cache_wallet_balance [[ $(cached_pending_outgoing) == 210000000 ]] && break sleep 1 done @@ -120,7 +120,7 @@ teardown_file() { bitcoin_cli -generate 2 for i in {1..30}; do - cache_wallet_balance default + cache_wallet_balance [[ $(cached_pending_outgoing) == 0 ]] && break sleep 1 done @@ -135,7 +135,7 @@ teardown_file() { bitcoin_cli -generate 1 for i in {1..30}; do - cache_wallet_balance default + cache_wallet_balance [[ $(cached_encumbered_fees) == 0 ]] && break sleep 1 done @@ -150,7 +150,7 @@ teardown_file() { lnd_cli sendcoins --addr=${bitcoind_address} --amt=60000000 --min_confs 0 for i in {1..30}; do - cache_wallet_balance default + cache_wallet_balance [[ $(cached_pending_outgoing) == 60000000 ]] && break sleep 1 done @@ -159,7 +159,7 @@ teardown_file() { bitcoin_cli -generate 2 for i in {1..30}; do - cache_wallet_balance default + cache_wallet_balance [[ $(cached_pending_outgoing) == 0 ]] && break sleep 1 done diff --git a/tests/e2e/multisig_payout.bats b/tests/e2e/multisig_payout.bats index 4cb9ac30..d6f5e95d 100644 --- a/tests/e2e/multisig_payout.bats +++ b/tests/e2e/multisig_payout.bats @@ -96,7 +96,8 @@ teardown_file() { unsigned_psbt=$(bria_cmd get-batch -b "${batch_id}" | jq -r '.unsignedPsbt') signed_psbt=$(bitcoin_signer_cli walletprocesspsbt "${unsigned_psbt}" true ALL true | jq -r '.psbt') - bria_cmd submit-signed-psbt -b "${batch_id}" -x key1 -s "${signed_psbt}" + bria_cmd submit-signed-psbt -b "${batch_id}" -x key1 -s "${signed_psbt}" + bria_cmd set-signer-config --xpub lnd_key lnd --endpoint "${LND_ENDPOINT}" --macaroon-file "./dev/lnd/regtest/lnd.admin.macaroon" --cert-file "./dev/lnd/tls.cert" for i in {1..20}; do signing_status=$(bria_cmd get-batch -b "${batch_id}" | jq -r '.sessions[0].state') diff --git a/tests/e2e/outbox.bats b/tests/e2e/outbox.bats index 7dee5b7d..706cd518 100644 --- a/tests/e2e/outbox.bats +++ b/tests/e2e/outbox.bats @@ -5,9 +5,9 @@ load "helpers" setup_file() { restart_bitcoin_stack reset_pg - bitcoind_init default + bitcoind_init start_daemon - bria_init default + bria_init } teardown_file() { @@ -24,7 +24,7 @@ teardown_file() { done event=$(bria_cmd watch-events -a 0 -o | jq -r '.payload.utxoDetected') [ "$event" != "null" ] || exit 1 - cache_wallet_balance default + cache_wallet_balance [[ $(cached_pending_income) == 100000000 ]] || exit 1; restart_bitcoin_stack @@ -33,7 +33,7 @@ teardown_file() { event=$(bria_cmd watch-events -a 1 -o | jq -r '.payload.utxoDropped') [ "$event" != "null" ] || exit 1 - cache_wallet_balance default + cache_wallet_balance [[ $(cached_pending_income) == 0 ]] || exit 1; } diff --git a/tests/e2e/payout.bats b/tests/e2e/payout.bats index b846a52d..b0be2ec3 100644 --- a/tests/e2e/payout.bats +++ b/tests/e2e/payout.bats @@ -5,9 +5,9 @@ load "helpers" setup_file() { restart_bitcoin_stack reset_pg - bitcoind_init default + bitcoind_init start_daemon - bria_init default + bria_init } teardown_file() { @@ -29,7 +29,7 @@ teardown_file() { [[ "${n_utxos}" == "2" ]] && break sleep 1 done - cache_wallet_balance default + cache_wallet_balance [[ $(cached_encumbered_fees) != 0 ]] || exit 1 [[ $(cached_pending_income) == 200000000 ]] || exit 1; } @@ -43,7 +43,7 @@ teardown_file() { [[ "${n_payouts}" == "2" ]] || exit 1 batch_id=$(bria_cmd list-payouts -w default | jq '.payouts[0].batchId') [[ "${batch_id}" == "null" ]] || exit 1 - cache_wallet_balance default + cache_wallet_balance [[ $(cached_encumbered_outgoing) == 150000000 && $(cached_pending_outgoing) == 0 ]] || exit 1 } @@ -55,7 +55,7 @@ teardown_file() { [[ "${utxo_height}" != "null" ]] && break; sleep 1 done - cache_wallet_balance default + cache_wallet_balance [[ $(cached_pending_income) == 0 ]] || exit 1 for i in {1..20}; do @@ -65,7 +65,7 @@ teardown_file() { done [[ "${batch_id}" != "null" ]] || exit 1 for i in {1..60}; do - cache_wallet_balance default + cache_wallet_balance [[ $(cached_pending_outgoing) == 150000000 ]] && break; sleep 1 done @@ -85,7 +85,7 @@ teardown_file() { [[ "${signing_failure_reason}" == "SignerConfigMissing" ]] || exit 1 - cache_wallet_balance default + cache_wallet_balance [[ $(cached_pending_income) == 0 ]] || exit 1 bria_cmd set-signer-config \ @@ -106,7 +106,7 @@ teardown_file() { fi for i in {1..20}; do - cache_wallet_balance default + cache_wallet_balance [[ $(cached_pending_income) != 0 ]] && break; sleep 1 done @@ -116,7 +116,7 @@ teardown_file() { bitcoin_cli -generate 2 for i in {1..20}; do - cache_wallet_balance default + cache_wallet_balance [[ $(cached_current_settled) != 0 ]] && break; sleep 1 done From 77e75673a3a412d0c7a60063987f5970a074a9a9 Mon Sep 17 00:00:00 2001 From: Vaibhav Date: Tue, 4 Jul 2023 12:34:56 +0530 Subject: [PATCH 16/26] chore: fix name --- tests/e2e/helpers.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/helpers.bash b/tests/e2e/helpers.bash index ff620069..1eb811e9 100644 --- a/tests/e2e/helpers.bash +++ b/tests/e2e/helpers.bash @@ -148,7 +148,7 @@ bria_init() { if [[ "${BRIA_CONFIG}" == "docker" ]]; then retry 10 1 bria_cmd import-xpub -x "${key1}" -n key1 -d m/48h/1h/0h/2h - bria_cmd import-xpub -x "${key2}" -n key2 -d m/84h/0h/0h + bria_cmd import-xpub -x "${key2}" -n lnd_key -d m/84h/0h/0h bria_cmd create-wallet -n multisig sorted-multisig -x key1 lnd_key -t 1 else bria_cmd import-xpub -x "${key1}" -n key1 -d m/48h/1h/0h/2h From 3cc27ad5d5fa2783b2d5005ec788167f69885501 Mon Sep 17 00:00:00 2001 From: bodymindarts Date: Tue, 4 Jul 2023 09:34:25 +0200 Subject: [PATCH 17/26] test: extract retry_cmd in bria_init helper --- tests/e2e/helpers.bash | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/tests/e2e/helpers.bash b/tests/e2e/helpers.bash index 1eb811e9..40c2efc7 100644 --- a/tests/e2e/helpers.bash +++ b/tests/e2e/helpers.bash @@ -127,34 +127,25 @@ bria_init() { local wallet_type="${1:-default}" if [[ "${BRIA_CONFIG}" == "docker" ]]; then - retry 10 1 bria_cmd admin bootstrap + retry_cmd="retry 10 1" else - bria_cmd admin bootstrap + retry_cmd="" fi + $retry_cmd bria_cmd admin bootstrap + bria_cmd admin create-account -n default if [[ "${wallet_type}" == "default" ]]; then - if [[ "${BRIA_CONFIG}" == "docker" ]]; then - retry 10 1 bria_cmd create-wallet -n default descriptors -d "wpkh([6f2fa1b2/84'/0'/0']tpubDDDDGYiFda8HfJRc2AHFJDxVzzEtBPrKsbh35EaW2UGd5qfzrF2G87ewAgeeRyHEz4iB3kvhAYW1sH6dpLepTkFUzAktumBN8AXeXWE9nd1/0/*)#l6n08zmr" \ - -c "wpkh([6f2fa1b2/84'/0'/0']tpubDDDDGYiFda8HfJRc2AHFJDxVzzEtBPrKsbh35EaW2UGd5qfzrF2G87ewAgeeRyHEz4iB3kvhAYW1sH6dpLepTkFUzAktumBN8AXeXWE9nd1/1/*)#wwkw6htm" - else - bria_cmd create-wallet -n default descriptors -d "wpkh([6f2fa1b2/84'/0'/0']tpubDDDDGYiFda8HfJRc2AHFJDxVzzEtBPrKsbh35EaW2UGd5qfzrF2G87ewAgeeRyHEz4iB3kvhAYW1sH6dpLepTkFUzAktumBN8AXeXWE9nd1/0/*)#l6n08zmr" \ + $retry_cmd bria_cmd create-wallet -n default descriptors -d "wpkh([6f2fa1b2/84'/0'/0']tpubDDDDGYiFda8HfJRc2AHFJDxVzzEtBPrKsbh35EaW2UGd5qfzrF2G87ewAgeeRyHEz4iB3kvhAYW1sH6dpLepTkFUzAktumBN8AXeXWE9nd1/0/*)#l6n08zmr" \ -c "wpkh([6f2fa1b2/84'/0'/0']tpubDDDDGYiFda8HfJRc2AHFJDxVzzEtBPrKsbh35EaW2UGd5qfzrF2G87ewAgeeRyHEz4iB3kvhAYW1sH6dpLepTkFUzAktumBN8AXeXWE9nd1/1/*)#wwkw6htm" - fi elif [[ "${wallet_type}" == "multisig" ]]; then local key1="tpubDE8HT914zGpxhJhgoMX35xgNyjHy5d1neGXHjTLAtuUssTA7tNWNs177JsFPbJwD5FBXCHJYbwUC9AzSEpYHC4hKgaCvZyZTuCbWfNUWXoM" local key2="tpubDD4vFnWuTMEcZiaaZPgvzeGyMzWe6qHW8gALk5Md9kutDvtdDjYFwzauEFFRHgov8pAwup5jX88j5YFyiACsPf3pqn5hBjvuTLRAseaJ6b4" - if [[ "${BRIA_CONFIG}" == "docker" ]]; then - retry 10 1 bria_cmd import-xpub -x "${key1}" -n key1 -d m/48h/1h/0h/2h - bria_cmd import-xpub -x "${key2}" -n lnd_key -d m/84h/0h/0h - bria_cmd create-wallet -n multisig sorted-multisig -x key1 lnd_key -t 1 - else - bria_cmd import-xpub -x "${key1}" -n key1 -d m/48h/1h/0h/2h - bria_cmd import-xpub -x "${key2}" -n lnd_key -d m/84h/0h/0h - bria_cmd create-wallet -n multisig sorted-multisig -x key1 lnd_key -t 2 - fi + $retry_cmd bria_cmd import-xpub -x "${key1}" -n key1 -d m/48h/1h/0h/2h + bria_cmd import-xpub -x "${key2}" -n lnd_key -d m/84h/0h/0h + bria_cmd create-wallet -n multisig sorted-multisig -x key1 lnd_key -t 2 fi echo "Bria Initialization Complete" From 4d93d40f08d761262ea50b83e6401a661277aa37 Mon Sep 17 00:00:00 2001 From: bodymindarts Date: Tue, 4 Jul 2023 09:59:50 +0200 Subject: [PATCH 18/26] chore: incomplete finalization step --- src/job/batch_signing.rs | 3 ++- src/wallet/keychain/wallet.rs | 9 ++++++--- tests/psbt_builder.rs | 1 + 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/job/batch_signing.rs b/src/job/batch_signing.rs index 4d6dc9f7..1d8b7cfa 100644 --- a/src/job/batch_signing.rs +++ b/src/job/batch_signing.rs @@ -145,12 +145,13 @@ pub async fn execute( .await, last_err, ) { - (Ok(finalized_psbt), _) => { + (Ok(Some(finalized_psbt)), _) => { let tx = finalized_psbt.extract_tx(); batches.set_signed_tx(data.batch_id, tx).await?; Ok((data, true)) } (_, Some(e)) => Err(e.into()), + (Ok(None), _) => Ok((data, false)), _ if stalled => Ok((data, false)), (Err(err), _) => Err(err.into()), } diff --git a/src/wallet/keychain/wallet.rs b/src/wallet/keychain/wallet.rs index d5b670bc..9f1f10eb 100644 --- a/src/wallet/keychain/wallet.rs +++ b/src/wallet/keychain/wallet.rs @@ -46,11 +46,14 @@ impl KeychainWallet { pub async fn finalize_psbt( &self, mut psbt: psbt::PartiallySignedTransaction, - ) -> Result { + ) -> Result, BdkError> { match self .with_wallet(move |wallet| { - wallet.finalize_psbt(&mut psbt, SignOptions::default())?; - Ok::<_, BdkError>(psbt) + if wallet.finalize_psbt(&mut psbt, SignOptions::default())? { + Ok::<_, BdkError>(Some(psbt)) + } else { + Ok::<_, BdkError>(None) + } }) .await { diff --git a/tests/psbt_builder.rs b/tests/psbt_builder.rs index 7620de69..53b5ae0a 100644 --- a/tests/psbt_builder.rs +++ b/tests/psbt_builder.rs @@ -207,6 +207,7 @@ async fn build_psbt() -> anyhow::Result<()> { let tx = domain_current_keychain .finalize_psbt(signed_psbt) .await? + .expect("Finalize should have completed") .extract_tx(); helpers::electrum_blockchain().await?.broadcast(&tx)?; From 419df372bc03b1e8485e69fbb07f62583dd72a10 Mon Sep 17 00:00:00 2001 From: Vaibhav Date: Tue, 4 Jul 2023 14:07:42 +0530 Subject: [PATCH 19/26] chore: address pr reviews --- src/api/server/convert.rs | 6 ++++- src/app/error.rs | 2 -- tests/e2e/multisig_payout.bats | 41 ++++++---------------------------- 3 files changed, 12 insertions(+), 37 deletions(-) diff --git a/src/api/server/convert.rs b/src/api/server/convert.rs index e4cd6a23..dd1b539b 100644 --- a/src/api/server/convert.rs +++ b/src/api/server/convert.rs @@ -603,7 +603,10 @@ impl From for tonic::Status { ApplicationError::SigningSessionNotFoundForXPubId(_) => { tonic::Status::not_found(err.to_string()) } - ApplicationError::SubmittedPsbtIsNotValid => { + ApplicationError::WalletError(WalletError::PsbtDoesNotHaveValidSignatures) => { + tonic::Status::invalid_argument(err.to_string()) + } + ApplicationError::WalletError(WalletError::UnsignedTxnMismatch) => { tonic::Status::invalid_argument(err.to_string()) } ApplicationError::CouldNotParseIncomingPsbt(_) => { @@ -620,6 +623,7 @@ impl ToTraceLevel for tonic::Status { tonic::Code::NotFound => tracing::Level::WARN, tonic::Code::AlreadyExists => tracing::Level::WARN, tonic::Code::PermissionDenied => tracing::Level::WARN, + tonic::Code::InvalidArgument => tracing::Level::WARN, _ => tracing::Level::ERROR, } } diff --git a/src/app/error.rs b/src/app/error.rs index 1ca49a5a..2768d714 100644 --- a/src/app/error.rs +++ b/src/app/error.rs @@ -69,6 +69,4 @@ pub enum ApplicationError { SigningSessionNotFoundForXPubId(crate::primitives::XPubId), #[error("Could not parse incoming psbt: {0}")] CouldNotParseIncomingPsbt(bitcoin::psbt::PsbtParseError), - #[error("Submitted Psbt is not valid")] - SubmittedPsbtIsNotValid, } diff --git a/tests/e2e/multisig_payout.bats b/tests/e2e/multisig_payout.bats index d6f5e95d..3ef75015 100644 --- a/tests/e2e/multisig_payout.bats +++ b/tests/e2e/multisig_payout.bats @@ -22,45 +22,34 @@ teardown_file() { exit 1 fi - bitcoin_cli -regtest sendtoaddress ${bria_address} 1 bitcoin_cli -regtest sendtoaddress ${bria_address} 1 for i in {1..30}; do n_utxos=$(bria_cmd list-utxos -w multisig | jq '.keychains[0].utxos | length') - [[ "${n_utxos}" == "2" ]] && break + [[ "${n_utxos}" == "1" ]] && break sleep 1 done cache_wallet_balance multisig [[ $(cached_encumbered_fees) != 0 ]] || exit 1 - [[ $(cached_pending_income) == 200000000 ]] || exit 1; + [[ $(cached_pending_income) == 100000000 ]] || exit 1; } -@test "mutlisig_payout: Create payout queue and have two queued payouts on it" { +@test "mutlisig_payout: Create payout queue and have a queued payout on it" { bria_cmd create-payout-queue --name high --interval-trigger 5 bria_cmd submit-payout --wallet multisig --queue-name high --destination bcrt1q208tuy5rd3kvy8xdpv6yrczg7f3mnlk3lql7ej --amount 75000000 - bria_cmd submit-payout --wallet multisig --queue-name high --destination bcrt1q3rr02wkkvkwcj7h0nr9dqr9z3z3066pktat7kv --amount 75000000 --metadata '{"foo":{"bar":"baz"}}' n_payouts=$(bria_cmd list-payouts -w multisig | jq '.payouts | length') - [[ "${n_payouts}" == "2" ]] || exit 1 + [[ "${n_payouts}" == "1" ]] || exit 1 batch_id=$(bria_cmd list-payouts -w multisig | jq '.payouts[0].batchId') [[ "${batch_id}" == "null" ]] || exit 1 cache_wallet_balance multisig - [[ $(cached_encumbered_outgoing) == 150000000 && $(cached_pending_outgoing) == 0 ]] || exit 1 + [[ $(cached_encumbered_outgoing) == 75000000 && $(cached_pending_outgoing) == 0 ]] || exit 1 } -@test "multisig_payout: Settling income means batch is created" { - bitcoin_cli -generate 20 - - for i in {1..30}; do - utxo_height=$(bria_cmd list-utxos -w multisig | jq '.keychains[0].utxos[0].blockHeight') - [[ "${utxo_height}" != "null" ]] && break; - sleep 1 - done - - cache_wallet_balance multisig - [[ $(cached_pending_income) == 0 ]] || exit 1 +@test "multisig_payout: Signing unsigned psbt and submitting signed psbt" { + bitcoin_cli -generate 5 for i in {1..20}; do batch_id=$(bria_cmd list-payouts -w multisig | jq -r '.payouts[0].batchId') @@ -69,19 +58,6 @@ teardown_file() { done [[ "${batch_id}" != "null" ]] || exit 1 - for i in {1..60}; do - cache_wallet_balance multisig - [[ $(cached_pending_outgoing) == 150000000 ]] && break; - sleep 1 - done - - [[ $(cached_pending_outgoing) == 150000000 ]] || exit 1 - [[ $(cached_pending_fees) != 0 ]] || exit 1 - [[ $(cached_encumbered_fees) == 0 ]] || exit 1 -} - -@test "multisig_payout: Signing unsigned psbt and submitting signed psbt" { - batch_id=$(bria_cmd list-payouts -w multisig | jq -r '.payouts[0].batchId') for i in {1..20}; do signing_failure_reason=$(bria_cmd get-batch -b "${batch_id}" | jq -r '.signingSessions[0].failureReason') @@ -91,9 +67,6 @@ teardown_file() { [[ "${signing_failure_reason}" == "SignerConfigMissing" ]] || exit 1 - cache_wallet_balance multisig - [[ $(cached_pending_income) == 0 ]] || exit 1 - unsigned_psbt=$(bria_cmd get-batch -b "${batch_id}" | jq -r '.unsignedPsbt') signed_psbt=$(bitcoin_signer_cli walletprocesspsbt "${unsigned_psbt}" true ALL true | jq -r '.psbt') bria_cmd submit-signed-psbt -b "${batch_id}" -x key1 -s "${signed_psbt}" From 8ed7722752225e2bcc9fe7a691f5568ab5ff4d8a Mon Sep 17 00:00:00 2001 From: Vaibhav Date: Tue, 4 Jul 2023 15:10:33 +0530 Subject: [PATCH 20/26] chore: create a new bitcoin-signer to sign psbt --- docker-compose.override.yml | 3 +++ docker-compose.yml | 10 ++++++++++ .../bitcoind_multisig_signer_descriptors.json | 2 +- tests/e2e/helpers.bash | 17 ++++++++++++----- tests/e2e/multisig_payout.bats | 4 ++-- 5 files changed, 28 insertions(+), 8 deletions(-) diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 04517d44..5744146d 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -13,6 +13,9 @@ services: bitcoind-signer: ports: - "18543:18443" + bitcoind-signer2: + ports: + - "18544:18443" lnd: ports: - "10009:10009" diff --git a/docker-compose.yml b/docker-compose.yml index 04e70d5f..6237028c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,6 +10,7 @@ services: - otel-agent - fulcrum - mempool + - bitcoind-signer2 postgres: image: postgres:14.1 environment: @@ -85,6 +86,15 @@ services: command: - | bitcoind -connect=bitcoind:18444 + bitcoind-signer2: + image: lncm/bitcoind:v24.0.1 + volumes: + - ${HOST_PROJECT_PATH:-.}/dev/bitcoind/bitcoin.conf:/data/.bitcoin/bitcoin.conf + depends_on: [ bitcoind ] + entrypoint: [ "/bin/sh", "-c" ] + command: + - | + bitcoind -connect=bitcoind:18444 lnd: image: lightninglabs/lnd:v0.15.4-beta volumes: diff --git a/tests/e2e/bitcoind_multisig_signer_descriptors.json b/tests/e2e/bitcoind_multisig_signer_descriptors.json index b6eaf040..13267ae9 100644 --- a/tests/e2e/bitcoind_multisig_signer_descriptors.json +++ b/tests/e2e/bitcoind_multisig_signer_descriptors.json @@ -1 +1 @@ -[{"active":true,"desc":"wsh(sortedmulti(2,[186ad0c4/48h/1h/0h/2h]tprv8hSFJixpqu9HoqftuhrSgZ2GQhn2vHpt4xvWSwHsUdgV2xuMFygngWVF8kxdGr983KngUHsuw3onLZZCivCHRg398cVd65TQxe8mjd467Qz/0/*,[8df69d29/84h/0h/0h]tpubDD4vFnWuTMEcZiaaZPgvzeGyMzWe6qHW8gALk5Md9kutDvtdDjYFwzauEFFRHgov8pAwup5jX88j5YFyiACsPf3pqn5hBjvuTLRAseaJ6b4/0/*))#9rj4qzrz","timestamp":0},{"active":true,"desc":"wsh(sortedmulti(2,[186ad0c4/48h/1h/0h/2h]tprv8hSFJixpqu9HoqftuhrSgZ2GQhn2vHpt4xvWSwHsUdgV2xuMFygngWVF8kxdGr983KngUHsuw3onLZZCivCHRg398cVd65TQxe8mjd467Qz/1/*,[8df69d29/84h/0h/0h]tpubDD4vFnWuTMEcZiaaZPgvzeGyMzWe6qHW8gALk5Md9kutDvtdDjYFwzauEFFRHgov8pAwup5jX88j5YFyiACsPf3pqn5hBjvuTLRAseaJ6b4/1/*))#vt68gsll","internal":true,"timestamp":0}] +[{"active":true,"desc":"wsh(sortedmulti(2,[5abe7e31/48h/1h/0h/2h]tprv8htBXEPm6A9AT28eUYqXRkdPSRjT2VZ7yjYuC1gxNbsE4KWnUyK83LMEFm2NMFiXAUE2sFUx1x8BZT4ZnBfdnXty5HisCZv3J2FPZVSF87B/0/*,[40e993e5/48h/1h/0h/2h]tpubDEPCxBfMFRNdfJaUeoTmepLJ6ZQmeTiU1Sko2sdx1R3tmPpZemRUjdAHqtmLfaVrBg1NBx2Yx3cVrsZ2FTyBuhiH9mPSL5ozkaTh1iZUTZx/0/*))#9jyr5fa2","timestamp":0},{"active":true,"desc":"wsh(sortedmulti(2,[5abe7e31/48h/1h/0h/2h]tprv8htBXEPm6A9AT28eUYqXRkdPSRjT2VZ7yjYuC1gxNbsE4KWnUyK83LMEFm2NMFiXAUE2sFUx1x8BZT4ZnBfdnXty5HisCZv3J2FPZVSF87B/1/*,[40e993e5/48h/1h/0h/2h]tpubDEPCxBfMFRNdfJaUeoTmepLJ6ZQmeTiU1Sko2sdx1R3tmPpZemRUjdAHqtmLfaVrBg1NBx2Yx3cVrsZ2FTyBuhiH9mPSL5ozkaTh1iZUTZx/1/*))#uph866gl","internal":true,"timestamp":0}] diff --git a/tests/e2e/helpers.bash b/tests/e2e/helpers.bash index 40c2efc7..c4717ff6 100644 --- a/tests/e2e/helpers.bash +++ b/tests/e2e/helpers.bash @@ -6,6 +6,7 @@ if [[ "${BRIA_CONFIG}" == "docker" ]]; then COMPOSE_FILE_ARG="-f docker-compose.yml" fi BITCOIND_SIGNER_ENDPOINT="${BITCOIND_SIGNER_ENDPOINT:-https://localhost:18543}" +BITCOIND_SIGNER2_ENDPOINT="${BITCOIND_SIGNER2_ENDPOINT:-https://localhost:18544}" LND_HOST="${LND_HOST:-localhost}" LND_ENDPOINT="https://${LND_HOST}:10009" SATS_IN_ONE_BTC=100000000 @@ -60,6 +61,10 @@ bitcoin_signer_cli() { docker exec "${COMPOSE_PROJECT_NAME}-bitcoind-signer-1" bitcoin-cli $@ } +bitcoin_signer2_cli() { + docker exec "${COMPOSE_PROJECT_NAME}-bitcoind-signer2-1" bitcoin-cli $@ +} + convert_btc_to_sats() { echo "$1 * $SATS_IN_ONE_BTC / 1" | bc } @@ -107,8 +112,10 @@ bitcoind_init() { bitcoin_signer_cli createwallet "default" || true bitcoin_signer_cli -rpcwallet=default importdescriptors "$(cat ${REPO_ROOT}/tests/e2e/bitcoind_signer_descriptors.json)" elif [[ "${wallet}" == "multisig" ]]; then - bitcoin_signer_cli createwallet "multisig" || true + bitcoin_signer_cli createwallet "multisig" || true bitcoin_signer_cli -rpcwallet=multisig importdescriptors "$(cat ${REPO_ROOT}/tests/e2e/bitcoind_multisig_signer_descriptors.json)" + bitcoin_signer2_cli createwallet "multisig2" || true + bitcoin_signer2_cli -rpcwallet=multisig2 importdescriptors "$(cat ${REPO_ROOT}/tests/e2e/bitcoind_multisig2_signer_descriptors.json)" fi } @@ -140,12 +147,12 @@ bria_init() { $retry_cmd bria_cmd create-wallet -n default descriptors -d "wpkh([6f2fa1b2/84'/0'/0']tpubDDDDGYiFda8HfJRc2AHFJDxVzzEtBPrKsbh35EaW2UGd5qfzrF2G87ewAgeeRyHEz4iB3kvhAYW1sH6dpLepTkFUzAktumBN8AXeXWE9nd1/0/*)#l6n08zmr" \ -c "wpkh([6f2fa1b2/84'/0'/0']tpubDDDDGYiFda8HfJRc2AHFJDxVzzEtBPrKsbh35EaW2UGd5qfzrF2G87ewAgeeRyHEz4iB3kvhAYW1sH6dpLepTkFUzAktumBN8AXeXWE9nd1/1/*)#wwkw6htm" elif [[ "${wallet_type}" == "multisig" ]]; then - local key1="tpubDE8HT914zGpxhJhgoMX35xgNyjHy5d1neGXHjTLAtuUssTA7tNWNs177JsFPbJwD5FBXCHJYbwUC9AzSEpYHC4hKgaCvZyZTuCbWfNUWXoM" - local key2="tpubDD4vFnWuTMEcZiaaZPgvzeGyMzWe6qHW8gALk5Md9kutDvtdDjYFwzauEFFRHgov8pAwup5jX88j5YFyiACsPf3pqn5hBjvuTLRAseaJ6b4" + local key1="tpubDEaDfeS1EXpqLVASNCW7qAHW1TFPBpk2Z39gUXjFnsfctomZ7N8iDpy6RuGwqdXAAZ5sr5kQZrxyuEn15tqPJjM4mcPSuXzV27AWRD3p9Q4" + local key2="tpubDEPCxBfMFRNdfJaUeoTmepLJ6ZQmeTiU1Sko2sdx1R3tmPpZemRUjdAHqtmLfaVrBg1NBx2Yx3cVrsZ2FTyBuhiH9mPSL5ozkaTh1iZUTZx" $retry_cmd bria_cmd import-xpub -x "${key1}" -n key1 -d m/48h/1h/0h/2h - bria_cmd import-xpub -x "${key2}" -n lnd_key -d m/84h/0h/0h - bria_cmd create-wallet -n multisig sorted-multisig -x key1 lnd_key -t 2 + bria_cmd import-xpub -x "${key2}" -n key2 -d m/48h/1h/0h/2h + bria_cmd create-wallet -n multisig sorted-multisig -x key1 key2 -t 2 fi echo "Bria Initialization Complete" diff --git a/tests/e2e/multisig_payout.bats b/tests/e2e/multisig_payout.bats index 3ef75015..c6f3abe1 100644 --- a/tests/e2e/multisig_payout.bats +++ b/tests/e2e/multisig_payout.bats @@ -70,8 +70,8 @@ teardown_file() { unsigned_psbt=$(bria_cmd get-batch -b "${batch_id}" | jq -r '.unsignedPsbt') signed_psbt=$(bitcoin_signer_cli walletprocesspsbt "${unsigned_psbt}" true ALL true | jq -r '.psbt') bria_cmd submit-signed-psbt -b "${batch_id}" -x key1 -s "${signed_psbt}" - bria_cmd set-signer-config --xpub lnd_key lnd --endpoint "${LND_ENDPOINT}" --macaroon-file "./dev/lnd/regtest/lnd.admin.macaroon" --cert-file "./dev/lnd/tls.cert" - + signed_psbt2=$(bitcoin_signer2_cli walletprocesspsbt "${unsigned_psbt}" true ALL true | jq -r '.psbt') + bria_cmd submit-signed-psbt -b "${batch_id}" -x key2 -s "${signed_psbt2}" for i in {1..20}; do signing_status=$(bria_cmd get-batch -b "${batch_id}" | jq -r '.sessions[0].state') [[ "${signing_status}" == "Complete" ]] && break From ec5911cf704117657ed57f5dcc09d3a3fc301ab1 Mon Sep 17 00:00:00 2001 From: Vaibhav Date: Tue, 4 Jul 2023 15:23:32 +0530 Subject: [PATCH 21/26] chore: add new bitcoin-signer descriptor --- tests/e2e/bitcoind_multisig2_signer_descriptors.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 tests/e2e/bitcoind_multisig2_signer_descriptors.json diff --git a/tests/e2e/bitcoind_multisig2_signer_descriptors.json b/tests/e2e/bitcoind_multisig2_signer_descriptors.json new file mode 100644 index 00000000..b023d306 --- /dev/null +++ b/tests/e2e/bitcoind_multisig2_signer_descriptors.json @@ -0,0 +1 @@ +[{"active":true,"desc":"wsh(sortedmulti(2,[5abe7e31/48h/1h/0h/2h]tpubDEaDfeS1EXpqLVASNCW7qAHW1TFPBpk2Z39gUXjFnsfctomZ7N8iDpy6RuGwqdXAAZ5sr5kQZrxyuEn15tqPJjM4mcPSuXzV27AWRD3p9Q4/0/*,[40e993e5/48h/1h/0h/2h]tprv8hhAomd773gxmqYgm9oBFQgBXXtqV8XZS9A1kMbeb9FVvuZo2NbtZ8YRfoWKq1e33GdELob79aK46CQLVHmfvGKJkFK1ExP7zejkT1fkqdD/0/*))#tfsx0cwk","timestamp":0},{"active":true,"desc":"wsh(sortedmulti(2,[5abe7e31/48h/1h/0h/2h]tpubDEaDfeS1EXpqLVASNCW7qAHW1TFPBpk2Z39gUXjFnsfctomZ7N8iDpy6RuGwqdXAAZ5sr5kQZrxyuEn15tqPJjM4mcPSuXzV27AWRD3p9Q4/1/*,[40e993e5/48h/1h/0h/2h]tprv8hhAomd773gxmqYgm9oBFQgBXXtqV8XZS9A1kMbeb9FVvuZo2NbtZ8YRfoWKq1e33GdELob79aK46CQLVHmfvGKJkFK1ExP7zejkT1fkqdD/1/*))#j6rzptmr","internal":true,"timestamp":0}] From e3b5092a14778b4cf1d80bcfd2d8f120c4127292 Mon Sep 17 00:00:00 2001 From: Vaibhav Date: Tue, 4 Jul 2023 16:58:36 +0530 Subject: [PATCH 22/26] revert: revert last 2 commits --- docker-compose.override.yml | 3 --- docker-compose.yml | 10 ---------- .../bitcoind_multisig2_signer_descriptors.json | 1 - .../bitcoind_multisig_signer_descriptors.json | 2 +- tests/e2e/helpers.bash | 17 +++++------------ tests/e2e/multisig_payout.bats | 4 ++-- 6 files changed, 8 insertions(+), 29 deletions(-) delete mode 100644 tests/e2e/bitcoind_multisig2_signer_descriptors.json diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 5744146d..04517d44 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -13,9 +13,6 @@ services: bitcoind-signer: ports: - "18543:18443" - bitcoind-signer2: - ports: - - "18544:18443" lnd: ports: - "10009:10009" diff --git a/docker-compose.yml b/docker-compose.yml index 6237028c..04e70d5f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,7 +10,6 @@ services: - otel-agent - fulcrum - mempool - - bitcoind-signer2 postgres: image: postgres:14.1 environment: @@ -86,15 +85,6 @@ services: command: - | bitcoind -connect=bitcoind:18444 - bitcoind-signer2: - image: lncm/bitcoind:v24.0.1 - volumes: - - ${HOST_PROJECT_PATH:-.}/dev/bitcoind/bitcoin.conf:/data/.bitcoin/bitcoin.conf - depends_on: [ bitcoind ] - entrypoint: [ "/bin/sh", "-c" ] - command: - - | - bitcoind -connect=bitcoind:18444 lnd: image: lightninglabs/lnd:v0.15.4-beta volumes: diff --git a/tests/e2e/bitcoind_multisig2_signer_descriptors.json b/tests/e2e/bitcoind_multisig2_signer_descriptors.json deleted file mode 100644 index b023d306..00000000 --- a/tests/e2e/bitcoind_multisig2_signer_descriptors.json +++ /dev/null @@ -1 +0,0 @@ -[{"active":true,"desc":"wsh(sortedmulti(2,[5abe7e31/48h/1h/0h/2h]tpubDEaDfeS1EXpqLVASNCW7qAHW1TFPBpk2Z39gUXjFnsfctomZ7N8iDpy6RuGwqdXAAZ5sr5kQZrxyuEn15tqPJjM4mcPSuXzV27AWRD3p9Q4/0/*,[40e993e5/48h/1h/0h/2h]tprv8hhAomd773gxmqYgm9oBFQgBXXtqV8XZS9A1kMbeb9FVvuZo2NbtZ8YRfoWKq1e33GdELob79aK46CQLVHmfvGKJkFK1ExP7zejkT1fkqdD/0/*))#tfsx0cwk","timestamp":0},{"active":true,"desc":"wsh(sortedmulti(2,[5abe7e31/48h/1h/0h/2h]tpubDEaDfeS1EXpqLVASNCW7qAHW1TFPBpk2Z39gUXjFnsfctomZ7N8iDpy6RuGwqdXAAZ5sr5kQZrxyuEn15tqPJjM4mcPSuXzV27AWRD3p9Q4/1/*,[40e993e5/48h/1h/0h/2h]tprv8hhAomd773gxmqYgm9oBFQgBXXtqV8XZS9A1kMbeb9FVvuZo2NbtZ8YRfoWKq1e33GdELob79aK46CQLVHmfvGKJkFK1ExP7zejkT1fkqdD/1/*))#j6rzptmr","internal":true,"timestamp":0}] diff --git a/tests/e2e/bitcoind_multisig_signer_descriptors.json b/tests/e2e/bitcoind_multisig_signer_descriptors.json index 13267ae9..b6eaf040 100644 --- a/tests/e2e/bitcoind_multisig_signer_descriptors.json +++ b/tests/e2e/bitcoind_multisig_signer_descriptors.json @@ -1 +1 @@ -[{"active":true,"desc":"wsh(sortedmulti(2,[5abe7e31/48h/1h/0h/2h]tprv8htBXEPm6A9AT28eUYqXRkdPSRjT2VZ7yjYuC1gxNbsE4KWnUyK83LMEFm2NMFiXAUE2sFUx1x8BZT4ZnBfdnXty5HisCZv3J2FPZVSF87B/0/*,[40e993e5/48h/1h/0h/2h]tpubDEPCxBfMFRNdfJaUeoTmepLJ6ZQmeTiU1Sko2sdx1R3tmPpZemRUjdAHqtmLfaVrBg1NBx2Yx3cVrsZ2FTyBuhiH9mPSL5ozkaTh1iZUTZx/0/*))#9jyr5fa2","timestamp":0},{"active":true,"desc":"wsh(sortedmulti(2,[5abe7e31/48h/1h/0h/2h]tprv8htBXEPm6A9AT28eUYqXRkdPSRjT2VZ7yjYuC1gxNbsE4KWnUyK83LMEFm2NMFiXAUE2sFUx1x8BZT4ZnBfdnXty5HisCZv3J2FPZVSF87B/1/*,[40e993e5/48h/1h/0h/2h]tpubDEPCxBfMFRNdfJaUeoTmepLJ6ZQmeTiU1Sko2sdx1R3tmPpZemRUjdAHqtmLfaVrBg1NBx2Yx3cVrsZ2FTyBuhiH9mPSL5ozkaTh1iZUTZx/1/*))#uph866gl","internal":true,"timestamp":0}] +[{"active":true,"desc":"wsh(sortedmulti(2,[186ad0c4/48h/1h/0h/2h]tprv8hSFJixpqu9HoqftuhrSgZ2GQhn2vHpt4xvWSwHsUdgV2xuMFygngWVF8kxdGr983KngUHsuw3onLZZCivCHRg398cVd65TQxe8mjd467Qz/0/*,[8df69d29/84h/0h/0h]tpubDD4vFnWuTMEcZiaaZPgvzeGyMzWe6qHW8gALk5Md9kutDvtdDjYFwzauEFFRHgov8pAwup5jX88j5YFyiACsPf3pqn5hBjvuTLRAseaJ6b4/0/*))#9rj4qzrz","timestamp":0},{"active":true,"desc":"wsh(sortedmulti(2,[186ad0c4/48h/1h/0h/2h]tprv8hSFJixpqu9HoqftuhrSgZ2GQhn2vHpt4xvWSwHsUdgV2xuMFygngWVF8kxdGr983KngUHsuw3onLZZCivCHRg398cVd65TQxe8mjd467Qz/1/*,[8df69d29/84h/0h/0h]tpubDD4vFnWuTMEcZiaaZPgvzeGyMzWe6qHW8gALk5Md9kutDvtdDjYFwzauEFFRHgov8pAwup5jX88j5YFyiACsPf3pqn5hBjvuTLRAseaJ6b4/1/*))#vt68gsll","internal":true,"timestamp":0}] diff --git a/tests/e2e/helpers.bash b/tests/e2e/helpers.bash index c4717ff6..40c2efc7 100644 --- a/tests/e2e/helpers.bash +++ b/tests/e2e/helpers.bash @@ -6,7 +6,6 @@ if [[ "${BRIA_CONFIG}" == "docker" ]]; then COMPOSE_FILE_ARG="-f docker-compose.yml" fi BITCOIND_SIGNER_ENDPOINT="${BITCOIND_SIGNER_ENDPOINT:-https://localhost:18543}" -BITCOIND_SIGNER2_ENDPOINT="${BITCOIND_SIGNER2_ENDPOINT:-https://localhost:18544}" LND_HOST="${LND_HOST:-localhost}" LND_ENDPOINT="https://${LND_HOST}:10009" SATS_IN_ONE_BTC=100000000 @@ -61,10 +60,6 @@ bitcoin_signer_cli() { docker exec "${COMPOSE_PROJECT_NAME}-bitcoind-signer-1" bitcoin-cli $@ } -bitcoin_signer2_cli() { - docker exec "${COMPOSE_PROJECT_NAME}-bitcoind-signer2-1" bitcoin-cli $@ -} - convert_btc_to_sats() { echo "$1 * $SATS_IN_ONE_BTC / 1" | bc } @@ -112,10 +107,8 @@ bitcoind_init() { bitcoin_signer_cli createwallet "default" || true bitcoin_signer_cli -rpcwallet=default importdescriptors "$(cat ${REPO_ROOT}/tests/e2e/bitcoind_signer_descriptors.json)" elif [[ "${wallet}" == "multisig" ]]; then - bitcoin_signer_cli createwallet "multisig" || true + bitcoin_signer_cli createwallet "multisig" || true bitcoin_signer_cli -rpcwallet=multisig importdescriptors "$(cat ${REPO_ROOT}/tests/e2e/bitcoind_multisig_signer_descriptors.json)" - bitcoin_signer2_cli createwallet "multisig2" || true - bitcoin_signer2_cli -rpcwallet=multisig2 importdescriptors "$(cat ${REPO_ROOT}/tests/e2e/bitcoind_multisig2_signer_descriptors.json)" fi } @@ -147,12 +140,12 @@ bria_init() { $retry_cmd bria_cmd create-wallet -n default descriptors -d "wpkh([6f2fa1b2/84'/0'/0']tpubDDDDGYiFda8HfJRc2AHFJDxVzzEtBPrKsbh35EaW2UGd5qfzrF2G87ewAgeeRyHEz4iB3kvhAYW1sH6dpLepTkFUzAktumBN8AXeXWE9nd1/0/*)#l6n08zmr" \ -c "wpkh([6f2fa1b2/84'/0'/0']tpubDDDDGYiFda8HfJRc2AHFJDxVzzEtBPrKsbh35EaW2UGd5qfzrF2G87ewAgeeRyHEz4iB3kvhAYW1sH6dpLepTkFUzAktumBN8AXeXWE9nd1/1/*)#wwkw6htm" elif [[ "${wallet_type}" == "multisig" ]]; then - local key1="tpubDEaDfeS1EXpqLVASNCW7qAHW1TFPBpk2Z39gUXjFnsfctomZ7N8iDpy6RuGwqdXAAZ5sr5kQZrxyuEn15tqPJjM4mcPSuXzV27AWRD3p9Q4" - local key2="tpubDEPCxBfMFRNdfJaUeoTmepLJ6ZQmeTiU1Sko2sdx1R3tmPpZemRUjdAHqtmLfaVrBg1NBx2Yx3cVrsZ2FTyBuhiH9mPSL5ozkaTh1iZUTZx" + local key1="tpubDE8HT914zGpxhJhgoMX35xgNyjHy5d1neGXHjTLAtuUssTA7tNWNs177JsFPbJwD5FBXCHJYbwUC9AzSEpYHC4hKgaCvZyZTuCbWfNUWXoM" + local key2="tpubDD4vFnWuTMEcZiaaZPgvzeGyMzWe6qHW8gALk5Md9kutDvtdDjYFwzauEFFRHgov8pAwup5jX88j5YFyiACsPf3pqn5hBjvuTLRAseaJ6b4" $retry_cmd bria_cmd import-xpub -x "${key1}" -n key1 -d m/48h/1h/0h/2h - bria_cmd import-xpub -x "${key2}" -n key2 -d m/48h/1h/0h/2h - bria_cmd create-wallet -n multisig sorted-multisig -x key1 key2 -t 2 + bria_cmd import-xpub -x "${key2}" -n lnd_key -d m/84h/0h/0h + bria_cmd create-wallet -n multisig sorted-multisig -x key1 lnd_key -t 2 fi echo "Bria Initialization Complete" diff --git a/tests/e2e/multisig_payout.bats b/tests/e2e/multisig_payout.bats index c6f3abe1..3ef75015 100644 --- a/tests/e2e/multisig_payout.bats +++ b/tests/e2e/multisig_payout.bats @@ -70,8 +70,8 @@ teardown_file() { unsigned_psbt=$(bria_cmd get-batch -b "${batch_id}" | jq -r '.unsignedPsbt') signed_psbt=$(bitcoin_signer_cli walletprocesspsbt "${unsigned_psbt}" true ALL true | jq -r '.psbt') bria_cmd submit-signed-psbt -b "${batch_id}" -x key1 -s "${signed_psbt}" - signed_psbt2=$(bitcoin_signer2_cli walletprocesspsbt "${unsigned_psbt}" true ALL true | jq -r '.psbt') - bria_cmd submit-signed-psbt -b "${batch_id}" -x key2 -s "${signed_psbt2}" + bria_cmd set-signer-config --xpub lnd_key lnd --endpoint "${LND_ENDPOINT}" --macaroon-file "./dev/lnd/regtest/lnd.admin.macaroon" --cert-file "./dev/lnd/tls.cert" + for i in {1..20}; do signing_status=$(bria_cmd get-batch -b "${batch_id}" | jq -r '.sessions[0].state') [[ "${signing_status}" == "Complete" ]] && break From e45d51c47c3e912e699fd900dbe0043643d62816 Mon Sep 17 00:00:00 2001 From: bodymindarts Date: Tue, 4 Jul 2023 13:50:20 +0200 Subject: [PATCH 23/26] chore: add some more events in batch_signing --- src/job/batch_signing.rs | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/src/job/batch_signing.rs b/src/job/batch_signing.rs index 1d8b7cfa..c2480f09 100644 --- a/src/job/batch_signing.rs +++ b/src/job/batch_signing.rs @@ -18,8 +18,15 @@ pub struct BatchSigningData { #[instrument( name = "job.batch_signing", - skip(pool, wallets, signing_sessions, batches, xpubs), - fields(stalled, txid), + skip( + pool, + wallets, + signing_sessions, + batches, + xpubs, + signer_encryption_config + ), + fields(stalled, txid, finalization_status), err )] #[allow(clippy::too_many_arguments)] @@ -33,6 +40,7 @@ pub async fn execute( xpubs: XPubs, signer_encryption_config: SignerEncryptionConfig, ) -> Result<(BatchSigningData, bool), JobError> { + let span = tracing::Span::current(); let mut stalled = false; let mut last_err = None; let mut current_keychain = None; @@ -45,7 +53,6 @@ pub async fn execute( let mut new_sessions = HashMap::new(); let mut account_xpubs = HashMap::new(); let batch = batches.find_by_id(data.account_id, data.batch_id).await?; - let span = tracing::Span::current(); span.record("txid", &tracing::field::display(batch.bitcoin_tx_id)); let unsigned_psbt = batch.unsigned_psbt; for (wallet_id, summary) in batch.wallet_summaries { @@ -124,6 +131,8 @@ pub async fn execute( tx.commit().await?; } let mut sessions = sessions.into_values(); + + span.record("stalled", &tracing::field::display(stalled)); if let Some(mut first_signed_psbt) = sessions.find_map(|s| s.signed_psbt().cloned()) { for s in sessions { if let Some(psbt) = s.signed_psbt() { @@ -132,7 +141,6 @@ pub async fn execute( } if current_keychain.is_none() { let batch = batches.find_by_id(data.account_id, data.batch_id).await?; - let span = tracing::Span::current(); span.record("txid", &tracing::field::display(batch.bitcoin_tx_id)); let wallet_id = batch.wallet_summaries.into_keys().next().unwrap(); let wallet = wallets.find_by_id(wallet_id).await?; @@ -146,14 +154,27 @@ pub async fn execute( last_err, ) { (Ok(Some(finalized_psbt)), _) => { + span.record("finalization_status", "complete"); let tx = finalized_psbt.extract_tx(); batches.set_signed_tx(data.batch_id, tx).await?; Ok((data, true)) } - (_, Some(e)) => Err(e.into()), - (Ok(None), _) => Ok((data, false)), - _ if stalled => Ok((data, false)), - (Err(err), _) => Err(err.into()), + (_, Some(e)) => { + span.record("finalization_status", "returning_last_error"); + Err(e.into()) + } + (Ok(None), _) => { + span.record("finalization_status", "stalled_due_to_finalization"); + Ok((data, false)) + } + _ if stalled => { + span.record("finalization_status", "stalled"); + Ok((data, false)) + } + (Err(err), _) => { + span.record("finalization_status", "errored"); + Err(err.into()) + } } } else { Ok((data, false)) From a0bc7ca6871aaa1e0de922ad1de4f2647e995eac Mon Sep 17 00:00:00 2001 From: Vaibhav Date: Tue, 4 Jul 2023 18:53:14 +0530 Subject: [PATCH 24/26] chore: add another bitcoind signer --- .../bitcoind_multisig2_signer_descriptors.json | 1 + .../e2e/bitcoind_multisig_signer_descriptors.json | 2 +- tests/e2e/helpers.bash | 12 ++++++------ tests/e2e/multisig_payout.bats | 15 ++++----------- 4 files changed, 12 insertions(+), 18 deletions(-) create mode 100644 tests/e2e/bitcoind_multisig2_signer_descriptors.json diff --git a/tests/e2e/bitcoind_multisig2_signer_descriptors.json b/tests/e2e/bitcoind_multisig2_signer_descriptors.json new file mode 100644 index 00000000..b023d306 --- /dev/null +++ b/tests/e2e/bitcoind_multisig2_signer_descriptors.json @@ -0,0 +1 @@ +[{"active":true,"desc":"wsh(sortedmulti(2,[5abe7e31/48h/1h/0h/2h]tpubDEaDfeS1EXpqLVASNCW7qAHW1TFPBpk2Z39gUXjFnsfctomZ7N8iDpy6RuGwqdXAAZ5sr5kQZrxyuEn15tqPJjM4mcPSuXzV27AWRD3p9Q4/0/*,[40e993e5/48h/1h/0h/2h]tprv8hhAomd773gxmqYgm9oBFQgBXXtqV8XZS9A1kMbeb9FVvuZo2NbtZ8YRfoWKq1e33GdELob79aK46CQLVHmfvGKJkFK1ExP7zejkT1fkqdD/0/*))#tfsx0cwk","timestamp":0},{"active":true,"desc":"wsh(sortedmulti(2,[5abe7e31/48h/1h/0h/2h]tpubDEaDfeS1EXpqLVASNCW7qAHW1TFPBpk2Z39gUXjFnsfctomZ7N8iDpy6RuGwqdXAAZ5sr5kQZrxyuEn15tqPJjM4mcPSuXzV27AWRD3p9Q4/1/*,[40e993e5/48h/1h/0h/2h]tprv8hhAomd773gxmqYgm9oBFQgBXXtqV8XZS9A1kMbeb9FVvuZo2NbtZ8YRfoWKq1e33GdELob79aK46CQLVHmfvGKJkFK1ExP7zejkT1fkqdD/1/*))#j6rzptmr","internal":true,"timestamp":0}] diff --git a/tests/e2e/bitcoind_multisig_signer_descriptors.json b/tests/e2e/bitcoind_multisig_signer_descriptors.json index b6eaf040..13267ae9 100644 --- a/tests/e2e/bitcoind_multisig_signer_descriptors.json +++ b/tests/e2e/bitcoind_multisig_signer_descriptors.json @@ -1 +1 @@ -[{"active":true,"desc":"wsh(sortedmulti(2,[186ad0c4/48h/1h/0h/2h]tprv8hSFJixpqu9HoqftuhrSgZ2GQhn2vHpt4xvWSwHsUdgV2xuMFygngWVF8kxdGr983KngUHsuw3onLZZCivCHRg398cVd65TQxe8mjd467Qz/0/*,[8df69d29/84h/0h/0h]tpubDD4vFnWuTMEcZiaaZPgvzeGyMzWe6qHW8gALk5Md9kutDvtdDjYFwzauEFFRHgov8pAwup5jX88j5YFyiACsPf3pqn5hBjvuTLRAseaJ6b4/0/*))#9rj4qzrz","timestamp":0},{"active":true,"desc":"wsh(sortedmulti(2,[186ad0c4/48h/1h/0h/2h]tprv8hSFJixpqu9HoqftuhrSgZ2GQhn2vHpt4xvWSwHsUdgV2xuMFygngWVF8kxdGr983KngUHsuw3onLZZCivCHRg398cVd65TQxe8mjd467Qz/1/*,[8df69d29/84h/0h/0h]tpubDD4vFnWuTMEcZiaaZPgvzeGyMzWe6qHW8gALk5Md9kutDvtdDjYFwzauEFFRHgov8pAwup5jX88j5YFyiACsPf3pqn5hBjvuTLRAseaJ6b4/1/*))#vt68gsll","internal":true,"timestamp":0}] +[{"active":true,"desc":"wsh(sortedmulti(2,[5abe7e31/48h/1h/0h/2h]tprv8htBXEPm6A9AT28eUYqXRkdPSRjT2VZ7yjYuC1gxNbsE4KWnUyK83LMEFm2NMFiXAUE2sFUx1x8BZT4ZnBfdnXty5HisCZv3J2FPZVSF87B/0/*,[40e993e5/48h/1h/0h/2h]tpubDEPCxBfMFRNdfJaUeoTmepLJ6ZQmeTiU1Sko2sdx1R3tmPpZemRUjdAHqtmLfaVrBg1NBx2Yx3cVrsZ2FTyBuhiH9mPSL5ozkaTh1iZUTZx/0/*))#9jyr5fa2","timestamp":0},{"active":true,"desc":"wsh(sortedmulti(2,[5abe7e31/48h/1h/0h/2h]tprv8htBXEPm6A9AT28eUYqXRkdPSRjT2VZ7yjYuC1gxNbsE4KWnUyK83LMEFm2NMFiXAUE2sFUx1x8BZT4ZnBfdnXty5HisCZv3J2FPZVSF87B/1/*,[40e993e5/48h/1h/0h/2h]tpubDEPCxBfMFRNdfJaUeoTmepLJ6ZQmeTiU1Sko2sdx1R3tmPpZemRUjdAHqtmLfaVrBg1NBx2Yx3cVrsZ2FTyBuhiH9mPSL5ozkaTh1iZUTZx/1/*))#uph866gl","internal":true,"timestamp":0}] diff --git a/tests/e2e/helpers.bash b/tests/e2e/helpers.bash index 40c2efc7..5a8d4163 100644 --- a/tests/e2e/helpers.bash +++ b/tests/e2e/helpers.bash @@ -6,8 +6,6 @@ if [[ "${BRIA_CONFIG}" == "docker" ]]; then COMPOSE_FILE_ARG="-f docker-compose.yml" fi BITCOIND_SIGNER_ENDPOINT="${BITCOIND_SIGNER_ENDPOINT:-https://localhost:18543}" -LND_HOST="${LND_HOST:-localhost}" -LND_ENDPOINT="https://${LND_HOST}:10009" SATS_IN_ONE_BTC=100000000 bria_cmd() { @@ -109,6 +107,8 @@ bitcoind_init() { elif [[ "${wallet}" == "multisig" ]]; then bitcoin_signer_cli createwallet "multisig" || true bitcoin_signer_cli -rpcwallet=multisig importdescriptors "$(cat ${REPO_ROOT}/tests/e2e/bitcoind_multisig_signer_descriptors.json)" + bitcoin_signer_cli createwallet "multisig2" || true + bitcoin_signer_cli -rpcwallet=multisig2 importdescriptors "$(cat ${REPO_ROOT}/tests/e2e/bitcoind_multisig2_signer_descriptors.json)" fi } @@ -140,12 +140,12 @@ bria_init() { $retry_cmd bria_cmd create-wallet -n default descriptors -d "wpkh([6f2fa1b2/84'/0'/0']tpubDDDDGYiFda8HfJRc2AHFJDxVzzEtBPrKsbh35EaW2UGd5qfzrF2G87ewAgeeRyHEz4iB3kvhAYW1sH6dpLepTkFUzAktumBN8AXeXWE9nd1/0/*)#l6n08zmr" \ -c "wpkh([6f2fa1b2/84'/0'/0']tpubDDDDGYiFda8HfJRc2AHFJDxVzzEtBPrKsbh35EaW2UGd5qfzrF2G87ewAgeeRyHEz4iB3kvhAYW1sH6dpLepTkFUzAktumBN8AXeXWE9nd1/1/*)#wwkw6htm" elif [[ "${wallet_type}" == "multisig" ]]; then - local key1="tpubDE8HT914zGpxhJhgoMX35xgNyjHy5d1neGXHjTLAtuUssTA7tNWNs177JsFPbJwD5FBXCHJYbwUC9AzSEpYHC4hKgaCvZyZTuCbWfNUWXoM" - local key2="tpubDD4vFnWuTMEcZiaaZPgvzeGyMzWe6qHW8gALk5Md9kutDvtdDjYFwzauEFFRHgov8pAwup5jX88j5YFyiACsPf3pqn5hBjvuTLRAseaJ6b4" + local key1="tpubDEaDfeS1EXpqLVASNCW7qAHW1TFPBpk2Z39gUXjFnsfctomZ7N8iDpy6RuGwqdXAAZ5sr5kQZrxyuEn15tqPJjM4mcPSuXzV27AWRD3p9Q4" + local key2="tpubDEPCxBfMFRNdfJaUeoTmepLJ6ZQmeTiU1Sko2sdx1R3tmPpZemRUjdAHqtmLfaVrBg1NBx2Yx3cVrsZ2FTyBuhiH9mPSL5ozkaTh1iZUTZx" $retry_cmd bria_cmd import-xpub -x "${key1}" -n key1 -d m/48h/1h/0h/2h - bria_cmd import-xpub -x "${key2}" -n lnd_key -d m/84h/0h/0h - bria_cmd create-wallet -n multisig sorted-multisig -x key1 lnd_key -t 2 + bria_cmd import-xpub -x "${key2}" -n key2 -d m/48h/1h/0h/2h + bria_cmd create-wallet -n multisig sorted-multisig -x key1 key2 -t 2 fi echo "Bria Initialization Complete" diff --git a/tests/e2e/multisig_payout.bats b/tests/e2e/multisig_payout.bats index 3ef75015..a79c8f6d 100644 --- a/tests/e2e/multisig_payout.bats +++ b/tests/e2e/multisig_payout.bats @@ -58,19 +58,12 @@ teardown_file() { done [[ "${batch_id}" != "null" ]] || exit 1 - - for i in {1..20}; do - signing_failure_reason=$(bria_cmd get-batch -b "${batch_id}" | jq -r '.signingSessions[0].failureReason') - [[ "${signing_failure_reason}" == "SignerConfigMissing" ]] && break - sleep 1 - done - - [[ "${signing_failure_reason}" == "SignerConfigMissing" ]] || exit 1 unsigned_psbt=$(bria_cmd get-batch -b "${batch_id}" | jq -r '.unsignedPsbt') - signed_psbt=$(bitcoin_signer_cli walletprocesspsbt "${unsigned_psbt}" true ALL true | jq -r '.psbt') - bria_cmd submit-signed-psbt -b "${batch_id}" -x key1 -s "${signed_psbt}" - bria_cmd set-signer-config --xpub lnd_key lnd --endpoint "${LND_ENDPOINT}" --macaroon-file "./dev/lnd/regtest/lnd.admin.macaroon" --cert-file "./dev/lnd/tls.cert" + signed_psbt=$(bitcoin_signer_cli -rpcwallet=multisig walletprocesspsbt "${unsigned_psbt}" true ALL true | jq -r '.psbt') + bria_cmd submit-signed-psbt -b "${batch_id}" -x key1 -s "${signed_psbt}" + signed_psbt2=$(bitcoin_signer_cli -rpcwallet=multisig2 walletprocesspsbt "${unsigned_psbt}" true ALL true | jq -r '.psbt') + bria_cmd submit-signed-psbt -b "${batch_id}" -x key2 -s "${signed_psbt2}" for i in {1..20}; do signing_status=$(bria_cmd get-batch -b "${batch_id}" | jq -r '.sessions[0].state') From a8fd55f22d530c872224162388d6ff3a657be8f9 Mon Sep 17 00:00:00 2001 From: Vaibhav Date: Tue, 4 Jul 2023 19:41:20 +0530 Subject: [PATCH 25/26] chore: add better assertions --- src/wallet/psbt_validator.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/wallet/psbt_validator.rs b/src/wallet/psbt_validator.rs index 49bac862..13d3e61e 100644 --- a/src/wallet/psbt_validator.rs +++ b/src/wallet/psbt_validator.rs @@ -59,14 +59,20 @@ mod test { let xpub = XPub::try_from(("tpubDE8HT914zGpxhJhgoMX35xgNyjHy5d1neGXHjTLAtuUssTA7tNWNs177JsFPbJwD5FBXCHJYbwUC9AzSEpYHC4hKgaCvZyZTuCbWfNUWXoM", Some("m/48h/1h/0h/2h"))).unwrap(); let signed_psbt = "cHNidP8BAHEBAAAAAYbn7MxiehS1ZSM0EB5cRE9nSFCZmsSG1esfWwyuVz+GAAAAAAD+////ArN3fQEAAAAAFgAU/gKMRui+SfQrLooISrMz67mo2TDAaHgEAAAAABYAFFPOvhKDbGzCHM0LNEHgSPJjuf7RzQAAAAABAHECAAAAAUHSbz5JON/N5LECN+D4fkQ4ePau7Swxe/W6Abiyik7/AAAAAAD9////AgDh9QUAAAAAFgAUmtl/mRY8rv7U7qlTERct+67KKEL8BRAkAQAAABYAFNwYhIQ2+xR1XyFfuB0O8PfBJB0ayAAAAAEBHwDh9QUAAAAAFgAUmtl/mRY8rv7U7qlTERct+67KKEIBCGsCRzBEAiAbOAYSbHJagpdcvez9jSFo4tWsN/cFBi1RtRHwh11t/gIgZbnkC8tKwAUMrF+dGjI6w1iChJHwN+Cs2VVhqCuEyWoBIQOZcT3zA/OKNzoMwjrfDPXErOVu7/Tevy9zOUkioZCXbwAiAgNZOo5LB+cTuY4cZu9Oa+w14tqxpMhUdA8YDniI9uRBKhhvL6GyVAAAgAAAAIAAAACAAQAAAAAAAAAAAA==".parse::().unwrap(); let unsigned_psbt = "cHNidP8BAH0BAAAAASNihqnLFfz7pHt1zDeB/iB7ku75Ah6EFaFhQZnbErt9AAAAAAD+////Ap13fQEAAAAAIgAgO37beKyitaViJwyjZ3oTIwdBU0JTbBRa32V1zvdifQzAaHgEAAAAABYAFFPOvhKDbGzCHM0LNEHgSPJjuf7RzQAAAAABAPYCAAAAAAEBTEYh+JWYBjbSBgwY+QxYOE25/vFk5zdS61jKtc1HJjYAAAAAAP3///8CAOH1BQAAAAAiACCOipWPCjso1EpZQctqUeF6N4QjTNQ3c+15axzGinwSVhwEECQBAAAAIlEgzmi+Ha7O7p08hrHEzLrq68MJlSDW40V39kbqS+ArmTMCRzBEAiB5fcQ8lx7fp+Calgy7o9jQEsHEPho0zfP13TQsCC2/GgIgSL/zyp0nz5PzdMXxhgBJ59O2t7tUhAfKxBYtVjMYXR0BIQN39pz1kuRtgfVu5SMba1rXL5HXDIKq4/rq7I/342+/GsgAAAABASsA4fUFAAAAACIAII6KlY8KOyjUSllBy2pR4Xo3hCNM1Ddz7XlrHMaKfBJWAQMEAQAAAAEFR1EhAlBn4VwHril4Da/2rGzF/FZnM0gnAi5M7A7iHMxMA4tIIQKXjwOvzjfb1Y0HMvH2Bc2Eqtukx+dxd4V8qOus23qGhlKuIgYCUGfhXAeuKXgNr/asbMX8VmczSCcCLkzsDuIczEwDi0gcmFPdqTAAAIABAACAAAAAgAIAAIAAAAAAAAAAACIGApePA6/ON9vVjQcy8fYFzYSq26TH53F3hXyo66zbeoaGHB3opBwwAACAAQAAgAAAAIACAACAAAAAAAAAAAAAAQFHUSECXDnAvMuAqtaBxRvWWRK4cOeJCmnxrHmzX7Ys+TOgLkMhAsl2+NBf0WNXB5Dyu/j0+luIVYCV+21GR7hPI2AUvisiUq4iAgJcOcC8y4Cq1oHFG9ZZErhw54kKafGsebNftiz5M6AuQxyYU92pMAAAgAEAAIAAAACAAgAAgAEAAAAAAAAAIgICyXb40F/RY1cHkPK7+PT6W4hVgJX7bUZHuE8jYBS+KyIcHeikHDAAAIABAACAAAAAgAIAAIABAAAAAAAAAAAA".parse::().unwrap(); - assert!(validate_psbt(&signed_psbt, xpub, &unsigned_psbt).is_err()); + assert!(matches!( + validate_psbt(&signed_psbt, xpub, &unsigned_psbt), + Err(WalletError::UnsignedTxnMismatch) + )); } #[test] fn fails_if_unsigned_psbt_passed() { let xpub = XPub::try_from(("tpubDE8HT914zGpxhJhgoMX35xgNyjHy5d1neGXHjTLAtuUssTA7tNWNs177JsFPbJwD5FBXCHJYbwUC9AzSEpYHC4hKgaCvZyZTuCbWfNUWXoM", Some("m/48h/1h/0h/2h"))).unwrap(); - let signed_psbt = "cHNidP8BAHEBAAAAAYbn7MxiehS1ZSM0EB5cRE9nSFCZmsSG1esfWwyuVz+GAAAAAAD+////ArN3fQEAAAAAFgAU/gKMRui+SfQrLooISrMz67mo2TDAaHgEAAAAABYAFFPOvhKDbGzCHM0LNEHgSPJjuf7RzQAAAAABAHECAAAAAUHSbz5JON/N5LECN+D4fkQ4ePau7Swxe/W6Abiyik7/AAAAAAD9////AgDh9QUAAAAAFgAUmtl/mRY8rv7U7qlTERct+67KKEL8BRAkAQAAABYAFNwYhIQ2+xR1XyFfuB0O8PfBJB0ayAAAAAEBHwDh9QUAAAAAFgAUmtl/mRY8rv7U7qlTERct+67KKEIBAwQBAAAAIgYDmXE98wPzijc6DMI63wz1xKzlbu/03r8vczlJIqGQl28Yby+hslQAAIAAAACAAAAAgAAAAAAAAAAAACICA1k6jksH5xO5jhxm705r7DXi2rGkyFR0DxgOeIj25EEqGG8vobJUAACAAAAAgAAAAIABAAAAAAAAAAAA".parse::().unwrap(); + let signed_psbt = "cHNidP8BAH0BAAAAASNihqnLFfz7pHt1zDeB/iB7ku75Ah6EFaFhQZnbErt9AAAAAAD+////Ap13fQEAAAAAIgAgO37beKyitaViJwyjZ3oTIwdBU0JTbBRa32V1zvdifQzAaHgEAAAAABYAFFPOvhKDbGzCHM0LNEHgSPJjuf7RzQAAAAABAPYCAAAAAAEBTEYh+JWYBjbSBgwY+QxYOE25/vFk5zdS61jKtc1HJjYAAAAAAP3///8CAOH1BQAAAAAiACCOipWPCjso1EpZQctqUeF6N4QjTNQ3c+15axzGinwSVhwEECQBAAAAIlEgzmi+Ha7O7p08hrHEzLrq68MJlSDW40V39kbqS+ArmTMCRzBEAiB5fcQ8lx7fp+Calgy7o9jQEsHEPho0zfP13TQsCC2/GgIgSL/zyp0nz5PzdMXxhgBJ59O2t7tUhAfKxBYtVjMYXR0BIQN39pz1kuRtgfVu5SMba1rXL5HXDIKq4/rq7I/342+/GsgAAAABASsA4fUFAAAAACIAII6KlY8KOyjUSllBy2pR4Xo3hCNM1Ddz7XlrHMaKfBJWAQMEAQAAAAEFR1EhAlBn4VwHril4Da/2rGzF/FZnM0gnAi5M7A7iHMxMA4tIIQKXjwOvzjfb1Y0HMvH2Bc2Eqtukx+dxd4V8qOus23qGhlKuIgYCUGfhXAeuKXgNr/asbMX8VmczSCcCLkzsDuIczEwDi0gcmFPdqTAAAIABAACAAAAAgAIAAIAAAAAAAAAAACIGApePA6/ON9vVjQcy8fYFzYSq26TH53F3hXyo66zbeoaGHB3opBwwAACAAQAAgAAAAIACAACAAAAAAAAAAAAAAQFHUSECXDnAvMuAqtaBxRvWWRK4cOeJCmnxrHmzX7Ys+TOgLkMhAsl2+NBf0WNXB5Dyu/j0+luIVYCV+21GR7hPI2AUvisiUq4iAgJcOcC8y4Cq1oHFG9ZZErhw54kKafGsebNftiz5M6AuQxyYU92pMAAAgAEAAIAAAACAAgAAgAEAAAAAAAAAIgICyXb40F/RY1cHkPK7+PT6W4hVgJX7bUZHuE8jYBS+KyIcHeikHDAAAIABAACAAAAAgAIAAIABAAAAAAAAAAAA".parse::().unwrap(); let unsigned_psbt = "cHNidP8BAH0BAAAAASNihqnLFfz7pHt1zDeB/iB7ku75Ah6EFaFhQZnbErt9AAAAAAD+////Ap13fQEAAAAAIgAgO37beKyitaViJwyjZ3oTIwdBU0JTbBRa32V1zvdifQzAaHgEAAAAABYAFFPOvhKDbGzCHM0LNEHgSPJjuf7RzQAAAAABAPYCAAAAAAEBTEYh+JWYBjbSBgwY+QxYOE25/vFk5zdS61jKtc1HJjYAAAAAAP3///8CAOH1BQAAAAAiACCOipWPCjso1EpZQctqUeF6N4QjTNQ3c+15axzGinwSVhwEECQBAAAAIlEgzmi+Ha7O7p08hrHEzLrq68MJlSDW40V39kbqS+ArmTMCRzBEAiB5fcQ8lx7fp+Calgy7o9jQEsHEPho0zfP13TQsCC2/GgIgSL/zyp0nz5PzdMXxhgBJ59O2t7tUhAfKxBYtVjMYXR0BIQN39pz1kuRtgfVu5SMba1rXL5HXDIKq4/rq7I/342+/GsgAAAABASsA4fUFAAAAACIAII6KlY8KOyjUSllBy2pR4Xo3hCNM1Ddz7XlrHMaKfBJWAQMEAQAAAAEFR1EhAlBn4VwHril4Da/2rGzF/FZnM0gnAi5M7A7iHMxMA4tIIQKXjwOvzjfb1Y0HMvH2Bc2Eqtukx+dxd4V8qOus23qGhlKuIgYCUGfhXAeuKXgNr/asbMX8VmczSCcCLkzsDuIczEwDi0gcmFPdqTAAAIABAACAAAAAgAIAAIAAAAAAAAAAACIGApePA6/ON9vVjQcy8fYFzYSq26TH53F3hXyo66zbeoaGHB3opBwwAACAAQAAgAAAAIACAACAAAAAAAAAAAAAAQFHUSECXDnAvMuAqtaBxRvWWRK4cOeJCmnxrHmzX7Ys+TOgLkMhAsl2+NBf0WNXB5Dyu/j0+luIVYCV+21GR7hPI2AUvisiUq4iAgJcOcC8y4Cq1oHFG9ZZErhw54kKafGsebNftiz5M6AuQxyYU92pMAAAgAEAAIAAAACAAgAAgAEAAAAAAAAAIgICyXb40F/RY1cHkPK7+PT6W4hVgJX7bUZHuE8jYBS+KyIcHeikHDAAAIABAACAAAAAgAIAAIABAAAAAAAAAAAA".parse::().unwrap(); - assert!(validate_psbt(&signed_psbt, xpub, &unsigned_psbt).is_err()); + assert!(matches!( + validate_psbt(&signed_psbt, xpub, &unsigned_psbt), + Err(WalletError::PsbtDoesNotHaveValidSignatures) + )) } } From 46bbb9251417b276e50e96e08aa180cdee0e6776 Mon Sep 17 00:00:00 2001 From: Vaibhav Date: Wed, 5 Jul 2023 19:13:21 +0530 Subject: [PATCH 26/26] chore: add remote signer --- tests/e2e/multisig_payout.bats | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/e2e/multisig_payout.bats b/tests/e2e/multisig_payout.bats index a79c8f6d..f892db63 100644 --- a/tests/e2e/multisig_payout.bats +++ b/tests/e2e/multisig_payout.bats @@ -62,8 +62,11 @@ teardown_file() { unsigned_psbt=$(bria_cmd get-batch -b "${batch_id}" | jq -r '.unsignedPsbt') signed_psbt=$(bitcoin_signer_cli -rpcwallet=multisig walletprocesspsbt "${unsigned_psbt}" true ALL true | jq -r '.psbt') bria_cmd submit-signed-psbt -b "${batch_id}" -x key1 -s "${signed_psbt}" - signed_psbt2=$(bitcoin_signer_cli -rpcwallet=multisig2 walletprocesspsbt "${unsigned_psbt}" true ALL true | jq -r '.psbt') - bria_cmd submit-signed-psbt -b "${batch_id}" -x key2 -s "${signed_psbt2}" + bria_cmd set-signer-config \ + --xpub key2 bitcoind \ + --endpoint "${BITCOIND_SIGNER_ENDPOINT}"/wallet/multisig2 \ + --rpc-user "rpcuser" \ + --rpc-password "rpcpassword" for i in {1..20}; do signing_status=$(bria_cmd get-batch -b "${batch_id}" | jq -r '.sessions[0].state')