Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ page. See [DEVELOPMENT_CYCLE.md](DEVELOPMENT_CYCLE.md) for more details.
- Rejected `--proxy` on the `rpc` backend, and unsupported proxy options (`--proxy_auth`, `--timeout`) on the `rpc` and `cbf` backends, instead of silently ignoring them
- Fixed `compile` rejecting policies that are valid for the requested script type
- Fixed `warn!` messages, including the mainnet notice, being hidden unless `RUST_LOG` was set; warnings are now shown by default
- Fixed `create_tx`, `create_dns_tx`, `create_sp_tx` and `bump_fee` building transactions over Bitcoin Core's 400,000 wu (100,000 vB) standard weight limit, which no default node relays

## [4.0.0]

Expand Down
11 changes: 10 additions & 1 deletion src/error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use bdk_wallet::bitcoin::hex::HexToBytesError;
use bdk_wallet::bitcoin::psbt::ExtractTxError;
use bdk_wallet::bitcoin::{base64, consensus};
use bdk_wallet::bitcoin::{Transaction, Weight, base64, consensus};
use thiserror::Error;

#[derive(Debug, Error)]
Expand Down Expand Up @@ -63,6 +63,15 @@ pub enum BDKCliError {
#[error("Miniscript compiler error: {0}")]
MiniscriptCompilerError(#[from] bdk_wallet::miniscript::policy::compiler::CompilerError),

#[error(
"Transaction can weigh up to {weight:#} ({} vB) once signed, over the {:#} ({} vB) \
standard limit, so Bitcoin Core nodes will not relay it",
weight.to_vbytes_ceil(),
Transaction::MAX_STANDARD_WEIGHT,
Transaction::MAX_STANDARD_WEIGHT.to_vbytes_ceil()
)]
NonStandardTxWeight { weight: Weight },

#[error("ParseError: {0}")]
ParseError(#[from] bdk_wallet::bitcoin::address::ParseError),

Expand Down
29 changes: 14 additions & 15 deletions src/handlers/dns/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ use crate::handlers::dns::dns_payment_instructions::{
};
use crate::handlers::{AppContext, AsyncAppCommand, Init, OfflineOperations};
use crate::utils::types::{PsbtResult, StatusResult};
use crate::utils::{parse_dns_recipient, parse_fee_rate, parse_outpoint, parse_recipient};
use crate::utils::{
check_standard_weight, max_signed_weight, parse_dns_recipient, parse_fee_rate,
parse_op_return_base64, parse_op_return_string, parse_outpoint, parse_recipient,
};
use bdk_wallet::KeychainKind;
use bdk_wallet::bitcoin::base64::Engine;
use bdk_wallet::bitcoin::base64::prelude::BASE64_STANDARD;
use bdk_wallet::bitcoin::script::PushBytesBuf;
use bdk_wallet::bitcoin::{Amount, FeeRate, OutPoint, ScriptBuf, Sequence};
use bdk_wallet::bitcoin::{Amount, FeeRate, OutPoint, ScriptBuf, Sequence, script::PushBytesBuf};
use clap::Parser;
use std::collections::BTreeMap;

Expand Down Expand Up @@ -67,16 +67,18 @@ pub struct CreateDnsTxCommand {
env = "ADD_STRING",
long = "add_string",
short = 's',
conflicts_with = "add_data"
conflicts_with = "add_data",
value_parser = parse_op_return_string,
)]
pub add_string: Option<String>,
pub add_string: Option<PushBytesBuf>,
#[arg(
env = "ADD_DATA",
long = "add_data",
short = 'o',
conflicts_with = "add_string"
conflicts_with = "add_string",
value_parser = parse_op_return_base64,
)]
pub add_data: Option<String>,
pub add_data: Option<PushBytesBuf>,
}

impl AsyncAppCommand<AppContext<OfflineOperations<'_>>> for CreateDnsTxCommand {
Expand Down Expand Up @@ -138,12 +140,8 @@ impl AsyncAppCommand<AppContext<OfflineOperations<'_>>> for CreateDnsTxCommand {
if let Some(unspendable) = &self.unspendable {
tx_builder.unspendable(unspendable.to_vec());
}
if let Some(base64_data) = &self.add_data {
let op_return_data = BASE64_STANDARD.decode(base64_data)?;
tx_builder.add_data(&PushBytesBuf::try_from(op_return_data)?);
} else if let Some(string_data) = &self.add_string {
let data = PushBytesBuf::try_from(string_data.as_bytes().to_vec())?;
tx_builder.add_data(&data);
if let Some(data) = self.add_data.as_ref().or(self.add_string.as_ref()) {
tx_builder.add_data(data);
}

let policies = vec![
Expand All @@ -160,6 +158,7 @@ impl AsyncAppCommand<AppContext<OfflineOperations<'_>>> for CreateDnsTxCommand {
}

let psbt = tx_builder.finish()?;
check_standard_weight(max_signed_weight(ctx.state.wallet, &psbt)?)?;
Ok(PsbtResult::new(&psbt, Some(false)))
}
}
57 changes: 30 additions & 27 deletions src/handlers/offline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ use crate::commands::OfflineWalletSubCommand;
use crate::error::BDKCliError as Error;
use crate::handlers::{AppCommand, AppContext, OfflineOperations};
use crate::utils::output::{FormatOutput, ListResult};
use crate::utils::parse_address;
use crate::utils::types::{
AddressResult, BalanceResult, KeychainPair, PsbtResult, RawPsbt, TransactionDetails,
UnspentDetails,
};
use crate::utils::{parse_fee_rate, parse_outpoint, parse_recipient};
use crate::utils::{
check_standard_weight, max_signed_weight, parse_address, parse_fee_rate,
parse_op_return_base64, parse_op_return_string, parse_outpoint, parse_recipient,
};
use bdk_wallet::bitcoin::base64::Engine;
use bdk_wallet::bitcoin::base64::prelude::BASE64_STANDARD;
use bdk_wallet::bitcoin::script::PushBytesBuf;
Expand Down Expand Up @@ -228,23 +230,26 @@ pub struct CreateTxCommand {
#[arg(env = "INT_POLICY", long = "internal_policy")]
pub internal_policy: Option<String>,

/// Optionally create an OP_RETURN output containing given String in utf8 encoding (max 80 bytes)
/// Optionally create an OP_RETURN output containing given String in utf8 encoding. The transaction must stay within Bitcoin Core's 100,000 vB standard size limit.

#[arg(
env = "ADD_STRING",
long = "add_string",
short = 's',
conflicts_with = "add_data"
conflicts_with = "add_data",
value_parser = parse_op_return_string,
)]
pub add_string: Option<String>,
pub add_string: Option<PushBytesBuf>,

