Skip to content

Commit 77e1efd

Browse files
committed
Implement Readable/Writeable for Events
As noted in the docs, Events don't round-trip fully, but round-trip in a way that is useful for ChannelManagers, specifically some events don't make sense anymore after a restart.
1 parent 030c49c commit 77e1efd

File tree

3 files changed

+172
-16
lines changed

3 files changed

+172
-16
lines changed

lightning/src/chain/keysinterface.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,57 @@ pub enum SpendableOutputDescriptor {
8888
}
8989
}
9090

91+
impl Writeable for SpendableOutputDescriptor {
92+
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
93+
match self {
94+
&SpendableOutputDescriptor::StaticOutput { ref outpoint, ref output } => {
95+
0u8.write(writer)?;
96+
outpoint.write(writer)?;
97+
output.write(writer)?;
98+
},
99+
&SpendableOutputDescriptor::DynamicOutputP2WSH { ref outpoint, ref key, ref witness_script, ref to_self_delay, ref output } => {
100+
1u8.write(writer)?;
101+
outpoint.write(writer)?;
102+
key.write(writer)?;
103+
witness_script.write(writer)?;
104+
to_self_delay.write(writer)?;
105+
output.write(writer)?;
106+
},
107+
&SpendableOutputDescriptor::DynamicOutputP2WPKH { ref outpoint, ref key, ref output } => {
108+
2u8.write(writer)?;
109+
outpoint.write(writer)?;
110+
key.write(writer)?;
111+
output.write(writer)?;
112+
},
113+
}
114+
Ok(())
115+
}
116+
}
117+
118+
impl<R: ::std::io::Read> Readable<R> for SpendableOutputDescriptor {
119+
fn read(reader: &mut R) -> Result<Self, DecodeError> {
120+
match Readable::read(reader)? {
121+
0u8 => Ok(SpendableOutputDescriptor::StaticOutput {
122+
outpoint: Readable::read(reader)?,
123+
output: Readable::read(reader)?,
124+
}),
125+
1u8 => Ok(SpendableOutputDescriptor::DynamicOutputP2WSH {
126+
outpoint: Readable::read(reader)?,
127+
key: Readable::read(reader)?,
128+
witness_script: Readable::read(reader)?,
129+
to_self_delay: Readable::read(reader)?,
130+
output: Readable::read(reader)?,
131+
}),
132+
2u8 => Ok(SpendableOutputDescriptor::DynamicOutputP2WPKH {
133+
outpoint: Readable::read(reader)?,
134+
key: Readable::read(reader)?,
135+
output: Readable::read(reader)?,
136+
}),
137+
_ => Err(DecodeError::InvalidValue),
138+
}
139+
}
140+
}
141+
91142
/// A trait to describe an object which can get user secrets and key material.
92143
pub trait KeysInterface: Send + Sync {
93144
/// A type which implements ChannelKeys which will be returned by get_channel_keys.

lightning/src/util/events.rs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use ln::msgs;
1616
use ln::channelmanager::{PaymentPreimage, PaymentHash};
1717
use chain::transaction::OutPoint;
1818
use chain::keysinterface::SpendableOutputDescriptor;
19+
use util::ser::{Writeable, Writer, MaybeReadable, Readable};
1920

2021
use bitcoin::blockdata::script::Script;
2122

@@ -24,6 +25,10 @@ use secp256k1::key::PublicKey;
2425
use std::time::Duration;
2526

2627
/// An Event which you should probably take some action in response to.
28+
///
29+
/// Note that while Writeable and Readable are implemented for Event, you probably shouldn't use
30+
/// them directly as they don't round-trip exactly (for example FundingGenerationReady is never
31+
/// written as it makes no sense to respond to it after reconnecting to peers).
2732
pub enum Event {
2833
/// Used to indicate that the client should generate a funding transaction with the given
2934
/// parameters and then call ChannelManager::funding_transaction_generated.
@@ -108,6 +113,91 @@ pub enum Event {
108113
},
109114
}
110115

116+
impl Writeable for Event {
117+
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
118+
match self {
119+
&Event::FundingGenerationReady { .. } => {
120+
0u8.write(writer)?;
121+
// We never write out FundingGenerationReady events as, upon disconnection, peers
122+
// drop any channels which have not yet exchanged funding_signed.
123+
},
124+
&Event::FundingBroadcastSafe { ref funding_txo, ref user_channel_id } => {
125+
1u8.write(writer)?;
126+
funding_txo.write(writer)?;
127+
user_channel_id.write(writer)?;
128+
},
129+
&Event::PaymentReceived { ref payment_hash, ref amt } => {
130+
2u8.write(writer)?;
131+
payment_hash.write(writer)?;
132+
amt.write(writer)?;
133+
},
134+
&Event::PaymentSent { ref payment_preimage } => {
135+
3u8.write(writer)?;
136+
payment_preimage.write(writer)?;
137+
},
138+
&Event::PaymentFailed { ref payment_hash, ref rejected_by_dest,
139+
#[cfg(test)]
140+
ref error_code,
141+
} => {
142+
4u8.write(writer)?;
143+
payment_hash.write(writer)?;
144+
rejected_by_dest.write(writer)?;
145+
#[cfg(test)]
146+
error_code.write(writer)?;
147+
},
148+
&Event::PendingHTLCsForwardable { time_forwardable: _ } => {
149+
5u8.write(writer)?;
150+
// We don't write the time_fordwardable out at all, as we presume when the user
151+
// deserializes us at least that much time has elapsed.
152+
},
153+
&Event::SpendableOutputs { ref outputs } => {
154+
6u8.write(writer)?;
155+
(outputs.len() as u64).write(writer)?;
156+
for output in outputs.iter() {
157+
output.write(writer)?;
158+
}
159+
},
160+
}
161+
Ok(())
162+
}
163+
}
164+
impl<R: ::std::io::Read> MaybeReadable<R> for Event {
165+
fn read(reader: &mut R) -> Result<Option<Self>, msgs::DecodeError> {
166+
match Readable::read(reader)? {
167+
0u8 => Ok(None),
168+
1u8 => Ok(Some(Event::FundingBroadcastSafe {
169+
funding_txo: Readable::read(reader)?,
170+
user_channel_id: Readable::read(reader)?,
171+
})),
172+
2u8 => Ok(Some(Event::PaymentReceived {
173+
payment_hash: Readable::read(reader)?,
174+
amt: Readable::read(reader)?,
175+
})),
176+
3u8 => Ok(Some(Event::PaymentSent {
177+
payment_preimage: Readable::read(reader)?,
178+
})),
179+
4u8 => Ok(Some(Event::PaymentFailed {
180+
payment_hash: Readable::read(reader)?,
181+
rejected_by_dest: Readable::read(reader)?,
182+
#[cfg(test)]
183+
error_code: Readable::read(reader)?,
184+
})),
185+
5u8 => Ok(Some(Event::PendingHTLCsForwardable {
186+
time_forwardable: Duration::from_secs(0)
187+
})),
188+
6u8 => {
189+
let outputs_len: u64 = Readable::read(reader)?;
190+
let mut outputs = Vec::new();
191+
for _ in 0..outputs_len {
192+
outputs.push(Readable::read(reader)?);
193+
}
194+
Ok(Some(Event::SpendableOutputs { outputs }))
195+
},
196+
_ => Err(msgs::DecodeError::InvalidValue)
197+
}
198+
}
199+
}
200+
111201
/// An event generated by ChannelManager which indicates a message should be sent to a peer (or
112202
/// broadcast to most peers).
113203
/// These events are handled by PeerManager::process_events if you are using a PeerManager.

