Skip to content

Commit ad40573

Browse files
authored
Merge pull request #1956 from TheBlueMatt/2023-01-ser-cleanups
Trivial Serialization Tweaks
2 parents 98417a1 + 3e9727b commit ad40573

File tree

2 files changed

+127
-64
lines changed

2 files changed

+127
-64
lines changed

lightning/src/util/ser.rs

+115-64
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ use core::cmp;
2222
use core::convert::TryFrom;
2323
use core::ops::Deref;
2424

25+
use alloc::collections::BTreeMap;
26+
2527
use bitcoin::secp256k1::{PublicKey, SecretKey};
2628
use bitcoin::secp256k1::constants::{PUBLIC_KEY_SIZE, SECRET_KEY_SIZE, COMPACT_SIGNATURE_SIZE, SCHNORR_SIGNATURE_SIZE};
2729
use bitcoin::secp256k1::ecdsa;
@@ -381,6 +383,40 @@ impl Readable for BigSize {
381383
}
382384
}
383385

386+
/// The lightning protocol uses u16s for lengths in most cases. As our serialization framework
387+
/// primarily targets that, we must as well. However, because we may serialize objects that have
388+
/// more than 65K entries, we need to be able to store larger values. Thus, we define a variable
389+
/// length integer here that is backwards-compatible for values < 0xffff. We treat 0xffff as
390+
/// "read eight more bytes".
391+
///
392+
/// To ensure we only have one valid encoding per value, we add 0xffff to values written as eight
393+
/// bytes. Thus, 0xfffe is serialized as 0xfffe, whereas 0xffff is serialized as
394+
/// 0xffff0000000000000000 (i.e. read-eight-bytes then zero).
395+
struct CollectionLength(pub u64);
396+
impl Writeable for CollectionLength {
397+
#[inline]
398+
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
399+
if self.0 < 0xffff {
400+
(self.0 as u16).write(writer)
401+
} else {
402+
0xffffu16.write(writer)?;
403+
(self.0 - 0xffff).write(writer)
404+
}
405+
}
406+
}
407+
408+
impl Readable for CollectionLength {
409+
#[inline]
410+
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
411+
let mut val: u64 = <u16 as Readable>::read(r)? as u64;
412+
if val == 0xffff {
413+
val = <u64 as Readable>::read(r)?
414+
.checked_add(0xffff).ok_or(DecodeError::InvalidValue)?;
415+
}
416+
Ok(CollectionLength(val))
417+
}
418+
}
419+
384420
/// In TLV we occasionally send fields which only consist of, or potentially end with, a
385421
/// variable-length integer which is simply truncated by skipping high zero bytes. This type
386422
/// encapsulates such integers implementing [`Readable`]/[`Writeable`] for them.
@@ -588,50 +624,54 @@ impl<'a, T> From<&'a Vec<T>> for WithoutLength<&'a Vec<T>> {
588624
fn from(v: &'a Vec<T>) -> Self { Self(v) }
589625
}
590626

