Skip to main content

ddk_manager/contract/
ser.rs

1//! Serialization trait implementations for various data structures enabling them
2//! to be converted to byte arrays.
3
4use crate::contract::accepted_contract::AcceptedContract;
5use crate::contract::contract_info::ContractInfo;
6use crate::contract::enum_descriptor::EnumDescriptor;
7use crate::contract::numerical_descriptor::{DifferenceParams, NumericalDescriptor};
8use crate::contract::offered_contract::OfferedContract;
9use crate::contract::signed_contract::SignedContract;
10use crate::contract::AdaptorInfo;
11use crate::contract::{
12    ClosedContract, ContractDescriptor, FailedAcceptContract, FailedSignContract, PreClosedContract,
13};
14use crate::payout_curve::{
15    HyperbolaPayoutCurvePiece, PayoutFunction, PayoutFunctionPiece, PayoutPoint,
16    PolynomialPayoutCurvePiece, RoundingInterval, RoundingIntervals,
17};
18use crate::KeysId;
19use bitcoin::Amount;
20use ddk_dlc::DlcTransactions;
21use ddk_messages::impl_dlc_writeable;
22use ddk_messages::ser_impls::{
23    read_ecdsa_adaptor_signatures, read_option_cb, read_usize, read_vec, read_vec_cb,
24    write_ecdsa_adaptor_signatures, write_option_cb, write_usize, write_vec, write_vec_cb,
25};
26use ddk_trie::digit_trie::{DigitNodeData, DigitTrieDump};
27use ddk_trie::multi_oracle_trie::{MultiOracleTrie, MultiOracleTrieDump};
28use ddk_trie::multi_oracle_trie_with_diff::{MultiOracleTrieWithDiff, MultiOracleTrieWithDiffDump};
29use ddk_trie::multi_trie::{MultiTrieDump, MultiTrieNodeData, TrieNodeInfo};
30use ddk_trie::{OracleNumericInfo, RangeInfo};
31use lightning::io::Read;
32use lightning::ln::msgs::DecodeError;
33use lightning::util::ser::{Readable, Writeable, Writer};
34
35/// Trait used to de/serialize an object to/from a vector of bytes.
36pub trait Serializable
37where
38    Self: Sized,
39{
40    /// Serialize the object.
41    fn serialize(&self) -> Result<Vec<u8>, lightning::io::Error>;
42    /// Deserialize the object.
43    fn deserialize<R: Read>(reader: &mut R) -> Result<Self, DecodeError>;
44}
45
46impl<T> Serializable for T
47where
48    T: Writeable + Readable,
49{
50    fn serialize(&self) -> Result<Vec<u8>, lightning::io::Error> {
51        let mut buffer = Vec::new();
52        self.write(&mut buffer)?;
53        Ok(buffer)
54    }
55
56    fn deserialize<R: Read>(reader: &mut R) -> Result<Self, DecodeError> {
57        Readable::read(reader)
58    }
59}
60
61impl_dlc_writeable!(PayoutPoint, { (event_outcome, writeable), (outcome_payout, writeable), (extra_precision, writeable) });
62impl_dlc_writeable_enum!(
63    PayoutFunctionPiece,
64    (0, PolynomialPayoutCurvePiece),
65    (1, HyperbolaPayoutCurvePiece);;;
66);
67impl_dlc_writeable!(RoundingInterval, { (begin_interval, writeable), (rounding_mod, writeable) });
68impl_dlc_writeable!(PayoutFunction, { (payout_function_pieces, vec) });
69impl_dlc_writeable!(NumericalDescriptor, { (payout_function, writeable), (rounding_intervals, writeable), (difference_params, option), (oracle_numeric_infos, {cb_writeable, oracle_params::write, oracle_params::read}) });
70impl_dlc_writeable!(PolynomialPayoutCurvePiece, { (payout_points, vec) });
71impl_dlc_writeable!(RoundingIntervals, { (intervals, vec) });
72impl_dlc_writeable!(DifferenceParams, { (max_error_exp, usize), (min_support_exp, usize), (maximize_coverage, writeable) });
73impl_dlc_writeable!(HyperbolaPayoutCurvePiece, {
74    (left_end_point, writeable),
75    (right_end_point, writeable),
76    (use_positive_piece, writeable),
77    (translate_outcome, float),
78    (translate_payout, float),
79    (a, float),
80    (b, float),
81    (c, float),
82    (d, float)
83});
84impl_dlc_writeable_enum!(ContractDescriptor, (0, Enum), (1, Numerical);;;);
85impl_dlc_writeable!(ContractInfo, { (contract_descriptor, writeable), (oracle_announcements, vec), (threshold, usize)});
86impl_dlc_writeable!(EnumDescriptor, {
87    (
88        outcome_payouts,
89        {vec_cb, ddk_messages::ser_impls::enum_payout::write, ddk_messages::ser_impls::enum_payout::read}
90    )
91});
92impl Writeable for OfferedContract {
93    fn write<W: Writer>(&self, w: &mut W) -> Result<(), lightning::io::Error> {
94        self.id.write(w)?;
95        self.is_offer_party.write(w)?;
96        write_vec(&self.contract_info, w)?;
97        ddk_messages::ser_impls::party_params::write(&self.offer_params, w)?;
98        self.total_collateral.write(w)?;
99        write_vec(&self.funding_inputs, w)?;
100        self.fund_output_serial_id.write(w)?;
101        self.fee_rate_per_vb.write(w)?;
102        self.cet_locktime.write(w)?;
103        self.refund_locktime.write(w)?;
104        self.contract_flags.write(w)?;
105        self.counter_party.write(w)?;
106        self.keys_id.write(w)?;
107        Ok(())
108    }
109}
110
111impl Readable for OfferedContract {
112    fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
113        let id: [u8; 32] = Readable::read(r)?;
114        let is_offer_party: bool = Readable::read(r)?;
115        let contract_info = read_vec(r)?;
116        let offer_params = ddk_messages::ser_impls::party_params::read(r)?;
117        let total_collateral: Amount = Readable::read(r)?;
118        let funding_inputs = read_vec(r)?;
119        let fund_output_serial_id: u64 = Readable::read(r)?;
120        let fee_rate_per_vb: u64 = Readable::read(r)?;
121        let cet_locktime: u32 = Readable::read(r)?;
122        let refund_locktime: u32 = Readable::read(r)?;
123
124        // Backward compatibility: contract_flags (u8) was inserted between
125        // refund_locktime and counter_party. Peek one byte: 0x02/0x03 means
126        // old format (compressed pubkey prefix), 0x00/0x01 means new format
127        // (contract_flags value).
128        let mut peek = [0u8; 1];
129        r.read_exact(&mut peek)?;
130        let (contract_flags, counter_party) = if peek[0] == 0x02 || peek[0] == 0x03 {
131            // Old format: this byte is the start of counter_party pubkey
132            let mut pubkey_bytes = [0u8; 33];
133            pubkey_bytes[0] = peek[0];
134            r.read_exact(&mut pubkey_bytes[1..])?;
135            let pk = secp256k1_zkp::PublicKey::from_slice(&pubkey_bytes)
136                .map_err(|_| DecodeError::InvalidValue)?;
137            (0u8, pk)
138        } else {
139            // New format: this byte is contract_flags
140            let counter_party: secp256k1_zkp::PublicKey = Readable::read(r)?;
141            (peek[0], counter_party)
142        };
143
144        let keys_id: KeysId = Readable::read(r)?;
145
146        Ok(Self {
147            id,
148            is_offer_party,
149            contract_info,
150            offer_params,
151            total_collateral,
152            funding_inputs,
153            fund_output_serial_id,
154            fee_rate_per_vb,
155            cet_locktime,
156            refund_locktime,
157            contract_flags,
158            counter_party,
159            keys_id,
160        })
161    }
162}
163impl_dlc_writeable_external!(RangeInfo, range_info, { (cet_index, usize), (adaptor_index, usize)});
164impl_dlc_writeable_enum!(AdaptorInfo,;; (0, Numerical, write_multi_oracle_trie, read_multi_oracle_trie), (1, NumericalWithDifference, write_multi_oracle_trie_with_diff, read_multi_oracle_trie_with_diff); (2, Enum));
165impl_dlc_writeable_external!(
166    DlcTransactions, dlc_transactions,
167    { (fund, writeable),
168    (cets, vec),
169    (refund, writeable),
170    (funding_script_pubkey, writeable),
171    (pending_close_txs, vec)}
172);
173impl_dlc_writeable!(AcceptedContract, {
174    (offered_contract, writeable),
175    (accept_params, { cb_writeable, ddk_messages::ser_impls::party_params::write, ddk_messages::ser_impls::party_params::read }),
176    (funding_inputs, vec),
177    (adaptor_infos, vec),
178    (adaptor_signatures, { cb_writeable, write_ecdsa_adaptor_signatures, read_ecdsa_adaptor_signatures }),
179    (accept_refund_signature, writeable),
180    (dlc_transactions, {cb_writeable, dlc_transactions::write, dlc_transactions::read })
181});
182impl_dlc_writeable!(SignedContract, {
183    (accepted_contract, writeable),
184    (adaptor_signatures, { cb_writeable, write_ecdsa_adaptor_signatures, read_ecdsa_adaptor_signatures }),
185    (offer_refund_signature, writeable),
186    (funding_signatures, writeable),
187    (channel_id, option)
188});
189impl_dlc_writeable!(PreClosedContract, {
190    (signed_contract, writeable),
191    (attestations, {option_cb, write_vec, read_vec}),
192    (signed_cet, writeable)
193});
194impl_dlc_writeable!(ClosedContract, {
195    (attestations, {option_cb, write_vec, read_vec}),
196    (signed_cet, writeable),
197    (contract_id, writeable),
198    (temporary_contract_id, writeable),
199    (counter_party_id, writeable),
200    (funding_txid, writeable),
201    (pnl, SignedAmount),
202    (signed_contract, writeable)
203});
204impl_dlc_writeable!(FailedAcceptContract, {(offered_contract, writeable), (accept_message, writeable), (error_message, string)});
205impl_dlc_writeable!(FailedSignContract, {(accepted_contract, writeable), (sign_message, writeable), (error_message, string)});
206
207impl_dlc_writeable_external!(DigitTrieDump<Vec<RangeInfo> >, digit_trie_dump_vec_range, { (node_data, {vec_cb, write_digit_node_data_vec_range, read_digit_node_data_vec_range}), (root, {option_cb, write_usize, read_usize}), (base, usize)});
208impl_dlc_writeable_external!(DigitTrieDump<RangeInfo>, digit_trie_dump_range, { (node_data, {vec_cb, write_digit_node_data_range, read_digit_node_data_range}), (root, {option_cb, write_usize, read_usize}), (base, usize)});
209impl_dlc_writeable_external!(DigitTrieDump<Vec<TrieNodeInfo> >, digit_trie_dump_trie, { (node_data, {vec_cb, write_digit_node_data_trie, read_digit_node_data_trie}), (root, {option_cb, write_usize, read_usize}), (base, usize)});
210impl_dlc_writeable_external!(MultiOracleTrieDump, multi_oracle_trie_dump, { (digit_trie_dump, {cb_writeable, digit_trie_dump_vec_range::write, digit_trie_dump_vec_range::read}), (threshold, usize), (oracle_numeric_infos, {cb_writeable, oracle_params::write, oracle_params::read}), (extra_cover_trie_dump, {option_cb, multi_trie_dump::write, multi_trie_dump::read}) });
211impl_dlc_writeable_external!(OracleNumericInfo, oracle_params, { (base, usize), (nb_digits, {vec_cb, write_usize, read_usize}) });
212impl_dlc_writeable_external_enum!(
213    MultiTrieNodeData<RangeInfo>,
214    multi_trie_node_data,
215    (0, Leaf, digit_trie_dump_range),
216    (1, Node, digit_trie_dump_trie)
217);
218impl_dlc_writeable_external!(MultiTrieDump<RangeInfo>, multi_trie_dump, { (node_data, {vec_cb, multi_trie_node_data::write, multi_trie_node_data::read}), (nb_tries, usize), (nb_required, usize), (min_support_exp, usize), (max_error_exp, usize), (maximize_coverage, writeable), (oracle_numeric_infos, {cb_writeable, oracle_params::write, oracle_params::read}) });
219impl_dlc_writeable_external!(MultiOracleTrieWithDiffDump, multi_oracle_trie_with_diff_dump, { (multi_trie_dump, {cb_writeable, multi_trie_dump::write, multi_trie_dump::read}), (oracle_numeric_infos, {cb_writeable, oracle_params::write, oracle_params::read}) });
220impl_dlc_writeable_external!(TrieNodeInfo, trie_node_info, { (trie_index, usize), (store_index, usize) });
221
222fn write_digit_node_data_trie<W: Writer>(
223    input: &DigitNodeData<Vec<TrieNodeInfo>>,
224    writer: &mut W,
225) -> Result<(), lightning::io::Error> {
226    let cb = |x: &Vec<TrieNodeInfo>, writer: &mut W| -> Result<(), lightning::io::Error> {
227        write_vec_cb(x, writer, &trie_node_info::write)
228    };
229    write_digit_node_data(input, writer, &cb)
230}
231
232fn read_digit_node_data_trie<R: Read>(
233    reader: &mut R,
234) -> Result<DigitNodeData<Vec<TrieNodeInfo>>, DecodeError> {
235    let cb = |reader: &mut R| -> Result<Vec<TrieNodeInfo>, DecodeError> {
236        read_vec_cb(reader, &trie_node_info::read)
237    };
238    read_digit_node_data(reader, &cb)
239}
240
241fn write_digit_node_data_range<W: Writer>(
242    input: &DigitNodeData<RangeInfo>,
243    writer: &mut W,
244) -> Result<(), lightning::io::Error> {
245    write_digit_node_data(input, writer, &range_info::write)
246}
247
248fn read_digit_node_data_range<R: Read>(
249    reader: &mut R,
250) -> Result<DigitNodeData<RangeInfo>, DecodeError> {
251    read_digit_node_data(reader, &range_info::read)
252}
253
254fn write_digit_node_data_vec_range<W: Writer>(
255    input: &DigitNodeData<Vec<RangeInfo>>,
256    writer: &mut W,
257) -> Result<(), lightning::io::Error> {
258    let cb = |x: &Vec<RangeInfo>, writer: &mut W| -> Result<(), lightning::io::Error> {
259        write_vec_cb(x, writer, &range_info::write)
260    };
261    write_digit_node_data(input, writer, &cb)
262}
263
264fn read_digit_node_data_vec_range<R: Read>(
265    reader: &mut R,
266) -> Result<DigitNodeData<Vec<RangeInfo>>, DecodeError> {
267    let cb = |reader: &mut R| -> Result<Vec<RangeInfo>, DecodeError> {
268        read_vec_cb(reader, &range_info::read)
269    };
270    read_digit_node_data(reader, &cb)
271}
272
273fn write_digit_node_data<W: Writer, T, F>(
274    input: &DigitNodeData<T>,
275    writer: &mut W,
276    cb: &F,
277) -> Result<(), lightning::io::Error>
278where
279    F: Fn(&T, &mut W) -> Result<(), lightning::io::Error>,
280{
281    write_option_cb(&input.data, writer, &cb)?;
282    write_vec_cb(&input.prefix, writer, &write_usize)?;
283    let cb = |x: &Vec<Option<usize>>, writer: &mut W| -> Result<(), lightning::io::Error> {
284        let cb = |y: &Option<usize>, writer: &mut W| -> Result<(), lightning::io::Error> {
285            write_option_cb(y, writer, &write_usize)
286        };
287        write_vec_cb(x, writer, &cb)
288    };
289    write_option_cb(&input.children, writer, &cb)
290}
291
292fn read_digit_node_data<R: Read, T, F>(
293    reader: &mut R,
294    cb: &F,
295) -> Result<DigitNodeData<T>, DecodeError>
296where
297    F: Fn(&mut R) -> Result<T, DecodeError>,
298{
299    let cb1 = |reader: &mut R| -> Result<T, DecodeError> { cb(reader) };
300    let cb = |reader: &mut R| -> Result<Vec<Option<usize>>, DecodeError> {
301        let cb = |reader: &mut R| -> Result<Option<usize>, DecodeError> {
302            read_option_cb(reader, &read_usize)
303        };
304        read_vec_cb(reader, &cb)
305    };
306
307    Ok(DigitNodeData {
308        data: read_option_cb(reader, &cb1)?,
309        prefix: read_vec_cb(reader, &read_usize)?,
310        children: read_option_cb(reader, &cb)?,
311    })
312}
313
314fn write_multi_oracle_trie<W: Writer>(
315    trie: &MultiOracleTrie,
316    w: &mut W,
317) -> Result<(), lightning::io::Error> {
318    multi_oracle_trie_dump::write(&trie.dump(), w)
319}
320
321fn read_multi_oracle_trie<R: Read>(reader: &mut R) -> Result<MultiOracleTrie, DecodeError> {
322    let dump = multi_oracle_trie_dump::read(reader)?;
323    Ok(MultiOracleTrie::from_dump(dump))
324}
325
326fn write_multi_oracle_trie_with_diff<W: Writer>(
327    trie: &MultiOracleTrieWithDiff,
328    w: &mut W,
329) -> Result<(), lightning::io::Error> {
330    multi_oracle_trie_with_diff_dump::write(&trie.dump(), w)
331}
332
333fn read_multi_oracle_trie_with_diff<R: Read>(
334    reader: &mut R,
335) -> Result<MultiOracleTrieWithDiff, DecodeError> {
336    let dump = multi_oracle_trie_with_diff_dump::read(reader)?;
337    Ok(MultiOracleTrieWithDiff::from_dump(dump))
338}