ddk_messages/
ser_impls.rs

1//! Set of utility functions to help with serialization.
2
3use bitcoin::Address;
4use bitcoin::Network;
5use bitcoin::SignedAmount;
6use ddk_dlc::dlc_input::DlcInputInfo;
7use ddk_dlc::{EnumerationPayout, PartyParams, Payout, TxInputInfo};
8use lightning::io::Read;
9use lightning::ln::msgs::DecodeError;
10use lightning::ln::wire::Type;
11use lightning::util::ser::{Readable, Writeable, Writer};
12use secp256k1_zkp::{ffi::ECDSA_ADAPTOR_SIGNATURE_LENGTH, EcdsaAdaptorSignature};
13use std::collections::HashMap;
14use std::hash::Hash;
15
16const MAX_VEC_SIZE: u64 = 1000000;
17
18/// Taken from rust-lightning: <https://github.com/rust-bitcoin/rust-lightning/blob/v0.0.101/lightning/src/util/ser.rs#L295>
19///
20/// Lightning TLV uses a custom variable-length integer called BigSize. It is similar to Bitcoin's
21/// variable-length integers except that it is serialized in big-endian instead of little-endian.
22///
23/// Like Bitcoin's variable-length integer, it exhibits ambiguity in that certain values can be
24/// encoded in several different ways, which we must check for at deserialization-time. Thus, if
25/// you're looking for an example of a variable-length integer to use for your own project, move
26/// along, this is a rather poor design.
27pub struct BigSize(pub u64);
28impl Writeable for BigSize {
29    #[inline]
30    fn write<W: Writer>(&self, writer: &mut W) -> Result<(), lightning::io::Error> {
31        match self.0 {
32            0..=0xFC => (self.0 as u8).write(writer),
33            0xFD..=0xFFFF => {
34                0xFDu8.write(writer)?;
35                (self.0 as u16).write(writer)
36            }
37            0x10000..=0xFFFFFFFF => {
38                0xFEu8.write(writer)?;
39                (self.0 as u32).write(writer)
40            }
41            _ => {
42                0xFFu8.write(writer)?;
43                self.0.write(writer)
44            }
45        }
46    }
47}
48impl Readable for BigSize {
49    #[inline]
50    fn read<R: Read>(reader: &mut R) -> Result<BigSize, DecodeError> {
51        let n: u8 = Readable::read(reader)?;
52        match n {
53            0xFF => {
54                let x: u64 = Readable::read(reader)?;
55                if x < 0x100000000 {
56                    Err(DecodeError::InvalidValue)
57                } else {
58                    Ok(BigSize(x))
59                }
60            }
61            0xFE => {
62                let x: u32 = Readable::read(reader)?;
63                if x < 0x10000 {
64                    Err(DecodeError::InvalidValue)
65                } else {
66                    Ok(BigSize(x as u64))
67                }
68            }
69            0xFD => {
70                let x: u16 = Readable::read(reader)?;
71                if x < 0xFD {
72                    Err(DecodeError::InvalidValue)
73                } else {
74                    Ok(BigSize(x as u64))
75                }
76            }
77            n => Ok(BigSize(n as u64)),
78        }
79    }
80}
81
82/// Writes a given string to the given writer, prefixing the string length as
83/// a BigSize value.
84pub fn write_string<W: Writer>(input: &str, writer: &mut W) -> Result<(), lightning::io::Error> {
85    let len = BigSize(input.len() as u64);
86    len.write(writer)?;
87    let bytes = input.as_bytes();
88
89    for b in bytes {
90        b.write(writer)?;
91    }
92
93    Ok(())
94}
95
96/// Reads a string from the given reader.
97pub fn read_string<R: Read>(reader: &mut R) -> Result<String, DecodeError> {
98    let len: BigSize = Readable::read(reader)?;
99
100    if len.0 > MAX_VEC_SIZE {
101        return Err(DecodeError::InvalidValue);
102    }
103
104    let mut buf = Vec::with_capacity(len.0 as usize);
105
106    for _ in 0..len.0 {
107        let b: u8 = Readable::read(reader)?;
108        buf.push(b);
109    }
110
111    let res = match String::from_utf8(buf) {
112        Ok(s) => s,
113        Err(_) => return Err(DecodeError::InvalidValue),
114    };
115
116    Ok(res)
117}
118
119/// Writes a set of strings to the given writer.
120pub fn write_strings<W: Writer>(
121    inputs: &[String],
122    writer: &mut W,
123) -> Result<(), lightning::io::Error> {
124    BigSize(inputs.len() as u64).write(writer)?;
125    for s in inputs {
126        write_string(s, writer)?;
127    }
128
129    Ok(())
130}
131
132/// Reads a set of strings from the given reader.
133pub fn read_strings<R: Read>(reader: &mut R) -> Result<Vec<String>, DecodeError> {
134    let len: BigSize = lightning::util::ser::Readable::read(reader)?;
135    if len.0 > MAX_VEC_SIZE {
136        return Err(DecodeError::InvalidValue);
137    }
138    let mut res = Vec::<String>::new();
139    for _ in 0..len.0 {
140        res.push(read_string(reader)?);
141    }
142
143    Ok(res)
144}
145
146/// Writes a set of strings to the given writer, using `u16` prefixes, compared
147/// to [`write_strings`] which uses `BigSize` prefixes.
148pub fn write_strings_u16<W: Writer>(
149    inputs: &[String],
150    writer: &mut W,
151) -> Result<(), lightning::io::Error> {
152    (inputs.len() as u16).write(writer)?;
153    for s in inputs {
154        write_string(s, writer)?;
155    }
156
157    Ok(())
158}
159
160/// Reads a set of string from the given reader, assuming `u16` prefixes, compared
161/// to [`read_strings`] which assumes `BigSize` prefixes.
162pub fn read_strings_u16<R: Read>(
163    reader: &mut R,
164) -> Result<Vec<String>, lightning::ln::msgs::DecodeError> {
165    let len: u16 = lightning::util::ser::Readable::read(reader)?;
166    let mut res = Vec::<String>::new();
167    for _ in 0..len {
168        res.push(read_string(reader)?);
169    }
170
171    Ok(res)
172}
173
174/// Writes an `f64` value to the given writer.
175pub fn write_f64<W: lightning::util::ser::Writer>(
176    input: f64,
177    writer: &mut W,
178) -> Result<(), ::lightning::io::Error> {
179    for b in input.to_be_bytes() {
180        b.write(writer)?;
181    }
182
183    Ok(())
184}
185
186/// Reads an `f64` value from the given reader.
187pub fn read_f64<R: ::lightning::io::Read>(
188    reader: &mut R,
189) -> Result<f64, lightning::ln::msgs::DecodeError> {
190    let mut buf = [0u8; 8];
191    for b in &mut buf {
192        *b = Readable::read(reader)?;
193    }
194    Ok(f64::from_be_bytes(buf))
195}
196
197/// Writes a [`secp256k1_zkp::schnorrsig::Signature`] value to the given writer.
198pub fn write_schnorrsig<W: lightning::util::ser::Writer>(
199    signature: &secp256k1_zkp::schnorr::Signature,
200    writer: &mut W,
201) -> Result<(), ::lightning::io::Error> {
202    signature.as_ref().write(writer)
203}
204
205/// Reads a [`secp256k1_zkp::schnorrsig::Signature`] value from the given reader.
206pub fn read_schnorrsig<R: ::lightning::io::Read>(
207    reader: &mut R,
208) -> Result<secp256k1_zkp::schnorr::Signature, lightning::ln::msgs::DecodeError> {
209    let buf: [u8; 64] = Readable::read(reader)?;
210    match secp256k1_zkp::schnorr::Signature::from_slice(&buf) {
211        Ok(sig) => Ok(sig),
212        Err(_) => Err(lightning::ln::msgs::DecodeError::InvalidValue),
213    }
214}
215
216/// Writes a set of [`secp256k1_zkp::schnorrsig::Signature`] to the given writer.
217pub fn write_schnorr_signatures<W: lightning::util::ser::Writer>(
218    signatures: &[secp256k1_zkp::schnorr::Signature],
219    writer: &mut W,
220) -> Result<(), ::lightning::io::Error> {
221    (signatures.len() as u16).write(writer)?;
222    for signature in signatures {
223        write_schnorrsig(signature, writer)?;
224    }
225    Ok(())
226}
227
228/// Reads a set of [`secp256k1_zkp::schnorrsig::Signature`] from the given reader.
229pub fn read_schnorr_signatures<R: Read>(
230    reader: &mut R,
231) -> Result<Vec<secp256k1_zkp::schnorr::Signature>, lightning::ln::msgs::DecodeError> {
232    let len: u16 = Readable::read(reader)?;
233    let byte_size = (len as usize)
234        .checked_mul(secp256k1_zkp::constants::SCHNORR_SIGNATURE_SIZE)
235        .ok_or(lightning::ln::msgs::DecodeError::BadLengthDescriptor)?;
236    if byte_size > lightning::util::ser::MAX_BUF_SIZE {
237        return Err(lightning::ln::msgs::DecodeError::BadLengthDescriptor);
238    }
239    let mut ret = Vec::with_capacity(len as usize);
240    for _ in 0..len {
241        ret.push(read_schnorrsig(reader)?);
242    }
243    Ok(ret)
244}
245
246/// Writes a schnorr public key to the given writer.
247pub fn write_schnorr_pubkey<W: lightning::util::ser::Writer>(
248    pubkey: &secp256k1_zkp::XOnlyPublicKey,
249    writer: &mut W,
250) -> Result<(), ::lightning::io::Error> {
251    pubkey.serialize().write(writer)
252}
253
254/// Reads a schnorr public key from the given reader.
255pub fn read_schnorr_pubkey<R: ::lightning::io::Read>(
256    reader: &mut R,
257) -> Result<secp256k1_zkp::XOnlyPublicKey, lightning::ln::msgs::DecodeError> {
258    let buf: [u8; 32] = Readable::read(reader)?;
259    match secp256k1_zkp::XOnlyPublicKey::from_slice(&buf) {
260        Ok(sig) => Ok(sig),
261        Err(_) => Err(lightning::ln::msgs::DecodeError::InvalidValue),
262    }
263}
264
265/// Writes a set of schnorr public keys to the given writer.
266pub fn write_schnorr_pubkeys<W: Writer>(
267    pubkeys: &[secp256k1_zkp::XOnlyPublicKey],
268    writer: &mut W,
269) -> Result<(), ::lightning::io::Error> {
270    (pubkeys.len() as u16).write(writer)?;
271    for pubkey in pubkeys {
272        write_schnorr_pubkey(pubkey, writer)?;
273    }
274    Ok(())
275}
276
277/// Reads a set of schnorr public keys from the given reader.
278pub fn read_schnorr_pubkeys<R: ::lightning::io::Read>(
279    reader: &mut R,
280) -> Result<Vec<secp256k1_zkp::XOnlyPublicKey>, DecodeError> {
281    let len: u16 = Readable::read(reader)?;
282    let byte_size = (len as usize)
283        .checked_mul(secp256k1_zkp::constants::SCHNORR_PUBLIC_KEY_SIZE)
284        .ok_or(DecodeError::BadLengthDescriptor)?;
285    if byte_size > lightning::util::ser::MAX_BUF_SIZE {
286        return Err(DecodeError::BadLengthDescriptor);
287    }
288    let mut ret = Vec::with_capacity(len as usize);
289    for _ in 0..len {
290        ret.push(read_schnorr_pubkey(reader)?);
291    }
292    Ok(ret)
293}
294
295/// Writes a vector of writeable to the given writer.
296pub fn write_vec<W: Writer, T>(input: &Vec<T>, writer: &mut W) -> Result<(), ::lightning::io::Error>
297where
298    T: Writeable,
299{
300    write_vec_cb(input, writer, &<T as Writeable>::write)
301}
302
303/// Reads a vector of writeable from the given reader.
304pub fn read_vec<R: ::lightning::io::Read, T>(reader: &mut R) -> Result<Vec<T>, DecodeError>
305where
306    T: Readable,
307{
308    read_vec_cb(reader, &Readable::read)
309}
310
311/// Writes a vector of values to the given writer using the provided callback to
312/// serialize each value.
313pub fn write_vec_cb<W: Writer, T, F>(
314    input: &Vec<T>,
315    writer: &mut W,
316    cb: &F,
317) -> Result<(), ::lightning::io::Error>
318where
319    F: Fn(&T, &mut W) -> Result<(), ::lightning::io::Error>,
320{
321    BigSize(input.len() as u64).write(writer)?;
322    for s in input {
323        cb(s, writer)?;
324    }
325    Ok(())
326}
327
328/// Reads a vector of values from the given reader using the provided callback to
329/// deserialize each value.
330pub fn read_vec_cb<R: ::lightning::io::Read, T, F>(
331    reader: &mut R,
332    cb: &F,
333) -> Result<Vec<T>, DecodeError>
334where
335    F: Fn(&mut R) -> Result<T, DecodeError>,
336{
337    let len: BigSize = Readable::read(reader)?;
338    if len.0 > MAX_VEC_SIZE {
339        return Err(DecodeError::InvalidValue);
340    }
341    let mut res = Vec::<T>::new();
342    for _ in 0..len.0 {
343        res.push(cb(reader)?);
344    }
345
346    Ok(res)
347}
348
349/// Writes a vector of values to the given writer. This function differs from
350/// [`write_vec`] in that it uses `u16` prefixes to give the length of the vector
351/// instead of a `BigSize`.
352pub fn write_vec_u16<W: Writer, T>(
353    input: &[T],
354    writer: &mut W,
355) -> Result<(), ::lightning::io::Error>
356where
357    T: Writeable,
358{
359    write_vec_u16_cb(input, writer, &<T as Writeable>::write)
360}
361
362/// Reads a vector of values from the given reader. This function differs from
363/// [`read_vec`] in that it uses `u16` prefixes to read the length of the vector
364/// instead of a `BigSize`.
365pub fn read_vec_u16<R: ::lightning::io::Read, T>(reader: &mut R) -> Result<Vec<T>, DecodeError>
366where
367    T: Readable,
368{
369    read_vec_u16_cb(reader, &Readable::read)
370}
371
372/// Writes a vector of values to the given writer using the provided callback to
373/// serialize each value. This function differs from [`write_vec_cb`] in that it
374/// uses `u16` prefixes to give the length of the vector instead of a `BigSize`.
375pub fn write_vec_u16_cb<W: Writer, T, F>(
376    input: &[T],
377    writer: &mut W,
378    cb: &F,
379) -> Result<(), ::lightning::io::Error>
380where
381    F: Fn(&T, &mut W) -> Result<(), ::lightning::io::Error>,
382{
383    (input.len() as u16).write(writer)?;
384    for s in input {
385        cb(s, writer)?;
386    }
387    Ok(())
388}
389
390/// Reads a vector of values from the given reader using the provided callback to
391/// deserialize each value. This function differs from [`read_vec_cb`] in that it
392/// uses `u16` prefixes to read the length of the vector instead of a `BigSize`.
393pub fn read_vec_u16_cb<R: ::lightning::io::Read, T, F>(
394    reader: &mut R,
395    cb: &F,
396) -> Result<Vec<T>, DecodeError>
397where
398    F: Fn(&mut R) -> Result<T, DecodeError>,
399{
400    let len: u16 = Readable::read(reader)?;
401    let mut res = Vec::<T>::new();
402    for _ in 0..len {
403        res.push(cb(reader)?);
404    }
405
406    Ok(res)
407}
408
409/// Writes a usize value as a u64 to the given writer.
410pub fn write_usize<W: Writer>(i: &usize, writer: &mut W) -> Result<(), ::lightning::io::Error> {
411    <u64 as Writeable>::write(&(*i as u64), writer)
412}
413
414/// Reads a usize value as a u64 from the given reader.
415pub fn read_usize<R: ::lightning::io::Read>(reader: &mut R) -> Result<usize, DecodeError> {
416    let i: u64 = Readable::read(reader)?;
417    Ok(i as usize)
418}
419
420/// Writes an option of a [`lightning::util::ser::Writeable`] value to the given writer.
421pub fn write_option<W: Writer, T>(
422    t: &Option<T>,
423    writer: &mut W,
424) -> Result<(), ::lightning::io::Error>
425where
426    T: Writeable,
427{
428    write_option_cb(t, writer, &<T as Writeable>::write)
429}
430
431/// Reads an option of a [`lightning::util::ser::Writeable`] value from the given reader.
432pub fn read_option<R: ::lightning::io::Read, T>(reader: &mut R) -> Result<Option<T>, DecodeError>
433where
434    T: Readable,
435{
436    read_option_cb(reader, &<T as Readable>::read)
437}
438
439/// Writes an option using the provided callback to serialize the inner value (if any).
440pub fn write_option_cb<W: Writer, T, F>(
441    t: &Option<T>,
442    writer: &mut W,
443    cb: &F,
444) -> Result<(), ::lightning::io::Error>
445where
446    F: Fn(&T, &mut W) -> Result<(), ::lightning::io::Error>,
447{
448    match t {
449        Some(t) => {
450            1_u8.write(writer)?;
451            cb(t, writer)
452        }
453        None => 0_u8.write(writer),
454    }
455}
456
457/// Reads an option using the provided callback to deserialize the inner value (if any).
458pub fn read_option_cb<R: ::lightning::io::Read, T, F>(
459    reader: &mut R,
460    cb: &F,
461) -> Result<Option<T>, DecodeError>
462where
463    F: Fn(&mut R) -> Result<T, DecodeError>,
464{
465    let prefix: u8 = Readable::read(reader)?;
466    let res = match prefix {
467        0 => None,
468        1 => Some(cb(reader)?),
469        _ => return Err(DecodeError::InvalidValue),
470    };
471    Ok(res)
472}
473
474/// Writes a [`bitcoin::util::address::Address`] value to the given writer.
475///
476/// https://docs.rs/bitcoin/0.30.2/bitcoin/address/struct.Address.html
477///
478/// Parsed addresses do not always have one network. The problem is that legacy testnet, regtest and
479/// signet addresse use the same prefix instead of multiple different ones. When parsing,
480/// such addresses are always assumed to be testnet addresses (the same is true for bech32 signet addresses).
481///
482/// Only checks if the address is Mainnet.
483pub fn write_address<W: Writer>(
484    address: &Address,
485    writer: &mut W,
486) -> Result<(), ::lightning::io::Error> {
487    address.script_pubkey().write(writer)?;
488    let unchecked_address = address.as_unchecked();
489
490    const NETWORKS: [Network; 4] = [
491        Network::Bitcoin,
492        Network::Testnet,
493        Network::Signet,
494        Network::Regtest,
495    ];
496
497    let mut net: u8 = 0;
498
499    for (i, n) in NETWORKS.iter().enumerate() {
500        if unchecked_address.is_valid_for_network(*n) {
501            net = i as u8;
502            break;
503        }
504    }
505
506    net.write(writer)
507}
508
509/// Reads a [`bitcoin::util::address::Address`] value from the given reader.
510pub fn read_address<R: Read>(reader: &mut R) -> Result<Address, DecodeError> {
511    let script: bitcoin::ScriptBuf = Readable::read(reader)?;
512    let net: u8 = Readable::read(reader)?;
513    let network = match net {
514        0 => Network::Bitcoin,
515        1 => Network::Testnet,
516        2 => Network::Signet,
517        3 => Network::Regtest,
518        _ => return Err(DecodeError::InvalidValue),
519    };
520    Ok(bitcoin::Address::from_script(&script, network).unwrap())
521}
522
523/// Writes an [`secp256k1_zkp::EcdsaAdaptorSignature`] to the given writer.
524pub fn write_ecdsa_adaptor_signature<W: Writer>(
525    sig: &EcdsaAdaptorSignature,
526    writer: &mut W,
527) -> Result<(), ::lightning::io::Error> {
528    for x in sig.as_ref() {
529        x.write(writer)?;
530    }
531    Ok(())
532}
533
534/// Reads an [`secp256k1_zkp::EcdsaAdaptorSignature`] from the given reader.
535pub fn read_ecdsa_adaptor_signature<R: ::lightning::io::Read>(
536    reader: &mut R,
537) -> Result<EcdsaAdaptorSignature, DecodeError> {
538    let mut buf: Vec<u8> = Vec::with_capacity(ECDSA_ADAPTOR_SIGNATURE_LENGTH);
539
540    for _ in 0..ECDSA_ADAPTOR_SIGNATURE_LENGTH {
541        buf.push(Readable::read(reader)?);
542    }
543    EcdsaAdaptorSignature::from_slice(&buf).map_err(|_| DecodeError::InvalidValue)
544}
545
546/// Writes a set of [`secp256k1_zkp::EcdsaAdaptorSignature`] to the given writer.
547#[allow(clippy::ptr_arg)] // Need to have Vec to work with callbacks.
548pub fn write_ecdsa_adaptor_signatures<W: Writer>(
549    sig: &Vec<EcdsaAdaptorSignature>,
550    writer: &mut W,
551) -> Result<(), ::lightning::io::Error> {
552    write_vec_cb(sig, writer, &write_ecdsa_adaptor_signature)
553}
554
555/// Reads a set of [`secp256k1_zkp::EcdsaAdaptorSignature`] from the given reader.
556pub fn read_ecdsa_adaptor_signatures<R: ::lightning::io::Read>(
557    reader: &mut R,
558) -> Result<Vec<EcdsaAdaptorSignature>, DecodeError> {
559    read_vec_cb(reader, &read_ecdsa_adaptor_signature)
560}
561
562/// Writes an `i32` value to the given writer.
563pub fn write_i32<W: Writer>(i: &i32, writer: &mut W) -> Result<(), ::lightning::io::Error> {
564    i.to_be_bytes().write(writer)
565}
566
567/// Reads an `i32` value from the given reader.
568pub fn read_i32<R: Read>(reader: &mut R) -> Result<i32, DecodeError> {
569    let v: [u8; 4] = Readable::read(reader)?;
570    Ok(i32::from_be_bytes(v))
571}
572/// Writes a `SignedAmount` value to the given writer.
573pub fn write_signed_amount<W: Writer>(
574    i: &SignedAmount,
575    writer: &mut W,
576) -> Result<(), ::lightning::io::Error> {
577    let i = i.to_sat().to_be_bytes();
578    for b in i {
579        b.write(writer)?;
580    }
581    Ok(())
582}
583
584/// Reads a `SignedAmount` value from the given reader.
585pub fn read_signed_amount<R: ::lightning::io::Read>(
586    reader: &mut R,
587) -> Result<SignedAmount, DecodeError> {
588    let mut v = [0u8; 8];
589    for x in &mut v {
590        *x = Readable::read(reader)?;
591    }
592    let signed_amount = i64::from_be_bytes(v);
593    Ok(SignedAmount::from_sat(signed_amount))
594}
595
596/// Writes a [`lightning::util::ser::Writeable`] value to the given writer as a TLV.
597pub fn write_as_tlv<T: Type + Writeable, W: Writer>(
598    e: &T,
599    writer: &mut W,
600) -> Result<(), ::lightning::io::Error> {
601    BigSize(e.type_id() as u64).write(writer)?;
602    BigSize(e.serialized_length() as u64).write(writer)?;
603    e.write(writer)
604}
605
606/// Read a [`lightning::util::ser::Writeable`] value from the given reader as a TLV.
607pub fn read_as_tlv<T: Type + Readable, R: Read>(reader: &mut R) -> Result<T, DecodeError> {
608    // TODO(tibo): consider checking type here.
609    // This retrieves type as BigSize. Will be u16 once specs are updated.
610    let _: BigSize = Readable::read(reader)?;
611    // This retrieves the length, will be removed once oracle specs are updated.
612    let _: BigSize = Readable::read(reader)?;
613    Readable::read(reader)
614}
615
616/// Writes a [`HashMap`].
617pub fn write_hash_map<W: Writer, T, V>(
618    input: &HashMap<T, V>,
619    writer: &mut W,
620) -> Result<(), lightning::io::Error>
621where
622    T: Writeable,
623    V: Writeable,
624{
625    (input.len() as u64).write(writer)?;
626
627    for (key, value) in input.iter() {
628        key.write(writer)?;
629        value.write(writer)?;
630    }
631
632    Ok(())
633}
634
635/// Reads a [`HashMap`].
636pub fn read_hash_map<R: Read, T, V>(reader: &mut R) -> Result<HashMap<T, V>, DecodeError>
637where
638    T: Readable + Hash + Eq,
639    V: Readable,
640{
641    let len: u64 = Readable::read(reader)?;
642    let mut map = HashMap::new();
643    for _ in 0..len {
644        let key: T = Readable::read(reader)?;
645        let value: V = Readable::read(reader)?;
646        map.insert(key, value);
647    }
648
649    Ok(map)
650}
651
652impl_dlc_writeable_external!(Payout, payout, { (offer, writeable), (accept, writeable) });
653impl_dlc_writeable_external!(EnumerationPayout, enum_payout, { (outcome, string), (payout, { cb_writeable, payout::write, payout::read} )});
654impl_dlc_writeable_external!(TxInputInfo, tx_input_info, { (outpoint, writeable), (max_witness_len, usize), (redeem_script, writeable), (serial_id, writeable)});
655impl_dlc_writeable_external!(DlcInputInfo, dlc_input_info, { (fund_tx, writeable), (fund_vout, writeable), (local_fund_pubkey, writeable), (remote_fund_pubkey, writeable), (fund_amount, writeable), (max_witness_len, usize), (input_serial_id, writeable), (contract_id, writeable)});
656impl_dlc_writeable_external!(PartyParams, party_params, {
657    (fund_pubkey, writeable),
658    (change_script_pubkey, writeable),
659    (change_serial_id, writeable),
660    (payout_script_pubkey, writeable),
661    (payout_serial_id, writeable),
662    (inputs, { vec_cb, tx_input_info::write, tx_input_info::read }),
663    (dlc_inputs, { vec_cb, dlc_input_info::write, dlc_input_info::read }),
664    (input_amount, writeable),
665    (collateral, writeable)
666});
667
668#[cfg(test)]
669mod tests {
670    use lightning::io::Cursor;
671
672    use super::{read_f64, write_f64};
673
674    #[test]
675    fn f64_serialize_round_trip() {
676        let original = 2.3;
677        let mut ser = Vec::new();
678        write_f64(original, &mut ser).unwrap();
679        let deser = read_f64(&mut Cursor::new(&ser)).unwrap();
680
681        assert_eq!(original, deser);
682    }
683}