591-
// HashMap
592-
impl<K, V> Writeable for HashMap<K, V>
593-
where K: Writeable + Eq + Hash,
594-
V: Writeable
595-
{
596-
#[inline]
597-
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
598-
(self.len() as u16).write(w)?;
599-
for (key, value) in self.iter() {
600-
key.write(w)?;
601-
value.write(w)?;
627+
macro_rules! impl_for_map {
628+
($ty: ident, $keybound: ident, $constr: expr) => {
629+
impl<K, V> Writeable for $ty<K, V>
630+
where K: Writeable + Eq + $keybound, V: Writeable
631+
{
632+
#[inline]
633+
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
634+
CollectionLength(self.len() as u64).write(w)?;
635+
for (key, value) in self.iter() {
636+
key.write(w)?;
637+
value.write(w)?;
638+
}
639+
Ok(())
640+
}
602641
}
603-
Ok(())
604-
}
605-
}
606642

607-
impl<K, V> Readable for HashMap<K, V>
608-
where K: Readable + Eq + Hash,
609-
V: MaybeReadable
610-
{
611-
#[inline]
612-
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
613-
let len: u16 = Readable::read(r)?;
614-
let mut ret = HashMap::with_capacity(len as usize);
615-
for _ in 0..len {
616-
let k = K::read(r)?;
617-
let v_opt = V::read(r)?;
618-
if let Some(v) = v_opt {
619-
if ret.insert(k, v).is_some() {
620-
return Err(DecodeError::InvalidValue);
643+
impl<K, V> Readable for $ty<K, V>
644+
where K: Readable + Eq + $keybound, V: MaybeReadable
645+
{
646+
#[inline]
647+
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
648+
let len: CollectionLength = Readable::read(r)?;
649+
let mut ret = $constr(len.0 as usize);
650+
for _ in 0..len.0 {
651+
let k = K::read(r)?;
652+
let v_opt = V::read(r)?;
653+
if let Some(v) = v_opt {
654+
if ret.insert(k, v).is_some() {
655+
return Err(DecodeError::InvalidValue);
656+
}
657+
}
621658
}
659+
Ok(ret)
622660
}
623661
}
624-
Ok(ret)
625662
}
626663
}
627664

665+
impl_for_map!(BTreeMap, Ord, |_| BTreeMap::new());
666+
impl_for_map!(HashMap, Hash, |len| HashMap::with_capacity(len));
667+
628668
// HashSet
629669
impl<T> Writeable for HashSet<T>
630670
where T: Writeable + Eq + Hash
631671
{
632672
#[inline]
633673
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
634-
(self.len() as u16).write(w)?;
674+
CollectionLength(self.len() as u64).write(w)?;
635675
for item in self.iter() {
636676
item.write(w)?;
637677
}
@@ -644,9 +684,9 @@ where T: Readable + Eq + Hash
644684
{
645685
#[inline]
646686
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
647-
let len: u16 = Readable::read(r)?;
648-
let mut ret = HashSet::with_capacity(len as usize);
649-
for _ in 0..len {
687+
let len: CollectionLength = Readable::read(r)?;
688+
let mut ret = HashSet::with_capacity(cmp::min(len.0 as usize, MAX_BUF_SIZE / core::mem::size_of::<T>()));
689+
for _ in 0..len.0 {
650690
if !ret.insert(T::read(r)?) {
651691
return Err(DecodeError::InvalidValue)
652692
}
@@ -656,51 +696,62 @@ where T: Readable + Eq + Hash
656696
}
657697

658698
// Vectors
659-
impl Writeable for Vec<u8> {
660-
#[inline]
661-
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
662-
(self.len() as u16).write(w)?;
663-
w.write_all(&self)
664-
}
665-
}
699+
macro_rules! impl_for_vec {
700+
($ty: ty $(, $name: ident)*) => {
701+
impl<$($name : Writeable),*> Writeable for Vec<$ty> {
702+
#[inline]
703+
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
704+
CollectionLength(self.len() as u64).write(w)?;
705+
for elem in self.iter() {
706+
elem.write(w)?;
707+
}
708+
Ok(())
709+
}
710+
}
666711

667-
impl Readable for Vec<u8> {
668-
#[inline]
669-
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
670-
let len: u16 = Readable::read(r)?;
671-
let mut ret = Vec::with_capacity(len as usize);
672-
ret.resize(len as usize, 0);
673-
r.read_exact(&mut ret)?;
674-
Ok(ret)
712+
impl<$($name : Readable),*> Readable for Vec<$ty> {
713+
#[inline]
714+
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
715+
let len: CollectionLength = Readable::read(r)?;
716+
let mut ret = Vec::with_capacity(cmp::min(len.0 as usize, MAX_BUF_SIZE / core::mem::size_of::<$ty>()));
717+
for _ in 0..len.0 {
718+
if let Some(val) = MaybeReadable::read(r)? {
719+
ret.push(val);
720+
}
721+
}
722+
Ok(ret)
723+
}
724+
}
675725
}
676726
}
677-
impl Writeable for Vec<ecdsa::Signature> {
727+
728+
impl Writeable for Vec<u8> {
678729
#[inline]
679730
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
680-
(self.len() as u16).write(w)?;
681-
for e in self.iter() {
682-
e.write(w)?;
683-
}
684-
Ok(())
731+
CollectionLength(self.len() as u64).write(w)?;
732+
w.write_all(&self)
685733
}
686734
}
687735

688-
impl Readable for Vec<ecdsa::Signature> {
736+
impl Readable for Vec<u8> {
689737
#[inline]
690738
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
691-
let len: u16 = Readable::read(r)?;
692-
let byte_size = (len as usize)
693-
.checked_mul(COMPACT_SIGNATURE_SIZE)
694-
.ok_or(DecodeError::BadLengthDescriptor)?;
695-
if byte_size > MAX_BUF_SIZE {
696-
return Err(DecodeError::BadLengthDescriptor);
739+
let mut len: CollectionLength = Readable::read(r)?;
740+
let mut ret = Vec::new();
741+
while len.0 > 0 {
742+
let readamt = cmp::min(len.0 as usize, MAX_BUF_SIZE);
743+
let readstart = ret.len();
744+
ret.resize(readstart + readamt, 0);
745+
r.read_exact(&mut ret[readstart..])?;
746+
len.0 -= readamt as u64;
697747
}
698-
let mut ret = Vec::with_capacity(len as usize);
699-
for _ in 0..len { ret.push(Readable::read(r)?); }
700748
Ok(ret)
701749
}
702750
}
703751

752+
impl_for_vec!(ecdsa::Signature);
753+
impl_for_vec!((A, B), A, B);
754+
704755
impl Writeable for Script {
705756
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
706757
(self.len() as u16).write(w)?;
@@ -1028,7 +1079,7 @@ impl Readable for () {
10281079
impl Writeable for String {
10291080
#[inline]
10301081
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
1031-
(self.len() as u16).write(w)?;
1082+
CollectionLength(self.len() as u64).write(w)?;
10321083
w.write_all(self.as_bytes())
10331084
}
10341085
}

lightning/src/util/ser_macros.rs

+12
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ macro_rules! _encode_tlv {
3939
field.write($stream)?;
4040
}
4141
};
42+
($stream: expr, $type: expr, $field: expr, ignorable) => {
43+
$crate::_encode_tlv!($stream, $type, $field, required);
44+
};
4245
($stream: expr, $type: expr, $field: expr, (option, encoding: ($fieldty: ty, $encoding: ident))) => {
4346
$crate::_encode_tlv!($stream, $type, $field.map(|f| $encoding(f)), option);
4447
};
@@ -155,6 +158,9 @@ macro_rules! _get_varint_length_prefixed_tlv_length {
155158
$len.0 += field_len;
156159
}
157160
};
161+
($len: expr, $type: expr, $field: expr, ignorable) => {
162+
$crate::_get_varint_length_prefixed_tlv_length!($len, $type, $field, required);
163+
};
158164
}
159165

160166
/// See the documentation of [`write_tlv_fields`].
@@ -581,6 +587,9 @@ macro_rules! _init_tlv_based_struct_field {
581587
($field: ident, option) => {
582588
$field
583589
};
590+
($field: ident, ignorable) => {
591+
if $field.is_none() { return Ok(None); } else { $field.unwrap() }
592+
};
584593
($field: ident, required) => {
585594
$field.0.unwrap()
586595
};
@@ -610,6 +619,9 @@ macro_rules! _init_tlv_field_var {
610619
($field: ident, option) => {
611620
let mut $field = None;
612621
};
622+
($field: ident, ignorable) => {
623+
let mut $field = None;
624+
};
613625
}
614626

615627
/// Equivalent to running [`_init_tlv_field_var`] then [`read_tlv_fields`].

0 commit comments

Comments
 (0)