Skip to content

Commit 9c5f76a

Browse files
committed
WIP: TlvStream::range
1 parent 04d89ce commit 9c5f76a

File tree

1 file changed

+47
-6
lines changed

1 file changed

+47
-6
lines changed

lightning/src/offers/merkle.rs

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -143,28 +143,37 @@ fn tagged_branch_hash_from_engine(
143143

144144
/// [`Iterator`] over a sequence of bytes yielding [`TlvRecord`]s. The input is assumed to be a
145145
/// well-formed TLV stream.
146-
struct TlvStream<'a> {
146+
pub(super) struct TlvStream<'a> {
147147
data: io::Cursor<&'a [u8]>,
148148
}
149149

150150
impl<'a> TlvStream<'a> {
151-
fn new(data: &'a [u8]) -> Self {
151+
pub fn new(data: &'a [u8]) -> Self {
152152
Self {
153153
data: io::Cursor::new(data),
154154
}
155155
}
156156

157+
pub fn range<T>(self, types: T) -> impl core::iter::Iterator<Item = TlvRecord<'a>>
158+
where
159+
T: core::ops::RangeBounds<u64> + Clone,
160+
{
161+
let take_range = types.clone();
162+
self.skip_while(move |record| !types.contains(&record.r#type))
163+
.take_while(move |record| take_range.contains(&record.r#type))
164+
}
165+
157166
fn skip_signatures(self) -> core::iter::Filter<TlvStream<'a>, fn(&TlvRecord) -> bool> {
158167
self.filter(|record| !SIGNATURE_TYPES.contains(&record.r#type))
159168
}
160169
}
161170

162171
/// A slice into a [`TlvStream`] for a record.
163-
struct TlvRecord<'a> {
164-
r#type: u64,
172+
pub(super) struct TlvRecord<'a> {
173+
pub(super) r#type: u64,
165174
type_bytes: &'a [u8],
166175
// The entire TLV record.
167-
record_bytes: &'a [u8],
176+
pub(super) record_bytes: &'a [u8],
168177
}
169178

170179
impl<'a> Iterator for TlvStream<'a> {
@@ -212,7 +221,7 @@ impl<'a> Writeable for WithoutSignatures<'a> {
212221

213222
#[cfg(test)]
214223
mod tests {
215-
use super::{TlvStream, WithoutSignatures};
224+
use super::{SIGNATURE_TYPES, TlvStream, WithoutSignatures};
216225

217226
use bitcoin::hashes::{Hash, sha256};
218227
use bitcoin::secp256k1::{KeyPair, Secp256k1, SecretKey};
@@ -302,6 +311,38 @@ mod tests {
302311
);
303312
}
304313

314+
#[test]
315+
fn iterates_over_tlv_stream_range() {
316+
let secp_ctx = Secp256k1::new();
317+
let recipient_pubkey = {
318+
let secret_key = SecretKey::from_slice(&[41; 32]).unwrap();
319+
KeyPair::from_secret_key(&secp_ctx, &secret_key).public_key()
320+
};
321+
let payer_keys = {
322+
let secret_key = SecretKey::from_slice(&[42; 32]).unwrap();
323+
KeyPair::from_secret_key(&secp_ctx, &secret_key)
324+
};
325+
326+
let invoice_request = OfferBuilder::new("foo".into(), recipient_pubkey)
327+
.amount_msats(100)
328+
.build_unchecked()
329+
.request_invoice(vec![0; 8], payer_keys.public_key()).unwrap()
330+
.build_unchecked()
331+
.sign::<_, Infallible>(|digest| Ok(secp_ctx.sign_schnorr_no_aux_rand(digest, &payer_keys)))
332+
.unwrap();
333+
334+
let tlv_stream = TlvStream::new(&invoice_request.bytes).range(0..1)
335+
.chain(TlvStream::new(&invoice_request.bytes).range(1..80))
336+
.chain(TlvStream::new(&invoice_request.bytes).range(80..160))
337+
.chain(TlvStream::new(&invoice_request.bytes).range(160..240))
338+
.chain(TlvStream::new(&invoice_request.bytes).range(SIGNATURE_TYPES))
339+
.map(|r| r.record_bytes.to_vec())
340+
.flatten()
341+
.collect::<Vec<u8>>();
342+
343+
assert_eq!(tlv_stream, invoice_request.bytes);
344+
}
345+
305346
impl AsRef<[u8]> for InvoiceRequest {
306347
fn as_ref(&self) -> &[u8] {
307348
&self.bytes

0 commit comments

Comments
 (0)