diff --git a/lnwallet/reservation.go b/lnwallet/reservation.go index a08a41b0..8aef594c 100644 --- a/lnwallet/reservation.go +++ b/lnwallet/reservation.go @@ -6,16 +6,17 @@ import ( "github.com/lightningnetwork/lnd/channeldb" "github.com/roasbeef/btcd/btcec" + "github.com/roasbeef/btcd/chaincfg/chainhash" "github.com/roasbeef/btcd/wire" "github.com/roasbeef/btcutil" ) -// ChannelContribution is the primary constituent of the funding workflow within -// lnwallet. Each side first exchanges their respective contributions along with -// channel specific parameters like the min fee/KB. Once contributions have been -// exchanged, each side will then produce signatures for all their inputs to the -// funding transactions, and finally a signature for the other party's version -// of the commitment transaction. +// ChannelContribution is the primary constituent of the funding workflow +// within lnwallet. Each side first exchanges their respective contributions +// along with channel specific parameters like the min fee/KB. Once +// contributions have been exchanged, each side will then produce signatures +// for all their inputs to the funding transactions, and finally a signature +// for the other party's version of the commitment transaction. type ChannelContribution struct { // FundingOutpoint is the amount of funds contributed to the funding // transaction. @@ -29,31 +30,22 @@ type ChannelContribution struct { // channel capacity. ChangeOutputs []*wire.TxOut - // MultiSigKey is the the key to be used for the funding transaction's - // P2SH multi-sig 2-of-2 output. - // TODO(roasbeef): replace with CDP - MultiSigKey *btcec.PublicKey + // FirstCommitmentPoint is the first commitment point that will be used + // to create the revocation key in the first commitment transaction we + // send to the remote party. + FirstCommitmentPoint *btcec.PublicKey - // CommitKey is the key to be used for this party's version of the - // commitment transaction. - CommitKey *btcec.PublicKey + // ChannelConfig is the concrete contribution that this node is + // offering to the channel. This includes all the various constraints + // such as the min HTLC, and also all the keys which will be used for + // the duration of the channel. + *channeldb.ChannelConfig +} - // DeliveryAddress is the address to be used for delivery of cleared - // channel funds in the scenario of a cooperative channel closure. - DeliveryAddress btcutil.Address - - // RevocationKey is the key to be used in the revocation clause for the - // initial version of this party's commitment transaction. - RevocationKey *btcec.PublicKey - - // DustLimit is the threshold below which no HTLC output should be - // generated for this party. HTLCs below this amount are not - // enforceable on-chain from this party's point of view. - DustLimit btcutil.Amount - - // CsvDelay The delay (in blocks) to be used for the pay-to-self output - // in this party's version of the commitment transaction. - CsvDelay uint32 +// toChanConfig returns the raw channel configuration generated by a node's +// contribution to the channel. +func (c *ChannelContribution) toChanConfig() channeldb.ChannelConfig { + return *c.ChannelConfig } // InputScript represents any script inputs required to redeem a previous @@ -65,8 +57,8 @@ type InputScript struct { } // ChannelReservation represents an intent to open a lightning payment channel -// a counterparty. The funding processes from reservation to channel opening -// is a 3-step process. In order to allow for full concurrency during the +// a counterparty. The funding processes from reservation to channel opening is +// a 3-step process. In order to allow for full concurrency during the // reservation workflow, resources consumed by a contribution are "locked" // themselves. This prevents a number of race conditions such as two funding // transactions double-spending the same input. A reservation can also be @@ -122,10 +114,6 @@ type ChannelReservation struct { // throughout its lifetime. reservationID uint64 - // numConfsToOpen is the number of confirmations required before the - // channel should be considered open. - numConfsToOpen uint16 - // pushSat the amount of satoshis that should be pushed to the // responder of a single funding channel as part of the initial // commitment state. @@ -145,9 +133,9 @@ type ChannelReservation struct { // used only internally by lnwallet. In order to concurrent safety, the // creation of all channel reservations should be carried out via the // lnwallet.InitChannelReservation interface. -func NewChannelReservation(capacity, fundingAmt btcutil.Amount, - feePerKw btcutil.Amount, wallet *LightningWallet, id uint64, - numConfs uint16, pushSat btcutil.Amount) *ChannelReservation { +func NewChannelReservation(capacity, fundingAmt, feePerKw btcutil.Amount, + wallet *LightningWallet, id uint64, pushSat btcutil.Amount, + chainHash *chainhash.Hash) *ChannelReservation { var ( ourBalance btcutil.Amount @@ -206,38 +194,66 @@ func NewChannelReservation(capacity, fundingAmt btcutil.Amount, return &ChannelReservation{ ourContribution: &ChannelContribution{ FundingAmount: ourBalance, + ChannelConfig: &channeldb.ChannelConfig{}, }, theirContribution: &ChannelContribution{ FundingAmount: theirBalance, + ChannelConfig: &channeldb.ChannelConfig{}, }, partialState: &channeldb.OpenChannel{ - Capacity: capacity, - IsInitiator: initiator, - IsPending: true, - ChanType: chanType, - OurBalance: ourBalance, - TheirBalance: theirBalance, - FeePerKw: feePerKw, - Db: wallet.ChannelDB, - CommitFee: commitFee, + ChainHash: *chainHash, + Db: wallet.Cfg.Database, + Capacity: capacity, + IsInitiator: initiator, + IsPending: true, + ChanType: chanType, + LocalBalance: ourBalance, + RemoteBalance: theirBalance, + FeePerKw: feePerKw, + CommitFee: commitFee, }, - numConfsToOpen: numConfs, - pushSat: pushSat, - reservationID: id, - chanOpen: make(chan *openChanDetails, 1), - chanOpenErr: make(chan error, 1), - wallet: wallet, + pushSat: pushSat, + reservationID: id, + chanOpen: make(chan *openChanDetails, 1), + chanOpenErr: make(chan error, 1), + wallet: wallet, } } +// SetNumConfsRequired sets the number of confirmations that are required for +// the ultimate funding transaction before the channel can be considered open. +// This is distinct from the main reservation workflow as it allows +// implementations a bit more flexibility w.r.t to if the responder of the +// initiator sets decides the number of confirmations needed. +func (r *ChannelReservation) SetNumConfsRequired(numConfs uint16) { + r.Lock() + defer r.Unlock() + + r.partialState.NumConfsRequired = numConfs +} + +// RequireLocalDelay sets the mandatory CSV delay that MUST be used when +// creating the local commitment transaction. This is distinct from the normal +// reservation workflow as the remote party will dictate this value for us. +// +// TODO(roasbeef): abstract out dictation of params remote side gives +func (r *ChannelReservation) RequireLocalDelay(csvDelay uint16) { + r.Lock() + defer r.Unlock() + + r.ourContribution.ChannelConfig.CsvDelay = csvDelay +} + // OurContribution returns the wallet's fully populated contribution to the // pending payment channel. See 'ChannelContribution' for further details // regarding the contents of a contribution. +// // NOTE: This SHOULD NOT be modified. // TODO(roasbeef): make copy? func (r *ChannelReservation) OurContribution() *ChannelContribution { r.RLock() defer r.RUnlock() + return r.ourContribution } @@ -277,9 +293,10 @@ func (r *ChannelReservation) ProcessSingleContribution(theirContribution *Channe } // TheirContribution returns the counterparty's pending contribution to the -// payment channel. See 'ChannelContribution' for further details regarding -// the contents of a contribution. This attribute will ONLY be available -// after a call to .ProcesContribution(). +// payment channel. See 'ChannelContribution' for further details regarding the +// contents of a contribution. This attribute will ONLY be available after a +// call to .ProcesContribution(). +// // NOTE: This SHOULD NOT be modified. func (r *ChannelReservation) TheirContribution() *ChannelContribution { r.RLock() @@ -292,6 +309,7 @@ func (r *ChannelReservation) TheirContribution() *ChannelContribution { // version of the commitment transaction. The signatures for the wallet's // inputs to the funding transaction are returned in sorted order according to // BIP-69: https://github.com/bitcoin/bips/blob/master/bip-0069.mediawiki. +// // NOTE: These signatures will only be populated after a call to // .ProcesContribution() func (r *ChannelReservation) OurSignatures() ([]*InputScript, []byte) { @@ -300,18 +318,19 @@ func (r *ChannelReservation) OurSignatures() ([]*InputScript, []byte) { return r.ourFundingInputScripts, r.ourCommitmentSig } -// CompleteReservation finalizes the pending channel reservation, -// transitioning from a pending payment channel, to an open payment -// channel. All passed signatures to the counterparty's inputs to the funding -// transaction will be fully verified. Signatures are expected to be passed in -// sorted order according to BIP-69: -// https://github.com/bitcoin/bips/blob/master/bip-0069.mediawiki. Additionally, -// verification is performed in order to ensure that the counterparty supplied -// a valid signature to our version of the commitment transaction. -// Once this method returns, caller's should then call .WaitForChannelOpen() -// which will block until the funding transaction obtains the configured number -// of confirmations. Once the method unblocks, a LightningChannel instance is -// returned, marking the channel available for updates. +// CompleteReservation finalizes the pending channel reservation, transitioning +// from a pending payment channel, to an open payment channel. All passed +// signatures to the counterparty's inputs to the funding transaction will be +// fully verified. Signatures are expected to be passed in sorted order +// according to BIP-69: +// https://github.com/bitcoin/bips/blob/master/bip-0069.mediawiki. +// Additionally, verification is performed in order to ensure that the +// counterparty supplied a valid signature to our version of the commitment +// transaction. Once this method returns, caller's should then call +// .WaitForChannelOpen() which will block until the funding transaction obtains +// the configured number of confirmations. Once the method unblocks, a +// LightningChannel instance is returned, marking the channel available for +// updates. func (r *ChannelReservation) CompleteReservation(fundingInputScripts []*InputScript, commitmentSig []byte) (*channeldb.OpenChannel, error) { @@ -331,27 +350,24 @@ func (r *ChannelReservation) CompleteReservation(fundingInputScripts []*InputScr } // CompleteReservationSingle finalizes the pending single funder channel -// reservation. Using the funding outpoint of the constructed funding transaction, -// and the initiator's signature for our version of the commitment transaction, -// we are able to verify the correctness of our committment transaction as -// crafted by the initiator. Once this method returns, our signature for the -// initiator's version of the commitment transaction is available via -// the .OurSignatures() method. As this method should only be called as a -// response to a single funder channel, only a commitment signature will be -// populated. -func (r *ChannelReservation) CompleteReservationSingle( - revocationKey *btcec.PublicKey, fundingPoint *wire.OutPoint, - commitSig []byte, obsfucator [StateHintSize]byte) (*channeldb.OpenChannel, error) { +// reservation. Using the funding outpoint of the constructed funding +// transaction, and the initiator's signature for our version of the commitment +// transaction, we are able to verify the correctness of our commitment +// transaction as crafted by the initiator. Once this method returns, our +// signature for the initiator's version of the commitment transaction is +// available via the .OurSignatures() method. As this method should only be +// called as a response to a single funder channel, only a commitment signature +// will be populated. +func (r *ChannelReservation) CompleteReservationSingle(fundingPoint *wire.OutPoint, + commitSig []byte) (*channeldb.OpenChannel, error) { errChan := make(chan error, 1) completeChan := make(chan *channeldb.OpenChannel, 1) r.wallet.msgChan <- &addSingleFunderSigsMsg{ pendingFundingID: r.reservationID, - revokeKey: revocationKey, fundingOutpoint: fundingPoint, theirCommitmentSig: commitSig, - obsfucator: obsfucator, completeChan: completeChan, err: errChan, } @@ -363,6 +379,7 @@ func (r *ChannelReservation) CompleteReservationSingle( // funding transaction belonging to them, as well as their signature for the // wallet's version of the commitment transaction. This methods is provided for // additional verification, such as needed by tests. +// // NOTE: These attributes will be unpopulated before a call to // .CompleteReservation(). func (r *ChannelReservation) TheirSignatures() ([]*InputScript, []byte) { @@ -383,34 +400,6 @@ func (r *ChannelReservation) FinalFundingTx() *wire.MsgTx { return r.fundingTx } -// FundingRedeemScript returns the fully populated funding redeem script. -// -// NOTE: This method will only return a non-nil value after either -// ProcesContribution or ProcessSingleContribution have been executed and -// returned without error. -func (r *ChannelReservation) FundingRedeemScript() []byte { - r.RLock() - defer r.RUnlock() - return r.partialState.FundingWitnessScript -} - -// LocalCommitTx returns the commitment transaction for the local node involved -// in this funding reservation. -func (r *ChannelReservation) LocalCommitTx() *wire.MsgTx { - r.RLock() - defer r.RUnlock() - - return r.partialState.OurCommitTx -} - -// SetTheirDustLimit set dust limit of the remote party. -func (r *ChannelReservation) SetTheirDustLimit(dustLimit btcutil.Amount) { - r.Lock() - defer r.Unlock() - - r.partialState.TheirDustLimit = dustLimit -} - // FundingOutpoint returns the outpoint of the funding transaction. // // NOTE: The pointer returned will only be set once the .ProcesContribution() @@ -420,20 +409,7 @@ func (r *ChannelReservation) SetTheirDustLimit(dustLimit btcutil.Amount) { func (r *ChannelReservation) FundingOutpoint() *wire.OutPoint { r.RLock() defer r.RUnlock() - return r.partialState.FundingOutpoint -} - -// StateNumObfuscator returns the bytes to be used to obsfucate the state -// number hints for all future states of the commitment transaction for this -// workflow. -// -// NOTE: This value will only be available for a single funder workflow after -// the CompleteReservation or CompleteReservationSingle methods have been -// successfully executed. -func (r *ChannelReservation) StateNumObfuscator() [StateHintSize]byte { - r.RLock() - defer r.RUnlock() - return r.partialState.StateHintObsfucator + return &r.partialState.FundingOutpoint } // Cancel abandons this channel reservation. This method should be called in @@ -459,8 +435,8 @@ type OpenChannelDetails struct { // ChannelReservation and the required funding workflow. Channel *LightningChannel - // ConfirmationHeight is the block height within the chain that included - // the channel. + // ConfirmationHeight is the block height within the chain that + // included the channel. ConfirmationHeight uint32 // TransactionIndex is the index within the confirming block that the