Merge rust-bitcoin/rust-bitcoin#4186: Clean up Witness API
Pull request description: Enhance Witness struct element access methods: - Rename `nth()` to `get()` for clearer slice-like element retrieval - Introduce `get_back()` method for flexible reverse indexing - Remove redundant `second_to_last()` and `third_to_last()` methods - Add `#[track_caller]` to index implementation for better error tracking - Update all references to use new method names - Improve documentation with usage examples The changes provide a more intuitive and consistent approach to accessing witness elements. Close #4098 ACKs for top commit: Kixunil: ACK3ca3218c23
tcharding: ACK3ca3218c23
apoelstra: ACK 3ca3218c236c63a9b006047524e2b47e310f07d9; successfully ran local tests Tree-SHA512: 163e7457f3fe5141373e27a6df5fe1da6f2f05f02e877ef96243510d030d832c0fa86ade781e015a3c392f004651170b60438a83d330f1059457e5ade6478af7
This commit is contained in:
commit
febce17eff
|
@ -29,8 +29,8 @@ fn compute_sighash_p2wpkh(raw_tx: &[u8], inp_idx: usize, amount: Amount) {
|
|||
// BIP-141: The witness must consist of exactly 2 items (≤ 520 bytes each). The first one a
|
||||
// signature, and the second one a public key.
|
||||
assert_eq!(witness.len(), 2);
|
||||
let sig_bytes = witness.nth(0).unwrap();
|
||||
let pk_bytes = witness.nth(1).unwrap();
|
||||
let sig_bytes = witness.get(0).unwrap();
|
||||
let pk_bytes = witness.get(1).unwrap();
|
||||
|
||||
let sig = ecdsa::Signature::from_slice(sig_bytes).expect("failed to parse sig");
|
||||
|
||||
|
@ -118,7 +118,7 @@ fn compute_sighash_p2wsh(raw_tx: &[u8], inp_idx: usize, amount: Amount) {
|
|||
|
||||
//in an M of N multisig, the witness elements from 1 (0-based) to M-2 are signatures (with sighash flags as the last byte)
|
||||
for n in 1..=witness.len() - 2 {
|
||||
let sig_bytes = witness.nth(n).expect("out of bounds");
|
||||
let sig_bytes = witness.get(n).expect("out of bounds");
|
||||
let sig = ecdsa::Signature::from_slice(sig_bytes).expect("failed to parse sig");
|
||||
let sig_len = sig_bytes.len() - 1; //last byte is EcdsaSighashType sighash flag
|
||||
//ECDSA signature in DER format lengths are between 70 and 72 bytes
|
||||
|
|
|
@ -257,7 +257,7 @@ impl<'a> P2TrSpend<'a> {
|
|||
}),
|
||||
2 if witness.last().expect("len > 0").starts_with(&[TAPROOT_ANNEX_PREFIX]) => {
|
||||
let spend = P2TrSpend::Key {
|
||||
// signature: witness.second_to_last().expect("len > 1"),
|
||||
// signature: witness.get_back(1).expect("len > 1"),
|
||||
annex: witness.last(),
|
||||
};
|
||||
Some(spend)
|
||||
|
@ -267,15 +267,15 @@ impl<'a> P2TrSpend<'a> {
|
|||
// arm.
|
||||
3.. if witness.last().expect("len > 0").starts_with(&[TAPROOT_ANNEX_PREFIX]) => {
|
||||
let spend = P2TrSpend::Script {
|
||||
leaf_script: Script::from_bytes(witness.third_to_last().expect("len > 2")),
|
||||
control_block: witness.second_to_last().expect("len > 1"),
|
||||
leaf_script: Script::from_bytes(witness.get_back(2).expect("len > 2")),
|
||||
control_block: witness.get_back(1).expect("len > 1"),
|
||||
annex: witness.last(),
|
||||
};
|
||||
Some(spend)
|
||||
}
|
||||
_ => {
|
||||
let spend = P2TrSpend::Script {
|
||||
leaf_script: Script::from_bytes(witness.second_to_last().expect("len > 1")),
|
||||
leaf_script: Script::from_bytes(witness.get_back(1).expect("len > 1")),
|
||||
control_block: witness.last().expect("len > 0"),
|
||||
annex: None,
|
||||
};
|
||||
|
@ -514,13 +514,10 @@ mod test {
|
|||
assert_eq!(expected_wit[i], wit_el.to_lower_hex_string());
|
||||
}
|
||||
assert_eq!(expected_wit[1], tx.input[0].witness.last().unwrap().to_lower_hex_string());
|
||||
assert_eq!(
|
||||
expected_wit[0],
|
||||
tx.input[0].witness.second_to_last().unwrap().to_lower_hex_string()
|
||||
);
|
||||
assert_eq!(expected_wit[0], tx.input[0].witness.nth(0).unwrap().to_lower_hex_string());
|
||||
assert_eq!(expected_wit[1], tx.input[0].witness.nth(1).unwrap().to_lower_hex_string());
|
||||
assert_eq!(None, tx.input[0].witness.nth(2));
|
||||
assert_eq!(expected_wit[0], tx.input[0].witness.get_back(1).unwrap().to_lower_hex_string());
|
||||
assert_eq!(expected_wit[0], tx.input[0].witness.get(0).unwrap().to_lower_hex_string());
|
||||
assert_eq!(expected_wit[1], tx.input[0].witness.get(1).unwrap().to_lower_hex_string());
|
||||
assert_eq!(None, tx.input[0].witness.get(2));
|
||||
assert_eq!(expected_wit[0], tx.input[0].witness[0].to_lower_hex_string());
|
||||
assert_eq!(expected_wit[1], tx.input[0].witness[1].to_lower_hex_string());
|
||||
|
||||
|
|
|
@ -185,37 +185,41 @@ impl Witness {
|
|||
|
||||
/// Returns the last element in the witness, if any.
|
||||
#[inline]
|
||||
pub fn last(&self) -> Option<&[u8]> {
|
||||
if self.witness_elements == 0 {
|
||||
pub fn last(&self) -> Option<&[u8]> { self.get_back(0) }
|
||||
|
||||
/// Retrieves an element from the end of the witness by its reverse index.
|
||||
///
|
||||
/// `index` is 0-based from the end, where 0 is the last element, 1 is the second-to-last, etc.
|
||||
///
|
||||
/// Returns `None` if the requested index is beyond the witness's elements.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use bitcoin_primitives::witness::Witness;
|
||||
///
|
||||
/// let mut witness = Witness::new();
|
||||
/// witness.push(b"A");
|
||||
/// witness.push(b"B");
|
||||
/// witness.push(b"C");
|
||||
/// witness.push(b"D");
|
||||
///
|
||||
/// assert_eq!(witness.get_back(0), Some(b"D".as_slice()));
|
||||
/// assert_eq!(witness.get_back(1), Some(b"C".as_slice()));
|
||||
/// assert_eq!(witness.get_back(2), Some(b"B".as_slice()));
|
||||
/// assert_eq!(witness.get_back(3), Some(b"A".as_slice()));
|
||||
/// assert_eq!(witness.get_back(4), None);
|
||||
/// ```
|
||||
pub fn get_back(&self, index: usize) -> Option<&[u8]> {
|
||||
if self.witness_elements <= index {
|
||||
None
|
||||
} else {
|
||||
self.nth(self.witness_elements - 1)
|
||||
self.get(self.witness_elements - 1 - index)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the second-to-last element in the witness, if any.
|
||||
/// Returns a specific element from the witness by its index, if any.
|
||||
#[inline]
|
||||
pub fn second_to_last(&self) -> Option<&[u8]> {
|
||||
if self.witness_elements <= 1 {
|
||||
None
|
||||
} else {
|
||||
self.nth(self.witness_elements - 2)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the third-to-last element in the witness, if any.
|
||||
#[inline]
|
||||
pub fn third_to_last(&self) -> Option<&[u8]> {
|
||||
if self.witness_elements <= 2 {
|
||||
None
|
||||
} else {
|
||||
self.nth(self.witness_elements - 3)
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the nth element in the witness, if any
|
||||
#[inline]
|
||||
pub fn nth(&self, index: usize) -> Option<&[u8]> {
|
||||
pub fn get(&self, index: usize) -> Option<&[u8]> {
|
||||
let pos = decode_cursor(&self.content, self.indices_start, index)?;
|
||||
self.element_at(pos)
|
||||
}
|
||||
|
@ -274,8 +278,9 @@ pub struct Iter<'a> {
|
|||
impl Index<usize> for Witness {
|
||||
type Output = [u8];
|
||||
|
||||
#[track_caller]
|
||||
#[inline]
|
||||
fn index(&self, index: usize) -> &Self::Output { self.nth(index).expect("out of bounds") }
|
||||
fn index(&self, index: usize) -> &Self::Output { self.get(index).expect("out of bounds") }
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Iter<'a> {
|
||||
|
@ -468,12 +473,12 @@ mod test {
|
|||
let mut witness = Witness::default();
|
||||
assert!(witness.is_empty());
|
||||
assert_eq!(witness.last(), None);
|
||||
assert_eq!(witness.second_to_last(), None);
|
||||
assert_eq!(witness.get_back(1), None);
|
||||
|
||||
assert_eq!(witness.nth(0), None);
|
||||
assert_eq!(witness.nth(1), None);
|
||||
assert_eq!(witness.nth(2), None);
|
||||
assert_eq!(witness.nth(3), None);
|
||||
assert_eq!(witness.get(0), None);
|
||||
assert_eq!(witness.get(1), None);
|
||||
assert_eq!(witness.get(2), None);
|
||||
assert_eq!(witness.get(3), None);
|
||||
|
||||
// Push a single byte element onto the witness stack.
|
||||
let push = [11_u8];
|
||||
|
@ -491,13 +496,13 @@ mod test {
|
|||
let element_0 = push.as_slice();
|
||||
assert_eq!(element_0, &witness[0]);
|
||||
|
||||
assert_eq!(witness.second_to_last(), None);
|
||||
assert_eq!(witness.get_back(1), None);
|
||||
assert_eq!(witness.last(), Some(element_0));
|
||||
|
||||
assert_eq!(witness.nth(0), Some(element_0));
|
||||
assert_eq!(witness.nth(1), None);
|
||||
assert_eq!(witness.nth(2), None);
|
||||
assert_eq!(witness.nth(3), None);
|
||||
assert_eq!(witness.get(0), Some(element_0));
|
||||
assert_eq!(witness.get(1), None);
|
||||
assert_eq!(witness.get(2), None);
|
||||
assert_eq!(witness.get(3), None);
|
||||
|
||||
// Now push 2 byte element onto the witness stack.
|
||||
let push = [21u8, 22u8];
|
||||
|
@ -514,12 +519,12 @@ mod test {
|
|||
let element_1 = push.as_slice();
|
||||
assert_eq!(element_1, &witness[1]);
|
||||
|
||||
assert_eq!(witness.nth(0), Some(element_0));
|
||||
assert_eq!(witness.nth(1), Some(element_1));
|
||||
assert_eq!(witness.nth(2), None);
|
||||
assert_eq!(witness.nth(3), None);
|
||||
assert_eq!(witness.get(0), Some(element_0));
|
||||
assert_eq!(witness.get(1), Some(element_1));
|
||||
assert_eq!(witness.get(2), None);
|
||||
assert_eq!(witness.get(3), None);
|
||||
|
||||
assert_eq!(witness.second_to_last(), Some(element_0));
|
||||
assert_eq!(witness.get_back(1), Some(element_0));
|
||||
assert_eq!(witness.last(), Some(element_1));
|
||||
|
||||
// Now push another 2 byte element onto the witness stack.
|
||||
|
@ -537,13 +542,13 @@ mod test {
|
|||
let element_2 = push.as_slice();
|
||||
assert_eq!(element_2, &witness[2]);
|
||||
|
||||
assert_eq!(witness.nth(0), Some(element_0));
|
||||
assert_eq!(witness.nth(1), Some(element_1));
|
||||
assert_eq!(witness.nth(2), Some(element_2));
|
||||
assert_eq!(witness.nth(3), None);
|
||||
assert_eq!(witness.get(0), Some(element_0));
|
||||
assert_eq!(witness.get(1), Some(element_1));
|
||||
assert_eq!(witness.get(2), Some(element_2));
|
||||
assert_eq!(witness.get(3), None);
|
||||
|
||||
assert_eq!(witness.third_to_last(), Some(element_0));
|
||||
assert_eq!(witness.second_to_last(), Some(element_1));
|
||||
assert_eq!(witness.get_back(2), Some(element_0));
|
||||
assert_eq!(witness.get_back(1), Some(element_1));
|
||||
assert_eq!(witness.last(), Some(element_2));
|
||||
}
|
||||
|
||||
|
@ -574,8 +579,8 @@ mod test {
|
|||
let indices_start = elements.len();
|
||||
let witness =
|
||||
Witness::from_parts__unstable(content.clone(), witness_elements, indices_start);
|
||||
assert_eq!(witness.nth(0).unwrap(), [11_u8]);
|
||||
assert_eq!(witness.nth(1).unwrap(), [21_u8, 22]);
|
||||
assert_eq!(witness.get(0).unwrap(), [11_u8]);
|
||||
assert_eq!(witness.get(1).unwrap(), [21_u8, 22]);
|
||||
assert_eq!(witness.size(), 6);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue