-
Notifications
You must be signed in to change notification settings - Fork 411
Add Shared Input support in interactive TX construction #3842
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
👋 Thanks for assigning @dunxen as a reviewer! |
prevtx_out, | ||
sequence, | ||
}, { | ||
(0, shared_input_txid, option), // `funding_txid` | ||
(0, prevtx, option), | ||
(1, shared_input_txid, option), // `funding_txid` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is actually TLV 0
, and there's no TLV for prevtx
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like we'll need to unroll the serialization macro. We need to read prevtx_len
and only if it's 0, do we need to read the shared_input_txid
TLV.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I need help with that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something like this:
diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs
index 76db8e67a..6f43ca8c1 100644
--- a/lightning/src/ln/msgs.rs
+++ b/lightning/src/ln/msgs.rs
@@ -29,7 +29,7 @@ use bitcoin::hash_types::Txid;
use bitcoin::script::ScriptBuf;
use bitcoin::secp256k1::ecdsa::Signature;
use bitcoin::secp256k1::PublicKey;
-use bitcoin::{secp256k1, Witness};
+use bitcoin::{secp256k1, Transaction, Witness};
use crate::blinded_path::payment::{
BlindedPaymentTlvs, ForwardTlvs, ReceiveTlvs, UnauthenticatedReceiveTlvs,
@@ -2668,15 +2668,59 @@ impl_writeable_msg!(SpliceLocked, {
splice_txid,
}, {});
-impl_writeable_msg!(TxAddInput, {
- channel_id,
- serial_id,
- prevtx_out,
- sequence,
-}, {
- (0, prevtx, option),
- (1, shared_input_txid, option), // `funding_txid`
-});
+impl Writeable for TxAddInput {
+ fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
+ self.channel_id.write(w)?;
+ self.serial_id.write(w)?;
+ if let Some(prevtx) = self.prevtx.as_ref() {
+ debug_assert!(self.shared_input_txid.is_none());
+ prevtx.write(w)?;
+ } else {
+ debug_assert!(self.shared_input_txid.is_some());
+ 0u16.write(w)?;
+ }
+ self.prevtx_out.write(w)?;
+ self.sequence.write(w)?;
+
+ if let Some(shared_input_txid) = self.shared_input_txid.as_ref() {
+ encode_tlv_stream!(w, { (0, shared_input_txid, required) });
+ } else {
+ encode_tlv_stream!(w, {});
+ }
+
+ Ok(())
+ }
+}
+impl LengthReadable for TxAddInput {
+ fn read_from_fixed_length_buffer<R: LengthLimitedRead>(r: &mut R) -> Result<Self, DecodeError> {
+ let channel_id = Readable::read(r)?;
+ let serial_id = Readable::read(r)?;
+ let prevtx_len = <u16 as Readable>::read(r)?;
+ let mut prevtx = None;
+ if prevtx_len > 0 {
+ let mut tx_reader = FixedLengthReader::new(r, prevtx_len as u64);
+ let tx: Transaction = Readable::read(&mut tx_reader)?;
+ if tx_reader.bytes_remain() {
+ return Err(DecodeError::BadLengthDescriptor);
+ }
+ prevtx =
+ Some(TransactionU16LenLimited::new(tx).map_err(|_| DecodeError::InvalidValue)?);
+ }
+ let prevtx_out = Readable::read(r)?;
+ let sequence = Readable::read(r)?;
+
+ let mut shared_input_txid = None;
+ if prevtx_len > 0 {
+ decode_tlv_stream!(r, {});
+ } else {
+ decode_tlv_stream!(r, {
+ (0, shared_input_txid, required),
+ });
+ }
+
+ Ok(Self { channel_id, serial_id, prevtx, prevtx_out, sequence, shared_input_txid })
+ }
+}
impl_writeable_msg!(TxAddOutput, {
channel_id,
/// malleable. | ||
pub prevtx: TransactionU16LenLimited, | ||
/// malleable. Omitted for shared input. | ||
pub prevtx: Option<TransactionU16LenLimited>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could make this an enum along with shared_input_txid
, but I'm not sure what's a good name to call it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably not a good suggestion, but how about just TxInputOrigin
with Txid
and PrevTx
variants?
@@ -551,6 +570,27 @@ impl NegotiationContext { | |||
Ok(shared_output) | |||
} | |||
|
|||
fn set_actual_funding_input(&mut self, txin: TxIn) -> Result<SharedOwnedInput, AbortReason> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need to do any of this, can't we rely on prevtx_outpoints
to know if it was already added?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know how can we know whether an OutPoint in prevtx_outpoints
is shared or not?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need to care if it is shared or not, just that it hasn't been added twice
@@ -890,6 +990,10 @@ impl NegotiationContext { | |||
return Err(AbortReason::MissingFundingOutput); | |||
} | |||
|
|||
if self.expected_shared_funding_input.is_some() && self.actual_funding_input.is_none() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, use prevtx_outpoints
to see if the input was added
} = args; | ||
|
||
// Sanity check: There can be at most one shared input, local-added or remote-added |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not convinced we need this NegotiationInput
abstraction, it seems to complicate things a good bit. Can we just keep inputs_to_contribute
as we had it, and use expected_shared_funding_input
along with is_initiator
to know if we have to add it in maybe_send_message
? Seems like the same could be done for expected_shared_funding_output
, I'm not sure why the OutputOwned
abstraction is needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, I guess we do need it, but I managed to clean up how the shared funding output works and think we could do something similar for the shared funding input.
Here's a diff of the changes I made that can be applied to main
(it doesn't fix tests): https://gist.github.com/wpaulino/d8e6282ecd63b250a6cc5820b25c7ca7
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably this could be simplified, after some considerations your diff looks right, but I need to try it with the tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've hacked the tests to work with your change, and they are generally OK.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In your change, the semantics for the shared_funding_output
is:
- if we are the initiator, we want this funding output, and we will add it as an output in the negotiation
- if we are the acceptor, we want this funding output, and we expect the initiator to add it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are a few cases which will not be possible to express with this change:
- adding multiple shared outputs
- acceptor adding a shared output.
As these are invalid combinations, it is fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, can you push those changes here then and rework the shared funding input work to follow a similar approach?
In interactive TX construction, add support for shared input:
Additionally, the
prevtx
field of theTxAddInput
message is changed to Optional, as it should not be set for the shared input (it cannot, as the full funding transaction is not stored on the acceptor side) (spec discussion: lightning/bolts#1160 (comment))To be used by splicing, see #3736 .
Note: this PR does not include splicing negotiation.