mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-02-24 23:08:36 +01:00
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.
This commit is contained in:
parent
8829d1b80f
commit
bfd4ac4995
3 changed files with 172 additions and 16 deletions
|
@ -88,6 +88,57 @@ pub enum SpendableOutputDescriptor {
|
|||
}
|
||||
}
|
||||
|
||||
impl Writeable for SpendableOutputDescriptor {
|
||||
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
|
||||
match self {
|
||||
&SpendableOutputDescriptor::StaticOutput { ref outpoint, ref output } => {
|
||||
0u8.write(writer)?;
|
||||
outpoint.write(writer)?;
|
||||
output.write(writer)?;
|
||||
},
|
||||
&SpendableOutputDescriptor::DynamicOutputP2WSH { ref outpoint, ref key, ref witness_script, ref to_self_delay, ref output } => {
|
||||
1u8.write(writer)?;
|
||||
outpoint.write(writer)?;
|
||||
key.write(writer)?;
|
||||
witness_script.write(writer)?;
|
||||
to_self_delay.write(writer)?;
|
||||
output.write(writer)?;
|
||||
},
|
||||
&SpendableOutputDescriptor::DynamicOutputP2WPKH { ref outpoint, ref key, ref output } => {
|
||||
2u8.write(writer)?;
|
||||
outpoint.write(writer)?;
|
||||
key.write(writer)?;
|
||||
output.write(writer)?;
|
||||
},
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: ::std::io::Read> Readable<R> for SpendableOutputDescriptor {
|
||||
fn read(reader: &mut R) -> Result<Self, DecodeError> {
|
||||
match Readable::read(reader)? {
|
||||
0u8 => Ok(SpendableOutputDescriptor::StaticOutput {
|
||||
outpoint: Readable::read(reader)?,
|
||||
output: Readable::read(reader)?,
|
||||
}),
|
||||
1u8 => Ok(SpendableOutputDescriptor::DynamicOutputP2WSH {
|
||||
outpoint: Readable::read(reader)?,
|
||||
key: Readable::read(reader)?,
|
||||
witness_script: Readable::read(reader)?,
|
||||
to_self_delay: Readable::read(reader)?,
|
||||
output: Readable::read(reader)?,
|
||||
}),
|
||||
2u8 => Ok(SpendableOutputDescriptor::DynamicOutputP2WPKH {
|
||||
outpoint: Readable::read(reader)?,
|
||||
key: Readable::read(reader)?,
|
||||
output: Readable::read(reader)?,
|
||||
}),
|
||||
_ => Err(DecodeError::InvalidValue),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait to describe an object which can get user secrets and key material.
|
||||
pub trait KeysInterface: Send + Sync {
|
||||
/// A type which implements ChannelKeys which will be returned by get_channel_keys.
|
||||
|
|
|
@ -16,6 +16,7 @@ use ln::msgs;
|
|||
use ln::channelmanager::{PaymentPreimage, PaymentHash};
|
||||
use chain::transaction::OutPoint;
|
||||
use chain::keysinterface::SpendableOutputDescriptor;
|
||||
use util::ser::{Writeable, Writer, MaybeReadable, Readable};
|
||||
|
||||
use bitcoin::blockdata::script::Script;
|
||||
|
||||
|
@ -24,6 +25,10 @@ use secp256k1::key::PublicKey;
|
|||
use std::time::Duration;
|
||||
|
||||
/// An Event which you should probably take some action in response to.
|
||||
///
|
||||
/// Note that while Writeable and Readable are implemented for Event, you probably shouldn't use
|
||||
/// them directly as they don't round-trip exactly (for example FundingGenerationReady is never
|
||||
/// written as it makes no sense to respond to it after reconnecting to peers).
|
||||
pub enum Event {
|
||||
/// Used to indicate that the client should generate a funding transaction with the given
|
||||
/// parameters and then call ChannelManager::funding_transaction_generated.
|
||||
|
@ -108,6 +113,91 @@ pub enum Event {
|
|||
},
|
||||
}
|
||||
|
||||
impl Writeable for Event {
|
||||
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
|
||||
match self {
|
||||
&Event::FundingGenerationReady { .. } => {
|
||||
0u8.write(writer)?;
|
||||
// We never write out FundingGenerationReady events as, upon disconnection, peers
|
||||
// drop any channels which have not yet exchanged funding_signed.
|
||||
},
|
||||
&Event::FundingBroadcastSafe { ref funding_txo, ref user_channel_id } => {
|
||||
1u8.write(writer)?;
|
||||
funding_txo.write(writer)?;
|
||||
user_channel_id.write(writer)?;
|
||||
},
|
||||
&Event::PaymentReceived { ref payment_hash, ref amt } => {
|
||||
2u8.write(writer)?;
|
||||
payment_hash.write(writer)?;
|
||||
amt.write(writer)?;
|
||||
},
|
||||
&Event::PaymentSent { ref payment_preimage } => {
|
||||
3u8.write(writer)?;
|
||||
payment_preimage.write(writer)?;
|
||||
},
|
||||
&Event::PaymentFailed { ref payment_hash, ref rejected_by_dest,
|
||||
#[cfg(test)]
|
||||
ref error_code,
|
||||
} => {
|
||||
4u8.write(writer)?;
|
||||
payment_hash.write(writer)?;
|
||||
rejected_by_dest.write(writer)?;
|
||||
#[cfg(test)]
|
||||
error_code.write(writer)?;
|
||||
},
|
||||
&Event::PendingHTLCsForwardable { time_forwardable: _ } => {
|
||||
5u8.write(writer)?;
|
||||
// We don't write the time_fordwardable out at all, as we presume when the user
|
||||
// deserializes us at least that much time has elapsed.
|
||||
},
|
||||
&Event::SpendableOutputs { ref outputs } => {
|
||||
6u8.write(writer)?;
|
||||
(outputs.len() as u64).write(writer)?;
|
||||
for output in outputs.iter() {
|
||||
output.write(writer)?;
|
||||
}
|
||||
},
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl<R: ::std::io::Read> MaybeReadable<R> for Event {
|
||||
fn read(reader: &mut R) -> Result<Option<Self>, msgs::DecodeError> {
|
||||
match Readable::read(reader)? {
|
||||
0u8 => Ok(None),
|
||||
1u8 => Ok(Some(Event::FundingBroadcastSafe {
|
||||
funding_txo: Readable::read(reader)?,
|
||||
user_channel_id: Readable::read(reader)?,
|
||||
})),
|
||||
2u8 => Ok(Some(Event::PaymentReceived {
|
||||
payment_hash: Readable::read(reader)?,
|
||||
amt: Readable::read(reader)?,
|
||||
})),
|
||||
3u8 => Ok(Some(Event::PaymentSent {
|
||||
payment_preimage: Readable::read(reader)?,
|
||||
})),
|
||||
4u8 => Ok(Some(Event::PaymentFailed {
|
||||
payment_hash: Readable::read(reader)?,
|
||||
rejected_by_dest: Readable::read(reader)?,
|
||||
#[cfg(test)]
|
||||
error_code: Readable::read(reader)?,
|
||||
})),
|
||||
5u8 => Ok(Some(Event::PendingHTLCsForwardable {
|
||||
time_forwardable: Duration::from_secs(0)
|
||||
})),
|
||||
6u8 => {
|
||||
let outputs_len: u64 = Readable::read(reader)?;
|
||||
let mut outputs = Vec::new();
|
||||
for _ in 0..outputs_len {
|
||||
outputs.push(Readable::read(reader)?);
|
||||
}
|
||||
Ok(Some(Event::SpendableOutputs { outputs }))
|
||||
},
|
||||
_ => Err(msgs::DecodeError::InvalidValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An event generated by ChannelManager which indicates a message should be sent to a peer (or
|
||||
/// broadcast to most peers).
|
||||
/// These events are handled by PeerManager::process_events if you are using a PeerManager.
|
||||
|
|
|
@ -11,7 +11,7 @@ use std::cmp;
|
|||
use secp256k1::Signature;
|
||||
use secp256k1::key::{PublicKey, SecretKey};
|
||||
use bitcoin::blockdata::script::Script;
|
||||
use bitcoin::blockdata::transaction::{OutPoint, Transaction};
|
||||
use bitcoin::blockdata::transaction::{OutPoint, Transaction, TxOut};
|
||||
use bitcoin::consensus;
|
||||
use bitcoin::consensus::Encodable;
|
||||
use bitcoin_hashes::sha256d::Hash as Sha256dHash;
|
||||
|
@ -191,6 +191,15 @@ pub trait ReadableArgs<R, P>
|
|||
fn read(reader: &mut R, params: P) -> Result<Self, DecodeError>;
|
||||
}
|
||||
|
||||
/// A trait that various rust-lightning types implement allowing them to (maybe) be read in from a Read
|
||||
pub trait MaybeReadable<R>
|
||||
where Self: Sized,
|
||||
R: Read
|
||||
{
|
||||
/// Reads a Self in from the given Read
|
||||
fn read(reader: &mut R) -> Result<Option<Self>, DecodeError>;
|
||||
}
|
||||
|
||||
pub(crate) struct U48(pub u64);
|
||||
impl Writeable for U48 {
|
||||
#[inline]
|
||||
|
@ -627,26 +636,32 @@ impl<R: Read> Readable<R> for OutPoint {
|
|||
}
|
||||
}
|
||||
|
||||
impl Writeable for Transaction {
|
||||
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
|
||||
match self.consensus_encode(WriterWriteAdaptor(writer)) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(consensus::encode::Error::Io(e)) => Err(e),
|
||||
Err(_) => panic!("We shouldn't get a consensus::encode::Error unless our Write generated an std::io::Error"),
|
||||
macro_rules! impl_consensus_ser {
|
||||
($bitcoin_type: ty) => {
|
||||
impl Writeable for $bitcoin_type {
|
||||
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
|
||||
match self.consensus_encode(WriterWriteAdaptor(writer)) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(consensus::encode::Error::Io(e)) => Err(e),
|
||||
Err(_) => panic!("We shouldn't get a consensus::encode::Error unless our Write generated an std::io::Error"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Read> Readable<R> for Transaction {
|
||||
fn read(r: &mut R) -> Result<Self, DecodeError> {
|
||||
match consensus::encode::Decodable::consensus_decode(r) {
|
||||
Ok(t) => Ok(t),
|
||||
Err(consensus::encode::Error::Io(ref e)) if e.kind() == ::std::io::ErrorKind::UnexpectedEof => Err(DecodeError::ShortRead),
|
||||
Err(consensus::encode::Error::Io(e)) => Err(DecodeError::Io(e)),
|
||||
Err(_) => Err(DecodeError::InvalidValue),
|
||||
impl<R: Read> Readable<R> for $bitcoin_type {
|
||||
fn read(r: &mut R) -> Result<Self, DecodeError> {
|
||||
match consensus::encode::Decodable::consensus_decode(r) {
|
||||
Ok(t) => Ok(t),
|
||||
Err(consensus::encode::Error::Io(ref e)) if e.kind() == ::std::io::ErrorKind::UnexpectedEof => Err(DecodeError::ShortRead),
|
||||
Err(consensus::encode::Error::Io(e)) => Err(DecodeError::Io(e)),
|
||||
Err(_) => Err(DecodeError::InvalidValue),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl_consensus_ser!(Transaction);
|
||||
impl_consensus_ser!(TxOut);
|
||||
|
||||
impl<R: Read, T: Readable<R>> Readable<R> for Mutex<T> {
|
||||
fn read(r: &mut R) -> Result<Self, DecodeError> {
|
||||
|
|
Loading…
Add table
Reference in a new issue