Skip to content

Commit 47e4e17

Browse files
committed
refactor: address code review feedback
- Rename MAX_SEQUENCE_VALUE to MAX_RELATIVE_HEIGHT for clarity - Use Script::is_p2tr() for more robust taproot input detection - Replace fallible LockTime::from_height with expect for valid Height - Remove unnecessary clippy allow attributes in lib.rs - Remove Box usage from error and enums - Rename anti_fee_snipping example to anti_fee_sniping
1 parent 9041b2f commit 47e4e17

File tree

7 files changed

+48
-57
lines changed

7 files changed

+48
-57
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,4 @@ name = "common"
3535
crate-type = ["lib"]
3636

3737
[[example]]
38-
name = "anti_fee_snipping"
38+
name = "anti_fee_sniping"
File renamed without changes.

src/input.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use alloc::boxed::Box;
21
use alloc::sync::Arc;
32
use alloc::vec::Vec;
43
use core::fmt;
@@ -35,9 +34,9 @@ impl TxStatus {
3534

3635
#[derive(Debug, Clone)]
3736
enum PlanOrPsbtInput {
38-
Plan(Box<Plan>),
37+
Plan(Plan),
3938
PsbtInput {
40-
psbt_input: Box<psbt::Input>,
39+
psbt_input: psbt::Input,
4140
sequence: Sequence,
4241
absolute_timelock: absolute::LockTime,
4342
satisfaction_weight: usize,
@@ -58,7 +57,7 @@ impl PlanOrPsbtInput {
5857
return Err(FromPsbtInputError::UtxoCheck);
5958
}
6059
Ok(Self::PsbtInput {
61-
psbt_input: Box::new(psbt_input),
60+
psbt_input,
6261
sequence,
6362
absolute_timelock: absolute::LockTime::ZERO,
6463
satisfaction_weight,
@@ -217,7 +216,7 @@ impl Input {
217216
prev_outpoint: OutPoint::new(tx.compute_txid(), output_index as _),
218217
prev_txout: tx.tx_out(output_index).cloned()?,
219218
prev_tx: Some(tx),
220-
plan: PlanOrPsbtInput::Plan(Box::new(plan)),
219+
plan: PlanOrPsbtInput::Plan(plan),
221220
status,
222221
is_coinbase,
223222
})
@@ -235,7 +234,7 @@ impl Input {
235234
prev_outpoint,
236235
prev_txout,
237236
prev_tx: None,
238-
plan: PlanOrPsbtInput::Plan(Box::new(plan)),
237+
plan: PlanOrPsbtInput::Plan(plan),
239238
status,
240239
is_coinbase,
241240
}

src/lib.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
11
//! `bdk_tx`
2-
3-
// FIXME: try to remove clippy "allows"
4-
#![allow(clippy::large_enum_variant)]
5-
#![allow(clippy::result_large_err)]
62
#![warn(missing_docs)]
73
#![no_std]
84

src/output.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use alloc::boxed::Box;
2-
31
use bitcoin::{Amount, ScriptBuf, TxOut};
42
use miniscript::bitcoin;
53

@@ -11,7 +9,7 @@ pub enum ScriptSource {
119
/// bitcoin script
1210
Script(ScriptBuf),
1311
/// definite descriptor
14-
Descriptor(Box<DefiniteDescriptor>),
12+
Descriptor(DefiniteDescriptor),
1513
}
1614

1715
impl From<ScriptBuf> for ScriptSource {
@@ -34,7 +32,7 @@ impl ScriptSource {
3432

3533
/// From descriptor
3634
pub fn from_descriptor(descriptor: DefiniteDescriptor) -> Self {
37-
Self::Descriptor(Box::new(descriptor))
35+
Self::Descriptor(descriptor)
3836
}
3937

4038
/// To ScriptBuf

src/selection.rs

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
use alloc::{boxed::Box, vec::Vec};
1+
use alloc::vec::Vec;
22
use core::fmt::{Debug, Display};
33

44
use bdk_coin_select::FeeRate;
5-
use bitcoin::{
5+
use miniscript::bitcoin;
6+
use miniscript::bitcoin::{
67
absolute::{self, LockTime},
7-
transaction, Psbt, Sequence,
8+
transaction, OutPoint, Psbt, Sequence,
89
};
9-
use miniscript::bitcoin;
10+
1011
use miniscript::psbt::PsbtExt;
1112

1213
use crate::{apply_anti_fee_sniping, Finalizer, Input, Output};
@@ -70,17 +71,15 @@ pub enum CreatePsbtError {
7071
/// Attempted to mix locktime types.
7172
LockTypeMismatch,
7273
/// Missing tx for legacy input.
73-
MissingFullTxForLegacyInput(Box<Input>),
74+
MissingFullTxForLegacyInput(OutPoint),
7475
/// Missing tx for segwit v0 input.
75-
MissingFullTxForSegwitV0Input(Box<Input>),
76+
MissingFullTxForSegwitV0Input(OutPoint),
7677
/// Psbt error.
7778
Psbt(bitcoin::psbt::Error),
7879
/// Update psbt output with descriptor error.
7980
OutputUpdate(miniscript::psbt::OutputUpdateError),
8081
/// Invalid locktime
8182
InvalidLockTime(absolute::LockTime),
82-
/// Invalid height
83-
InvalidHeight(u32),
8483
/// Unsupported version for anti fee snipping
8584
UnsupportedVersion(transaction::Version),
8685
}
@@ -89,15 +88,15 @@ impl core::fmt::Display for CreatePsbtError {
8988
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
9089
match self {
9190
CreatePsbtError::LockTypeMismatch => write!(f, "cannot mix locktime units"),
92-
CreatePsbtError::MissingFullTxForLegacyInput(input) => write!(
91+
CreatePsbtError::MissingFullTxForLegacyInput(outpoint) => write!(
9392
f,
9493
"legacy input that spends {} requires PSBT_IN_NON_WITNESS_UTXO",
95-
input.prev_outpoint()
94+
outpoint
9695
),
97-
CreatePsbtError::MissingFullTxForSegwitV0Input(input) => write!(
96+
CreatePsbtError::MissingFullTxForSegwitV0Input(outpoint) => write!(
9897
f,
9998
"segwit v0 input that spends {} requires PSBT_IN_NON_WITNESS_UTXO",
100-
input.prev_outpoint()
99+
outpoint
101100
),
102101
CreatePsbtError::Psbt(error) => Display::fmt(&error, f),
103102
CreatePsbtError::OutputUpdate(output_update_error) => {
@@ -106,9 +105,6 @@ impl core::fmt::Display for CreatePsbtError {
106105
CreatePsbtError::InvalidLockTime(locktime) => {
107106
write!(f, "The locktime - {}, is invalid", locktime)
108107
}
109-
CreatePsbtError::InvalidHeight(height) => {
110-
write!(f, "The height - {}, is invalid", height)
111-
}
112108
CreatePsbtError::UnsupportedVersion(version) => {
113109
write!(f, "Unsupported version {}", version)
114110
}
@@ -202,16 +198,16 @@ impl Selection {
202198
psbt_input.non_witness_utxo = plan_input.prev_tx().cloned();
203199
if psbt_input.non_witness_utxo.is_none() {
204200
if witness_version.is_none() {
205-
return Err(CreatePsbtError::MissingFullTxForLegacyInput(Box::new(
206-
plan_input.clone(),
207-
)));
201+
return Err(CreatePsbtError::MissingFullTxForLegacyInput(
202+
plan_input.prev_outpoint(),
203+
));
208204
}
209205
if params.mandate_full_tx_for_segwit_v0
210206
&& witness_version == Some(bitcoin::WitnessVersion::V0)
211207
{
212-
return Err(CreatePsbtError::MissingFullTxForSegwitV0Input(Box::new(
213-
plan_input.clone(),
214-
)));
208+
return Err(CreatePsbtError::MissingFullTxForSegwitV0Input(
209+
plan_input.prev_outpoint(),
210+
));
215211
}
216212
}
217213
continue;

src/utils.rs

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use alloc::vec::Vec;
33
use miniscript::bitcoin::{
44
absolute::{self, LockTime},
55
transaction::Version,
6-
Sequence, Transaction, WitnessVersion,
6+
Sequence, Transaction,
77
};
88

99
use rand_core::{OsRng, RngCore};
@@ -15,39 +15,41 @@ pub fn apply_anti_fee_sniping(
1515
current_height: absolute::Height,
1616
rbf_enabled: bool,
1717
) -> Result<(), CreatePsbtError> {
18-
const MAX_SEQUENCE_VALUE: u32 = 65_535;
18+
const MAX_RELATIVE_HEIGHT: u32 = 65_535;
1919
const USE_NLOCKTIME_PROBABILITY: u32 = 2;
2020
const MIN_SEQUENCE_VALUE: u32 = 1;
2121
const FURTHER_BACK_PROBABILITY: u32 = 10;
22-
const MAX_RANDOM_OFFSET: u32 = 99;
22+
const MAX_RANDOM_OFFSET: u32 = 100;
2323

2424
let mut rng = OsRng;
2525

2626
if tx.version < Version::TWO {
2727
return Err(CreatePsbtError::UnsupportedVersion(tx.version));
2828
}
2929

30-
let taproot_inputs: Vec<usize> = (0..tx.input.len())
31-
.filter(|&idx| {
32-
// Check if this input is taproot using the corresponding Input data
33-
inputs
34-
.get(idx)
35-
.and_then(|input| input.plan())
36-
.and_then(|plan| plan.witness_version())
37-
.map(|version| version == WitnessVersion::V1)
38-
.unwrap_or(false)
30+
// vector of input_index and associated Input ref.
31+
let taproot_inputs: Vec<(usize, &Input)> = tx
32+
.input
33+
.iter()
34+
.enumerate()
35+
.filter_map(|(vin, txin)| {
36+
let input = inputs
37+
.iter()
38+
.find(|input| input.prev_outpoint() == txin.previous_output)?;
39+
if input.prev_txout().script_pubkey.is_p2tr() {
40+
Some((vin, input))
41+
} else {
42+
None
43+
}
3944
})
4045
.collect();
4146

4247
// Check always‐locktime conditions
4348
let must_use_locktime = inputs.iter().any(|input| {
4449
let confirmation = input.confirmations(current_height);
4550
confirmation == 0
46-
|| confirmation > MAX_SEQUENCE_VALUE
47-
|| !matches!(
48-
input.plan().and_then(|plan| plan.witness_version()),
49-
Some(WitnessVersion::V1)
50-
)
51+
|| confirmation > MAX_RELATIVE_HEIGHT
52+
|| !input.prev_txout().script_pubkey.is_p2tr()
5153
});
5254

5355
let use_locktime = !rbf_enabled
@@ -64,15 +66,15 @@ pub fn apply_anti_fee_sniping(
6466
locktime = locktime.saturating_sub(random_offset);
6567
}
6668

67-
let new_locktime = LockTime::from_height(locktime)
68-
.map_err(|_| CreatePsbtError::InvalidHeight(locktime))?;
69+
let new_locktime = LockTime::from_height(locktime).expect("must be valid Height");
6970

7071
tx.lock_time = new_locktime;
7172
} else {
7273
// Use Sequence
7374
tx.lock_time = LockTime::ZERO;
74-
let input_index = random_range(&mut rng, taproot_inputs.len() as u32) as usize;
75-
let confirmation = inputs[input_index].confirmations(current_height);
75+
let random_index = random_range(&mut rng, taproot_inputs.len() as u32);
76+
let (input_index, input) = taproot_inputs[random_index as usize];
77+
let confirmation = input.confirmations(current_height);
7678

7779
let mut sequence_value = confirmation;
7880
if random_probability(&mut rng, FURTHER_BACK_PROBABILITY) {

0 commit comments

Comments
 (0)