/// Optionally create an OP_RETURN output containing given base64 encoded String. (max 80 bytes)
/// Optionally create an OP_RETURN output containing given base64 encoded String. The transaction must stay within Bitcoin Core's 100,000 vB standard size limit.
#[arg(
env = "ADD_DATA",
long = "add_data",
short = 'o',
conflicts_with = "add_string"
conflicts_with = "add_string",
value_parser = parse_op_return_base64,
)]
pub add_data: Option<String>,
pub add_data: Option<PushBytesBuf>,
}

impl AppCommand<AppContext<OfflineOperations<'_>>> for CreateTxCommand {
Expand Down Expand Up @@ -293,12 +298,8 @@ impl AppCommand<AppContext<OfflineOperations<'_>>> for CreateTxCommand {
tx_builder.unspendable(unspendable.to_vec());
}

if let Some(base64_data) = &self.add_data {
let op_return_data = BASE64_STANDARD.decode(base64_data)?;
tx_builder.add_data(&PushBytesBuf::try_from(op_return_data)?);
} else if let Some(string_data) = &self.add_string {
let data = PushBytesBuf::try_from(string_data.as_bytes().to_vec())?;
tx_builder.add_data(&data);
if let Some(data) = self.add_data.as_ref().or(self.add_string.as_ref()) {
tx_builder.add_data(data);
}

let policies = vec![
Expand All @@ -317,6 +318,8 @@ impl AppCommand<AppContext<OfflineOperations<'_>>> for CreateTxCommand {

let psbt = tx_builder.finish()?;

check_standard_weight(max_signed_weight(ctx.state.wallet, &psbt)?)?;

Ok(PsbtResult::new(&psbt, Some(false)))
}
}
Expand Down Expand Up @@ -353,22 +356,24 @@ pub struct CreateSpTxCommand {
/// Selects which policy should be used to satisfy the internal descriptor.
#[arg(env = "INT_POLICY", long = "internal_policy")]
pub internal_policy: Option<String>,
/// Optionally create an OP_RETURN output containing given String in utf8 encoding (max 80 bytes)
/// Optionally create an OP_RETURN output containing given String in utf8 encoding. The transaction must stay within Bitcoin Core's 100,000 vB standard size limit.
#[arg(
env = "ADD_STRING",
long = "add_string",
short = 's',
conflicts_with = "add_data"
conflicts_with = "add_data",
value_parser = parse_op_return_string,
)]
pub add_string: Option<String>,
/// Optionally create an OP_RETURN output containing given base64 encoded String. (max 80 bytes)
pub add_string: Option<PushBytesBuf>,
/// Optionally create an OP_RETURN output containing given base64 encoded String. The transaction must stay within Bitcoin Core's 100,000 vB standard size limit.
#[arg(
env = "ADD_DATA",
long = "add_data",
short = 'o',
conflicts_with = "add_string"
conflicts_with = "add_string",
value_parser = parse_op_return_base64,
)]
pub add_data: Option<String>, //base 64 econding
pub add_data: Option<PushBytesBuf>,
}

#[cfg(feature = "silent-payments")]
Expand Down Expand Up @@ -444,12 +449,8 @@ impl AppCommand<AppContext<OfflineOperations<'_>>> for CreateSpTxCommand {
tx_builder.unspendable(unspendable.to_vec());
}

if let Some(base64_data) = &self.add_data {
let op_return_data = BASE64_STANDARD.decode(base64_data)?;
tx_builder.add_data(&PushBytesBuf::try_from(op_return_data)?);
} else if let Some(string_data) = &self.add_string {
let data = PushBytesBuf::try_from(string_data.as_bytes().to_vec())?;
tx_builder.add_data(&data);
if let Some(data) = self.add_data.as_ref().or(self.add_string.as_ref()) {
tx_builder.add_data(data);
}

let policies = vec![
Expand Down Expand Up @@ -528,6 +529,8 @@ impl AppCommand<AppContext<OfflineOperations<'_>>> for CreateSpTxCommand {

let raw_tx = psbt.extract_tx()?;

check_standard_weight(raw_tx.weight())?;

Ok(RawPsbt::new(&raw_tx))
}
}
Expand Down Expand Up @@ -593,7 +596,7 @@ impl AppCommand<AppContext<OfflineOperations<'_>>> for BumpFeeCommand {

let psbt = tx_builder.finish()?;

// let psbt_base64 = BASE64_STANDARD.encode(psbt.serialize());
check_standard_weight(max_signed_weight(wallet, &psbt)?)?;

Ok(PsbtResult::new(&psbt, Some(false)))
}
Expand Down
Loading
Loading