diff --git a/bitcoin/src/blockdata/script.rs b/bitcoin/src/blockdata/script.rs index dc3a0f91..68efcb18 100644 --- a/bitcoin/src/blockdata/script.rs +++ b/bitcoin/src/blockdata/script.rs @@ -1433,10 +1433,11 @@ impl<'a> core::iter::FromIterator> for ScriptBuf { impl<'a> Extend> for ScriptBuf { fn extend(&mut self, iter: T) where T: IntoIterator> { - let mut iter = iter.into_iter(); + let iter = iter.into_iter(); // Most of Bitcoin scripts have only a few opcodes, so we can avoid reallocations in many // cases. if iter.size_hint().1.map(|max| max < 6).unwrap_or(false) { + let mut iter = iter.fuse(); // `MaybeUninit` might be faster but we don't want to introduce more `unsafe` than // required. let mut head = [None; 5]; @@ -1445,8 +1446,10 @@ impl<'a> Extend> for ScriptBuf { total_size += instr.script_serialized_len(); *head = Some(instr); } + // Incorrect impl of `size_hint` breaks `Iterator` contract so we're free to panic. + assert!(iter.next().is_none(), "Buggy implementation of `Iterator` on {} returns invalid upper bound", core::any::type_name::()); self.reserve(total_size); - for instr in iter { + for instr in head.iter().cloned().flatten() { self.push_instruction_no_opt(instr); } } else {