lightning/src/util/ser.rs

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use std::cmp;
1111
use secp256k1::Signature;
1212
use secp256k1::key::{PublicKey, SecretKey};
1313
use bitcoin::blockdata::script::Script;
14-
use bitcoin::blockdata::transaction::{OutPoint, Transaction};
14+
use bitcoin::blockdata::transaction::{OutPoint, Transaction, TxOut};
1515
use bitcoin::consensus;
1616
use bitcoin::consensus::Encodable;
1717
use bitcoin_hashes::sha256d::Hash as Sha256dHash;
@@ -191,6 +191,15 @@ pub trait ReadableArgs<R, P>
191191
fn read(reader: &mut R, params: P) -> Result<Self, DecodeError>;
192192
}
193193

194+
/// A trait that various rust-lightning types implement allowing them to (maybe) be read in from a Read
195+
pub trait MaybeReadable<R>
196+
where Self: Sized,
197+
R: Read
198+
{
199+
/// Reads a Self in from the given Read
200+
fn read(reader: &mut R) -> Result<Option<Self>, DecodeError>;
201+
}
202+
194203
pub(crate) struct U48(pub u64);
195204
impl Writeable for U48 {
196205
#[inline]
@@ -627,26 +636,32 @@ impl<R: Read> Readable<R> for OutPoint {
627636
}
628637
}
629638

630-
impl Writeable for Transaction {
631-
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
632-
match self.consensus_encode(WriterWriteAdaptor(writer)) {
633-
Ok(_) => Ok(()),
634-
Err(consensus::encode::Error::Io(e)) => Err(e),
635-
Err(_) => panic!("We shouldn't get a consensus::encode::Error unless our Write generated an std::io::Error"),
639+
macro_rules! impl_consensus_ser {
640+
($bitcoin_type: ty) => {
641+
impl Writeable for $bitcoin_type {
642+
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
643+
match self.consensus_encode(WriterWriteAdaptor(writer)) {
644+
Ok(_) => Ok(()),
645+
Err(consensus::encode::Error::Io(e)) => Err(e),
646+
Err(_) => panic!("We shouldn't get a consensus::encode::Error unless our Write generated an std::io::Error"),
647+
}
648+
}
636649
}
637-
}
638-
}
639650

640-
impl<R: Read> Readable<R> for Transaction {
641-
fn read(r: &mut R) -> Result<Self, DecodeError> {
642-
match consensus::encode::Decodable::consensus_decode(r) {
643-
Ok(t) => Ok(t),
644-
Err(consensus::encode::Error::Io(ref e)) if e.kind() == ::std::io::ErrorKind::UnexpectedEof => Err(DecodeError::ShortRead),
645-
Err(consensus::encode::Error::Io(e)) => Err(DecodeError::Io(e)),
646-
Err(_) => Err(DecodeError::InvalidValue),
651+
impl<R: Read> Readable<R> for $bitcoin_type {
652+
fn read(r: &mut R) -> Result<Self, DecodeError> {
653+
match consensus::encode::Decodable::consensus_decode(r) {
654+
Ok(t) => Ok(t),
655+
Err(consensus::encode::Error::Io(ref e)) if e.kind() == ::std::io::ErrorKind::UnexpectedEof => Err(DecodeError::ShortRead),
656+
Err(consensus::encode::Error::Io(e)) => Err(DecodeError::Io(e)),
657+
Err(_) => Err(DecodeError::InvalidValue),
658+
}
659+
}
647660
}
648661
}
649662
}
663+
impl_consensus_ser!(Transaction);
664+
impl_consensus_ser!(TxOut);
650665

651666
impl<R: Read, T: Readable<R>> Readable<R> for Mutex<T> {
652667
fn read(r: &mut R) -> Result<Self, DecodeError> {

0 commit comments

Comments
 (0)