Skip to content

Commit 9371018

Browse files
committed
Merge rust-bitcoin#4554: Sane InputWeightPredition Arbitrary Type
8dd24cb Add Arbitrary type for InputWeightPrediction (yancy) Pull request description: This type creates sane Arbitrary InputWeightPrediction types that do not panic. To this end, when a custom type is created by calling new() or from_slice() constructor, only use values that would no greater than block size 4 MB of witness data or 1 MB of non-witness data. This idea is from the discussion here rust-bitcoin#4547 I'd be up for a future PR that limits the constructors to no greater than 1MB or 4MB witness data, although I feel like this Arbitrary type will be less controversial. Furthermore, I did test this locally against my application and no panics where produced either through the constructor nor auxiliary methods `total_weight` or `witness_weight`. ACKs for top commit: tcharding: ACK 8dd24cb apoelstra: ACK 8dd24cb; successfully ran local tests Tree-SHA512: ff33f1a6ced4f68c4d236e362b1d03da405a8b9701cda0405405421ca21a563fa288c8065a9309e542fec0c8bc850119bcf93a2dc5e27677c42b35b1e5e52722
2 parents 3c64cef + 8dd24cb commit 9371018

File tree

1 file changed

+34
-0
lines changed

1 file changed

+34
-0
lines changed

bitcoin/src/blockdata/transaction.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
1313
use core::fmt;
1414

15+
#[cfg(feature = "arbitrary")]
16+
use arbitrary::{Arbitrary, Unstructured};
1517
use hashes::sha256d;
1618
use internals::{compact_size, write_err, ToU64};
1719
use io::{BufRead, Write};
@@ -1141,6 +1143,38 @@ mod sealed {
11411143
impl Sealed for super::Version {}
11421144
}
11431145

1146+
#[cfg(feature = "arbitrary")]
1147+
impl<'a> Arbitrary<'a> for InputWeightPrediction {
1148+
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
1149+
// limit script size to 4Mwu block size.
1150+
let max_block = Weight::MAX_BLOCK.to_wu() as usize;
1151+
let input_script_len = u.int_in_range(0..=max_block)?;
1152+
let remaining = max_block - input_script_len;
1153+
1154+
// create witness data if there is remaining space.
1155+
let mut witness_length = u.int_in_range(0..=remaining)?;
1156+
let mut witness_element_lengths = Vec::new();
1157+
1158+
// build vec of random witness element lengths.
1159+
while witness_length > 0 {
1160+
let elem = u.int_in_range(1..=witness_length)?;
1161+
witness_element_lengths.push(elem);
1162+
witness_length -= elem;
1163+
}
1164+
1165+
match u.int_in_range(0..=7)? {
1166+
0 => Ok(InputWeightPrediction::P2WPKH_MAX),
1167+
1 => Ok(InputWeightPrediction::NESTED_P2WPKH_MAX),
1168+
2 => Ok(InputWeightPrediction::P2PKH_COMPRESSED_MAX),
1169+
3 => Ok(InputWeightPrediction::P2PKH_UNCOMPRESSED_MAX),
1170+
4 => Ok(InputWeightPrediction::P2TR_KEY_DEFAULT_SIGHASH),
1171+
5 => Ok(InputWeightPrediction::P2TR_KEY_NON_DEFAULT_SIGHASH),
1172+
6 => Ok(InputWeightPrediction::new(input_script_len, witness_element_lengths)),
1173+
_ => Ok(InputWeightPrediction::from_slice(input_script_len, &witness_element_lengths)),
1174+
}
1175+
}
1176+
}
1177+
11441178
#[cfg(test)]
11451179
mod tests {
11461180
use hex::FromHex;

0 commit comments

Comments
 (0)