Merge pull request #4757 from Crypt-iQ/fmgr_1109

funding: move Manager to own package
This commit is contained in:
Eugene 2020-12-17 11:43:12 -05:00 committed by GitHub
commit e0439965bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 653 additions and 657 deletions

@ -27,6 +27,7 @@ import (
"github.com/lightningnetwork/lnd/chanbackup" "github.com/lightningnetwork/lnd/chanbackup"
"github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/discovery" "github.com/lightningnetwork/lnd/discovery"
"github.com/lightningnetwork/lnd/funding"
"github.com/lightningnetwork/lnd/htlcswitch" "github.com/lightningnetwork/lnd/htlcswitch"
"github.com/lightningnetwork/lnd/htlcswitch/hodl" "github.com/lightningnetwork/lnd/htlcswitch/hodl"
"github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/input"
@ -413,7 +414,7 @@ func DefaultConfig() Config {
Autopilot: &lncfg.AutoPilot{ Autopilot: &lncfg.AutoPilot{
MaxChannels: 5, MaxChannels: 5,
Allocation: 0.6, Allocation: 0.6,
MinChannelSize: int64(minChanFundingSize), MinChannelSize: int64(funding.MinChanFundingSize),
MaxChannelSize: int64(MaxFundingAmount), MaxChannelSize: int64(MaxFundingAmount),
MinConfs: 1, MinConfs: 1,
ConfTarget: autopilot.DefaultConfTarget, ConfTarget: autopilot.DefaultConfTarget,
@ -429,7 +430,7 @@ func DefaultConfig() Config {
HeightHintCacheQueryDisable: defaultHeightHintCacheQueryDisable, HeightHintCacheQueryDisable: defaultHeightHintCacheQueryDisable,
Alias: defaultAlias, Alias: defaultAlias,
Color: defaultColor, Color: defaultColor,
MinChanSize: int64(minChanFundingSize), MinChanSize: int64(funding.MinChanFundingSize),
MaxChanSize: int64(0), MaxChanSize: int64(0),
DefaultRemoteMaxHtlcs: defaultRemoteMaxHtlcs, DefaultRemoteMaxHtlcs: defaultRemoteMaxHtlcs,
NumGraphSyncPeers: defaultMinPeers, NumGraphSyncPeers: defaultMinPeers,
@ -689,8 +690,8 @@ func ValidateConfig(cfg Config, usageMessage string) (*Config, error) {
// Ensure that the specified values for the min and max channel size // Ensure that the specified values for the min and max channel size
// are within the bounds of the normal chan size constraints. // are within the bounds of the normal chan size constraints.
if cfg.Autopilot.MinChannelSize < int64(minChanFundingSize) { if cfg.Autopilot.MinChannelSize < int64(funding.MinChanFundingSize) {
cfg.Autopilot.MinChannelSize = int64(minChanFundingSize) cfg.Autopilot.MinChannelSize = int64(funding.MinChanFundingSize)
} }
if cfg.Autopilot.MaxChannelSize > int64(MaxFundingAmount) { if cfg.Autopilot.MaxChannelSize > int64(MaxFundingAmount) {
cfg.Autopilot.MaxChannelSize = int64(MaxFundingAmount) cfg.Autopilot.MaxChannelSize = int64(MaxFundingAmount)
@ -707,9 +708,9 @@ func ValidateConfig(cfg Config, usageMessage string) (*Config, error) {
// If unset (marked by 0 value), then enforce proper default. // If unset (marked by 0 value), then enforce proper default.
if cfg.MaxChanSize == 0 { if cfg.MaxChanSize == 0 {
if cfg.ProtocolOptions.Wumbo() { if cfg.ProtocolOptions.Wumbo() {
cfg.MaxChanSize = int64(MaxBtcFundingAmountWumbo) cfg.MaxChanSize = int64(funding.MaxBtcFundingAmountWumbo)
} else { } else {
cfg.MaxChanSize = int64(MaxBtcFundingAmount) cfg.MaxChanSize = int64(funding.MaxBtcFundingAmount)
} }
} }
@ -857,7 +858,7 @@ func ValidateConfig(cfg Config, usageMessage string) (*Config, error) {
"litecoin.active must be set to 1 (true)", funcName) "litecoin.active must be set to 1 (true)", funcName)
case cfg.Litecoin.Active: case cfg.Litecoin.Active:
err := cfg.Litecoin.Validate(minTimeLockDelta, minLtcRemoteDelay) err := cfg.Litecoin.Validate(minTimeLockDelta, funding.MinLtcRemoteDelay)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -941,7 +942,7 @@ func ValidateConfig(cfg Config, usageMessage string) (*Config, error) {
// Finally we'll register the litecoin chain as our current // Finally we'll register the litecoin chain as our current
// primary chain. // primary chain.
cfg.registeredChains.RegisterPrimaryChain(chainreg.LitecoinChain) cfg.registeredChains.RegisterPrimaryChain(chainreg.LitecoinChain)
MaxFundingAmount = maxLtcFundingAmount MaxFundingAmount = funding.MaxLtcFundingAmount
case cfg.Bitcoin.Active: case cfg.Bitcoin.Active:
// Multiple networks can't be selected simultaneously. Count // Multiple networks can't be selected simultaneously. Count
@ -982,7 +983,7 @@ func ValidateConfig(cfg Config, usageMessage string) (*Config, error) {
return nil, err return nil, err
} }
err := cfg.Bitcoin.Validate(minTimeLockDelta, minBtcRemoteDelay) err := cfg.Bitcoin.Validate(minTimeLockDelta, funding.MinBtcRemoteDelay)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1060,8 +1061,8 @@ func ValidateConfig(cfg Config, usageMessage string) (*Config, error) {
// Ensure that the specified values for the min and max channel size // Ensure that the specified values for the min and max channel size
// don't are within the bounds of the normal chan size constraints. // don't are within the bounds of the normal chan size constraints.
if cfg.Autopilot.MinChannelSize < int64(minChanFundingSize) { if cfg.Autopilot.MinChannelSize < int64(funding.MinChanFundingSize) {
cfg.Autopilot.MinChannelSize = int64(minChanFundingSize) cfg.Autopilot.MinChannelSize = int64(funding.MinChanFundingSize)
} }
if cfg.Autopilot.MaxChannelSize > int64(MaxFundingAmount) { if cfg.Autopilot.MaxChannelSize > int64(MaxFundingAmount) {
cfg.Autopilot.MaxChannelSize = int64(MaxFundingAmount) cfg.Autopilot.MaxChannelSize = int64(MaxFundingAmount)

@ -1,20 +1,21 @@
package fmgr package funding
import ( import (
"github.com/lightningnetwork/lnd/lnpeer" "github.com/lightningnetwork/lnd/lnpeer"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
) )
// Manager is an interface that describes the basic operation of a funding // Controller is an interface with basic funding flow functions.
// manager. It should at a minimum process a subset of lnwire messages that // It describes the basic functionality of a funding manager.
// It should at a minimum process a subset of lnwire messages that
// are denoted as funding messages. // are denoted as funding messages.
type Manager interface { type Controller interface {
// ProcessFundingMsg processes a funding message represented by the // ProcessFundingMsg processes a funding message represented by the
// lnwire.Message parameter along with the Peer object representing a // lnwire.Message parameter along with the Peer object representing a
// connection to the counterparty. // connection to the counterparty.
ProcessFundingMsg(lnwire.Message, lnpeer.Peer) ProcessFundingMsg(lnwire.Message, lnpeer.Peer)
// IsPendingChannel is used to determine whether to send an Error message // IsPendingChannel returns whether a particular 32-byte identifier
// to the funding manager or not. // represents a pending channel in the Controller implementation.
IsPendingChannel([32]byte, lnpeer.Peer) bool IsPendingChannel([32]byte, lnpeer.Peer) bool
} }

27
funding/log.go Normal file

@ -0,0 +1,27 @@
package funding
import (
"github.com/btcsuite/btclog"
"github.com/lightningnetwork/lnd/build"
)
// Subsystem defines the logging code for this subsystem.
const Subsystem = "FNDG"
// log is a logger that is initialized with the btclog.Disabled logger.
var log btclog.Logger
// The default amount of logging is none.
func init() {
UseLogger(build.NewSubLogger(Subsystem, nil))
}
// DisableLog disables all logging output.
func DisableLog() {
UseLogger(btclog.Disabled)
}
// UseLogger uses a specified Logger to output package logging info.
func UseLogger(logger btclog.Logger) {
log = logger
}

@ -1,9 +1,10 @@
package lnd package funding
import ( import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"io"
"sync" "sync"
"time" "time"
@ -34,32 +35,46 @@ import (
"golang.org/x/crypto/salsa20" "golang.org/x/crypto/salsa20"
) )
var (
// byteOrder defines the endian-ness we use for encoding to and from
// buffers.
byteOrder = binary.BigEndian
)
// WriteOutpoint writes an outpoint to an io.Writer. This is not the same as
// the channeldb variant as this uses WriteVarBytes for the Hash.
func WriteOutpoint(w io.Writer, o *wire.OutPoint) error {
scratch := make([]byte, 4)
if err := wire.WriteVarBytes(w, 0, o.Hash[:]); err != nil {
return err
}
byteOrder.PutUint32(scratch, o.Index)
_, err := w.Write(scratch)
return err
}
const ( const (
// TODO(roasbeef): tune // MinBtcRemoteDelay is the minimum CSV delay we will require the remote
msgBufferSize = 50 // to use for its commitment transaction.
MinBtcRemoteDelay uint16 = 144
// minBtcRemoteDelay and maxBtcRemoteDelay is the extremes of the // MaxBtcRemoteDelay is the maximum CSV delay we will require the remote
// Bitcoin CSV delay we will require the remote to use for its // to use for its commitment transaction.
// commitment transaction. The actual delay we will require will be MaxBtcRemoteDelay uint16 = 2016
// somewhere between these values, depending on channel size.
minBtcRemoteDelay uint16 = 144
maxBtcRemoteDelay uint16 = 2016
// minLtcRemoteDelay and maxLtcRemoteDelay is the extremes of the // MinLtcRemoteDelay is the minimum Litecoin CSV delay we will require the
// Litecoin CSV delay we will require the remote to use for its // remote to use for its commitment transaction.
// commitment transaction. The actual delay we will require will be MinLtcRemoteDelay uint16 = 576
// somewhere between these values, depending on channel size.
minLtcRemoteDelay uint16 = 576
maxLtcRemoteDelay uint16 = 8064
// maxWaitNumBlocksFundingConf is the maximum number of blocks to wait // MaxLtcRemoteDelay is the maximum Litecoin CSV delay we will require the
// for the funding transaction to be confirmed before forgetting // remote to use for its commitment transaction.
// channels that aren't initiated by us. 2016 blocks is ~2 weeks. MaxLtcRemoteDelay uint16 = 8064
maxWaitNumBlocksFundingConf = 2016
// minChanFundingSize is the smallest channel that we'll allow to be // MinChanFundingSize is the smallest channel that we'll allow to be
// created over the RPC interface. // created over the RPC interface.
minChanFundingSize = btcutil.Amount(20000) MinChanFundingSize = btcutil.Amount(20000)
// MaxBtcFundingAmount is a soft-limit of the maximum channel size // MaxBtcFundingAmount is a soft-limit of the maximum channel size
// currently accepted on the Bitcoin chain within the Lightning // currently accepted on the Bitcoin chain within the Lightning
@ -73,24 +88,21 @@ const (
// you and limitless channel size (apart from 21 million cap) // you and limitless channel size (apart from 21 million cap)
MaxBtcFundingAmountWumbo = btcutil.Amount(1000000000) MaxBtcFundingAmountWumbo = btcutil.Amount(1000000000)
// maxLtcFundingAmount is a soft-limit of the maximum channel size // MaxLtcFundingAmount is a soft-limit of the maximum channel size
// currently accepted on the Litecoin chain within the Lightning // currently accepted on the Litecoin chain within the Lightning
// Protocol. // Protocol.
maxLtcFundingAmount = MaxBtcFundingAmount * chainreg.BtcToLtcConversionRate MaxLtcFundingAmount = MaxBtcFundingAmount * chainreg.BtcToLtcConversionRate
// TODO(roasbeef): tune
msgBufferSize = 50
// maxWaitNumBlocksFundingConf is the maximum number of blocks to wait
// for the funding transaction to be confirmed before forgetting
// channels that aren't initiated by us. 2016 blocks is ~2 weeks.
maxWaitNumBlocksFundingConf = 2016
) )
var ( var (
// MaxFundingAmount is a soft-limit of the maximum channel size
// currently accepted within the Lightning Protocol. This limit is
// defined in BOLT-0002, and serves as an initial precautionary limit
// while implementations are battle tested in the real world.
//
// At the moment, this value depends on which chain is active. It is set
// to the value under the Bitcoin chain as default.
//
// TODO(roasbeef): add command line param to modify
MaxFundingAmount = MaxBtcFundingAmount
// ErrFundingManagerShuttingDown is an error returned when attempting to // ErrFundingManagerShuttingDown is an error returned when attempting to
// process a funding request/message but the funding manager has already // process a funding request/message but the funding manager has already
// been signaled to shut down. // been signaled to shut down.
@ -159,14 +171,82 @@ func (r *reservationWithCtx) updateTimestamp() {
r.lastUpdated = time.Now() r.lastUpdated = time.Now()
} }
// initFundingMsg is sent by an outside subsystem to the funding manager in // InitFundingMsg is sent by an outside subsystem to the funding manager in
// order to kick off a funding workflow with a specified target peer. The // order to kick off a funding workflow with a specified target peer. The
// original request which defines the parameters of the funding workflow are // original request which defines the parameters of the funding workflow are
// embedded within this message giving the funding manager full context w.r.t // embedded within this message giving the funding manager full context w.r.t
// the workflow. // the workflow.
type initFundingMsg struct { type InitFundingMsg struct {
peer lnpeer.Peer // Peer is the peer that we want to open a channel to.
*openChanReq Peer lnpeer.Peer
// TargetPubkey is the public key of the peer.
TargetPubkey *btcec.PublicKey
// ChainHash is the target genesis hash for this channel.
ChainHash chainhash.Hash
// SubtractFees set to true means that fees will be subtracted
// from the LocalFundingAmt.
SubtractFees bool
// LocalFundingAmt is the size of the channel.
LocalFundingAmt btcutil.Amount
// PushAmt is the amount pushed to the counterparty.
PushAmt lnwire.MilliSatoshi
// FundingFeePerKw is the fee for the funding transaction.
FundingFeePerKw chainfee.SatPerKWeight
// Private determines whether or not this channel will be private.
Private bool
// MinHtlcIn is the minimum incoming HTLC that we accept.
MinHtlcIn lnwire.MilliSatoshi
// RemoteCsvDelay is the CSV delay we require for the remote peer.
RemoteCsvDelay uint16
// MinConfs indicates the minimum number of confirmations that each
// output selected to fund the channel should satisfy.
MinConfs int32
// ShutdownScript is an optional upfront shutdown script for the
// channel. This value is optional, so may be nil.
ShutdownScript lnwire.DeliveryAddress
// MaxValueInFlight is the maximum amount of coins in MilliSatoshi
// that can be pending within the channel. It only applies to the
// remote party.
MaxValueInFlight lnwire.MilliSatoshi
// MaxHtlcs is the maximum number of HTLCs that the remote peer
// can offer us.
MaxHtlcs uint16
// MaxLocalCsv is the maximum local csv delay we will accept from our
// peer.
MaxLocalCsv uint16
// ChanFunder is an optional channel funder that allows the caller to
// control exactly how the channel funding is carried out. If not
// specified, then the default chanfunding.WalletAssembler will be
// used.
ChanFunder chanfunding.Assembler
// PendingChanID is not all zeroes (the default value), then this will
// be the pending channel ID used for the funding flow within the wire
// protocol.
PendingChanID [32]byte
// Updates is a channel which updates to the opening status of the channel
// are sent on.
Updates chan *lnrpc.OpenStatusUpdate
// Err is a channel which errors encountered during the funding flow are
// sent on.
Err chan error
} }
// fundingMsg is sent by the ProcessFundingMsg function and packages a // fundingMsg is sent by the ProcessFundingMsg function and packages a
@ -194,10 +274,10 @@ func newSerializedKey(pubKey *btcec.PublicKey) serializedPubKey {
return s return s
} }
// fundingConfig defines the configuration for the FundingManager. All elements // Config defines the configuration for the FundingManager. All elements
// within the configuration MUST be non-nil for the FundingManager to carry out // within the configuration MUST be non-nil for the FundingManager to carry out
// its duties. // its duties.
type fundingConfig struct { type Config struct {
// NoWumboChans indicates if we're to reject all incoming wumbo channel // NoWumboChans indicates if we're to reject all incoming wumbo channel
// requests, and also reject all outgoing wumbo channel requests. // requests, and also reject all outgoing wumbo channel requests.
NoWumboChans bool NoWumboChans bool
@ -372,7 +452,7 @@ type fundingConfig struct {
MaxAnchorsCommitFeeRate chainfee.SatPerKWeight MaxAnchorsCommitFeeRate chainfee.SatPerKWeight
} }
// fundingManager acts as an orchestrator/bridge between the wallet's // Manager acts as an orchestrator/bridge between the wallet's
// 'ChannelReservation' workflow, and the wire protocol's funding initiation // 'ChannelReservation' workflow, and the wire protocol's funding initiation
// messages. Any requests to initiate the funding workflow for a channel, // messages. Any requests to initiate the funding workflow for a channel,
// either kicked-off locally or remotely are handled by the funding manager. // either kicked-off locally or remotely are handled by the funding manager.
@ -381,13 +461,13 @@ type fundingConfig struct {
// the channel workflow. Additionally, any temporary or permanent access // the channel workflow. Additionally, any temporary or permanent access
// controls between the wallet and remote peers are enforced via the funding // controls between the wallet and remote peers are enforced via the funding
// manager. // manager.
type fundingManager struct { type Manager struct {
started sync.Once started sync.Once
stopped sync.Once stopped sync.Once
// cfg is a copy of the configuration struct that the FundingManager // cfg is a copy of the configuration struct that the FundingManager
// was initialized with. // was initialized with.
cfg *fundingConfig cfg *Config
// chanIDKey is a cryptographically random key that's used to generate // chanIDKey is a cryptographically random key that's used to generate
// temporary channel ID's. // temporary channel ID's.
@ -417,13 +497,9 @@ type fundingManager struct {
// external sub-systems using the ProcessFundingMsg call. // external sub-systems using the ProcessFundingMsg call.
fundingMsgs chan *fundingMsg fundingMsgs chan *fundingMsg
// queries is a channel which receives requests to query the internal
// state of the funding manager.
queries chan interface{}
// fundingRequests is a channel used to receive channel initiation // fundingRequests is a channel used to receive channel initiation
// requests from a local subsystem within the daemon. // requests from a local subsystem within the daemon.
fundingRequests chan *initFundingMsg fundingRequests chan *InitFundingMsg
// newChanBarriers is a map from a channel ID to a 'barrier' which will // newChanBarriers is a map from a channel ID to a 'barrier' which will
// be signalled once the channel is fully open. This barrier acts as a // be signalled once the channel is fully open. This barrier acts as a
@ -478,27 +554,26 @@ var (
ErrChannelNotFound = fmt.Errorf("channel not found") ErrChannelNotFound = fmt.Errorf("channel not found")
) )
// newFundingManager creates and initializes a new instance of the // NewFundingManager creates and initializes a new instance of the
// fundingManager. // fundingManager.
func newFundingManager(cfg fundingConfig) (*fundingManager, error) { func NewFundingManager(cfg Config) (*Manager, error) {
return &fundingManager{ return &Manager{
cfg: &cfg, cfg: &cfg,
chanIDKey: cfg.TempChanIDSeed, chanIDKey: cfg.TempChanIDSeed,
activeReservations: make(map[serializedPubKey]pendingChannels), activeReservations: make(map[serializedPubKey]pendingChannels),
signedReservations: make(map[lnwire.ChannelID][32]byte), signedReservations: make(map[lnwire.ChannelID][32]byte),
newChanBarriers: make(map[lnwire.ChannelID]chan struct{}), newChanBarriers: make(map[lnwire.ChannelID]chan struct{}),
fundingMsgs: make(chan *fundingMsg, msgBufferSize), fundingMsgs: make(chan *fundingMsg, msgBufferSize),
fundingRequests: make(chan *initFundingMsg, msgBufferSize), fundingRequests: make(chan *InitFundingMsg, msgBufferSize),
localDiscoverySignals: make(map[lnwire.ChannelID]chan struct{}), localDiscoverySignals: make(map[lnwire.ChannelID]chan struct{}),
handleFundingLockedBarriers: make(map[lnwire.ChannelID]struct{}), handleFundingLockedBarriers: make(map[lnwire.ChannelID]struct{}),
queries: make(chan interface{}, 1),
quit: make(chan struct{}), quit: make(chan struct{}),
}, nil }, nil
} }
// Start launches all helper goroutines required for handling requests sent // Start launches all helper goroutines required for handling requests sent
// to the funding manager. // to the funding manager.
func (f *fundingManager) Start() error { func (f *Manager) Start() error {
var err error var err error
f.started.Do(func() { f.started.Do(func() {
err = f.start() err = f.start()
@ -506,8 +581,8 @@ func (f *fundingManager) Start() error {
return err return err
} }
func (f *fundingManager) start() error { func (f *Manager) start() error {
fndgLog.Tracef("Funding manager running") log.Tracef("Funding manager running")
// Upon restart, the Funding Manager will check the database to load any // Upon restart, the Funding Manager will check the database to load any
// channels that were waiting for their funding transactions to be // channels that were waiting for their funding transactions to be
@ -529,7 +604,7 @@ func (f *fundingManager) start() error {
// funding transaction if we're the initiator. // funding transaction if we're the initiator.
if channel.IsPending { if channel.IsPending {
f.barrierMtx.Lock() f.barrierMtx.Lock()
fndgLog.Tracef("Loading pending ChannelPoint(%v), "+ log.Tracef("Loading pending ChannelPoint(%v), "+
"creating chan barrier", "creating chan barrier",
channel.FundingOutpoint) channel.FundingOutpoint)
@ -548,7 +623,7 @@ func (f *fundingManager) start() error {
var fundingTxBuf bytes.Buffer var fundingTxBuf bytes.Buffer
err := channel.FundingTxn.Serialize(&fundingTxBuf) err := channel.FundingTxn.Serialize(&fundingTxBuf)
if err != nil { if err != nil {
fndgLog.Errorf("Unable to serialize "+ log.Errorf("Unable to serialize "+
"funding transaction %v: %v", "funding transaction %v: %v",
channel.FundingTxn.TxHash(), err) channel.FundingTxn.TxHash(), err)
@ -559,7 +634,7 @@ func (f *fundingManager) start() error {
fundingTxBuf.Reset() fundingTxBuf.Reset()
} }
fndgLog.Debugf("Rebroadcasting funding tx for "+ log.Debugf("Rebroadcasting funding tx for "+
"ChannelPoint(%v): %x", "ChannelPoint(%v): %x",
channel.FundingOutpoint, channel.FundingOutpoint,
fundingTxBuf.Bytes()) fundingTxBuf.Bytes())
@ -575,7 +650,7 @@ func (f *fundingManager) start() error {
channel.FundingTxn, label, channel.FundingTxn, label,
) )
if err != nil { if err != nil {
fndgLog.Errorf("Unable to rebroadcast "+ log.Errorf("Unable to rebroadcast "+
"funding tx %x for "+ "funding tx %x for "+
"ChannelPoint(%v): %v", "ChannelPoint(%v): %v",
fundingTxBuf.Bytes(), fundingTxBuf.Bytes(),
@ -600,26 +675,17 @@ func (f *fundingManager) start() error {
// Stop signals all helper goroutines to execute a graceful shutdown. This // Stop signals all helper goroutines to execute a graceful shutdown. This
// method will block until all goroutines have exited. // method will block until all goroutines have exited.
func (f *fundingManager) Stop() error { func (f *Manager) Stop() {
var err error
f.stopped.Do(func() { f.stopped.Do(func() {
err = f.stop() log.Info("Funding manager shutting down")
})
return err
}
func (f *fundingManager) stop() error {
fndgLog.Infof("Funding manager shutting down")
close(f.quit) close(f.quit)
f.wg.Wait() f.wg.Wait()
})
return nil
} }
// nextPendingChanID returns the next free pending channel ID to be used to // nextPendingChanID returns the next free pending channel ID to be used to
// identify a particular future channel funding workflow. // identify a particular future channel funding workflow.
func (f *fundingManager) nextPendingChanID() [32]byte { func (f *Manager) nextPendingChanID() [32]byte {
// Obtain a fresh nonce. We do this by encoding the current nonce // Obtain a fresh nonce. We do this by encoding the current nonce
// counter, then incrementing it by one. // counter, then incrementing it by one.
f.nonceMtx.Lock() f.nonceMtx.Lock()
@ -639,52 +705,12 @@ func (f *fundingManager) nextPendingChanID() [32]byte {
return nextChanID return nextChanID
} }
type pendingChannel struct {
identityPub *btcec.PublicKey
channelPoint *wire.OutPoint
capacity btcutil.Amount
localBalance btcutil.Amount
remoteBalance btcutil.Amount
}
type pendingChansReq struct {
resp chan []*pendingChannel
err chan error
}
// PendingChannels returns a slice describing all the channels which are
// currently pending at the last state of the funding workflow.
func (f *fundingManager) PendingChannels() ([]*pendingChannel, error) {
respChan := make(chan []*pendingChannel, 1)
errChan := make(chan error, 1)
req := &pendingChansReq{
resp: respChan,
err: errChan,
}
select {
case f.queries <- req:
case <-f.quit:
return nil, ErrFundingManagerShuttingDown
}
select {
case resp := <-respChan:
return resp, nil
case err := <-errChan:
return nil, err
case <-f.quit:
return nil, ErrFundingManagerShuttingDown
}
}
// CancelPeerReservations cancels all active reservations associated with the // CancelPeerReservations cancels all active reservations associated with the
// passed node. This will ensure any outputs which have been pre committed, // passed node. This will ensure any outputs which have been pre committed,
// (and thus locked from coin selection), are properly freed. // (and thus locked from coin selection), are properly freed.
func (f *fundingManager) CancelPeerReservations(nodePub [33]byte) { func (f *Manager) CancelPeerReservations(nodePub [33]byte) {
fndgLog.Debugf("Cancelling all reservations for peer %x", nodePub[:]) log.Debugf("Cancelling all reservations for peer %x", nodePub[:])
f.resMtx.Lock() f.resMtx.Lock()
defer f.resMtx.Unlock() defer f.resMtx.Unlock()
@ -694,7 +720,7 @@ func (f *fundingManager) CancelPeerReservations(nodePub [33]byte) {
// to be done. // to be done.
nodeReservations, ok := f.activeReservations[nodePub] nodeReservations, ok := f.activeReservations[nodePub]
if !ok { if !ok {
fndgLog.Debugf("No active reservations for node: %x", nodePub[:]) log.Debugf("No active reservations for node: %x", nodePub[:])
return return
} }
@ -703,7 +729,7 @@ func (f *fundingManager) CancelPeerReservations(nodePub [33]byte) {
// reservation map. // reservation map.
for pendingID, resCtx := range nodeReservations { for pendingID, resCtx := range nodeReservations {
if err := resCtx.reservation.Cancel(); err != nil { if err := resCtx.reservation.Cancel(); err != nil {
fndgLog.Errorf("unable to cancel reservation for "+ log.Errorf("unable to cancel reservation for "+
"node=%x: %v", nodePub[:], err) "node=%x: %v", nodePub[:], err)
} }
@ -722,15 +748,15 @@ func (f *fundingManager) CancelPeerReservations(nodePub [33]byte) {
// //
// TODO(roasbeef): if peer disconnects, and haven't yet broadcast funding // TODO(roasbeef): if peer disconnects, and haven't yet broadcast funding
// transaction, then all reservations should be cleared. // transaction, then all reservations should be cleared.
func (f *fundingManager) failFundingFlow(peer lnpeer.Peer, tempChanID [32]byte, func (f *Manager) failFundingFlow(peer lnpeer.Peer, tempChanID [32]byte,
fundingErr error) { fundingErr error) {
fndgLog.Debugf("Failing funding flow for pending_id=%x: %v", log.Debugf("Failing funding flow for pending_id=%x: %v",
tempChanID, fundingErr) tempChanID, fundingErr)
ctx, err := f.cancelReservationCtx(peer.IdentityKey(), tempChanID, false) ctx, err := f.cancelReservationCtx(peer.IdentityKey(), tempChanID, false)
if err != nil { if err != nil {
fndgLog.Errorf("unable to cancel reservation: %v", err) log.Errorf("unable to cancel reservation: %v", err)
} }
// In case the case where the reservation existed, send the funding // In case the case where the reservation existed, send the funding
@ -763,10 +789,10 @@ func (f *fundingManager) failFundingFlow(peer lnpeer.Peer, tempChanID [32]byte,
Data: msg, Data: msg,
} }
fndgLog.Debugf("Sending funding error to peer (%x): %v", log.Debugf("Sending funding error to peer (%x): %v",
peer.IdentityKey().SerializeCompressed(), spew.Sdump(errMsg)) peer.IdentityKey().SerializeCompressed(), spew.Sdump(errMsg))
if err := peer.SendMessage(false, errMsg); err != nil { if err := peer.SendMessage(false, errMsg); err != nil {
fndgLog.Errorf("unable to send error message to peer %v", err) log.Errorf("unable to send error message to peer %v", err)
} }
} }
@ -774,7 +800,7 @@ func (f *fundingManager) failFundingFlow(peer lnpeer.Peer, tempChanID [32]byte,
// funding workflow between the wallet, and any outside peers or local callers. // funding workflow between the wallet, and any outside peers or local callers.
// //
// NOTE: This MUST be run as a goroutine. // NOTE: This MUST be run as a goroutine.
func (f *fundingManager) reservationCoordinator() { func (f *Manager) reservationCoordinator() {
defer f.wg.Done() defer f.wg.Done()
zombieSweepTicker := time.NewTicker(f.cfg.ZombieSweeperInterval) zombieSweepTicker := time.NewTicker(f.cfg.ZombieSweeperInterval)
@ -805,11 +831,6 @@ func (f *fundingManager) reservationCoordinator() {
case <-zombieSweepTicker.C: case <-zombieSweepTicker.C:
f.pruneZombieReservations() f.pruneZombieReservations()
case req := <-f.queries:
switch msg := req.(type) {
case *pendingChansReq:
f.handlePendingChannels(msg)
}
case <-f.quit: case <-f.quit:
return return
} }
@ -824,7 +845,7 @@ func (f *fundingManager) reservationCoordinator() {
// to get OpenStatusUpdates. // to get OpenStatusUpdates.
// //
// NOTE: This MUST be run as a goroutine. // NOTE: This MUST be run as a goroutine.
func (f *fundingManager) advanceFundingState(channel *channeldb.OpenChannel, func (f *Manager) advanceFundingState(channel *channeldb.OpenChannel,
pendingChanID [32]byte, updateChan chan<- *lnrpc.OpenStatusUpdate) { pendingChanID [32]byte, updateChan chan<- *lnrpc.OpenStatusUpdate) {
defer f.wg.Done() defer f.wg.Done()
@ -834,7 +855,7 @@ func (f *fundingManager) advanceFundingState(channel *channeldb.OpenChannel,
if channel.IsPending { if channel.IsPending {
err := f.advancePendingChannelState(channel, pendingChanID) err := f.advancePendingChannelState(channel, pendingChanID)
if err != nil { if err != nil {
fndgLog.Errorf("Unable to advance pending state of "+ log.Errorf("Unable to advance pending state of "+
"ChannelPoint(%v): %v", "ChannelPoint(%v): %v",
channel.FundingOutpoint, err) channel.FundingOutpoint, err)
return return
@ -846,7 +867,7 @@ func (f *fundingManager) advanceFundingState(channel *channeldb.OpenChannel,
nil, channel, nil, nil, channel, nil,
) )
if err != nil { if err != nil {
fndgLog.Errorf("Unable to create LightningChannel(%v): %v", log.Errorf("Unable to create LightningChannel(%v): %v",
channel.FundingOutpoint, err) channel.FundingOutpoint, err)
return return
} }
@ -861,13 +882,13 @@ func (f *fundingManager) advanceFundingState(channel *channeldb.OpenChannel,
// network. // network.
// TODO(halseth): could do graph consistency check // TODO(halseth): could do graph consistency check
// here, and re-add the edge if missing. // here, and re-add the edge if missing.
fndgLog.Debugf("ChannelPoint(%v) with chan_id=%x not "+ log.Debugf("ChannelPoint(%v) with chan_id=%x not "+
"found in opening database, assuming already "+ "found in opening database, assuming already "+
"announced to the network", "announced to the network",
channel.FundingOutpoint, pendingChanID) channel.FundingOutpoint, pendingChanID)
return return
} else if err != nil { } else if err != nil {
fndgLog.Errorf("Unable to query database for "+ log.Errorf("Unable to query database for "+
"channel opening state(%v): %v", "channel opening state(%v): %v",
channel.FundingOutpoint, err) channel.FundingOutpoint, err)
return return
@ -882,7 +903,7 @@ func (f *fundingManager) advanceFundingState(channel *channeldb.OpenChannel,
channelState, updateChan, channelState, updateChan,
) )
if err != nil { if err != nil {
fndgLog.Errorf("Unable to advance state(%v): %v", log.Errorf("Unable to advance state(%v): %v",
channel.FundingOutpoint, err) channel.FundingOutpoint, err)
return return
} }
@ -893,14 +914,14 @@ func (f *fundingManager) advanceFundingState(channel *channeldb.OpenChannel,
// machine. This method is synchronous and the new channel opening state will // machine. This method is synchronous and the new channel opening state will
// have been written to the database when it successfully returns. The // have been written to the database when it successfully returns. The
// updateChan can be set non-nil to get OpenStatusUpdates. // updateChan can be set non-nil to get OpenStatusUpdates.
func (f *fundingManager) stateStep(channel *channeldb.OpenChannel, func (f *Manager) stateStep(channel *channeldb.OpenChannel,
lnChannel *lnwallet.LightningChannel, lnChannel *lnwallet.LightningChannel,
shortChanID *lnwire.ShortChannelID, pendingChanID [32]byte, shortChanID *lnwire.ShortChannelID, pendingChanID [32]byte,
channelState channelOpeningState, channelState channelOpeningState,
updateChan chan<- *lnrpc.OpenStatusUpdate) error { updateChan chan<- *lnrpc.OpenStatusUpdate) error {
chanID := lnwire.NewChanIDFromOutPoint(&channel.FundingOutpoint) chanID := lnwire.NewChanIDFromOutPoint(&channel.FundingOutpoint)
fndgLog.Debugf("Channel(%v) with ShortChanID %v has opening state %v", log.Debugf("Channel(%v) with ShortChanID %v has opening state %v",
chanID, shortChanID, channelState) chanID, shortChanID, channelState)
switch channelState { switch channelState {
@ -927,7 +948,7 @@ func (f *fundingManager) stateStep(channel *channeldb.OpenChannel,
" fundingLockedSent: %v", err) " fundingLockedSent: %v", err)
} }
fndgLog.Debugf("Channel(%v) with ShortChanID %v: successfully "+ log.Debugf("Channel(%v) with ShortChanID %v: successfully "+
"sent FundingLocked", chanID, shortChanID) "sent FundingLocked", chanID, shortChanID)
return nil return nil
@ -954,7 +975,7 @@ func (f *fundingManager) stateStep(channel *channeldb.OpenChannel,
" addedToRouterGraph: %v", err) " addedToRouterGraph: %v", err)
} }
fndgLog.Debugf("Channel(%v) with ShortChanID %v: successfully "+ log.Debugf("Channel(%v) with ShortChanID %v: successfully "+
"added to router graph", chanID, shortChanID) "added to router graph", chanID, shortChanID)
// Give the caller a final update notifying them that // Give the caller a final update notifying them that
@ -1007,7 +1028,7 @@ func (f *fundingManager) stateStep(channel *channeldb.OpenChannel,
err) err)
} }
fndgLog.Debugf("Channel(%v) with ShortChanID %v: successfully "+ log.Debugf("Channel(%v) with ShortChanID %v: successfully "+
"announced", chanID, shortChanID) "announced", chanID, shortChanID)
return nil return nil
@ -1018,7 +1039,7 @@ func (f *fundingManager) stateStep(channel *channeldb.OpenChannel,
// advancePendingChannelState waits for a pending channel's funding tx to // advancePendingChannelState waits for a pending channel's funding tx to
// confirm, and marks it open in the database when that happens. // confirm, and marks it open in the database when that happens.
func (f *fundingManager) advancePendingChannelState( func (f *Manager) advancePendingChannelState(
channel *channeldb.OpenChannel, pendingChanID [32]byte) error { channel *channeldb.OpenChannel, pendingChanID [32]byte) error {
confChannel, err := f.waitForFundingWithTimeout(channel) confChannel, err := f.waitForFundingWithTimeout(channel)
@ -1086,7 +1107,7 @@ func (f *fundingManager) advancePendingChannelState(
// Success, funding transaction was confirmed. // Success, funding transaction was confirmed.
chanID := lnwire.NewChanIDFromOutPoint(&channel.FundingOutpoint) chanID := lnwire.NewChanIDFromOutPoint(&channel.FundingOutpoint)
fndgLog.Debugf("ChannelID(%v) is now fully confirmed! "+ log.Debugf("ChannelID(%v) is now fully confirmed! "+
"(shortChanID=%v)", chanID, confChannel.shortChanID) "(shortChanID=%v)", chanID, confChannel.shortChanID)
err = f.handleFundingConfirmation(channel, confChannel) err = f.handleFundingConfirmation(channel, confChannel)
@ -1099,36 +1120,9 @@ func (f *fundingManager) advancePendingChannelState(
return nil return nil
} }
// handlePendingChannels responds to a request for details concerning all
// currently pending channels waiting for the final phase of the funding
// workflow (funding txn confirmation).
func (f *fundingManager) handlePendingChannels(msg *pendingChansReq) {
var pendingChannels []*pendingChannel
dbPendingChannels, err := f.cfg.Wallet.Cfg.Database.FetchPendingChannels()
if err != nil {
msg.err <- err
return
}
for _, dbPendingChan := range dbPendingChannels {
pendingChan := &pendingChannel{
identityPub: dbPendingChan.IdentityPub,
channelPoint: &dbPendingChan.FundingOutpoint,
capacity: dbPendingChan.Capacity,
localBalance: dbPendingChan.LocalCommitment.LocalBalance.ToSatoshis(),
remoteBalance: dbPendingChan.LocalCommitment.RemoteBalance.ToSatoshis(),
}
pendingChannels = append(pendingChannels, pendingChan)
}
msg.resp <- pendingChannels
}
// ProcessFundingMsg sends a message to the internal fundingManager goroutine, // ProcessFundingMsg sends a message to the internal fundingManager goroutine,
// allowing it to handle the lnwire.Message. // allowing it to handle the lnwire.Message.
func (f *fundingManager) ProcessFundingMsg(msg lnwire.Message, peer lnpeer.Peer) { func (f *Manager) ProcessFundingMsg(msg lnwire.Message, peer lnpeer.Peer) {
select { select {
case f.fundingMsgs <- &fundingMsg{msg, peer}: case f.fundingMsgs <- &fundingMsg{msg, peer}:
case <-f.quit: case <-f.quit:
@ -1179,7 +1173,7 @@ func commitmentType(localFeatures,
// //
// TODO(roasbeef): add error chan to all, let channelManager handle // TODO(roasbeef): add error chan to all, let channelManager handle
// error+propagate // error+propagate
func (f *fundingManager) handleFundingOpen(peer lnpeer.Peer, func (f *Manager) handleFundingOpen(peer lnpeer.Peer,
msg *lnwire.OpenChannel) { msg *lnwire.OpenChannel) {
// Check number of pending channels to be smaller than maximum allowed // Check number of pending channels to be smaller than maximum allowed
@ -1244,7 +1238,7 @@ func (f *fundingManager) handleFundingOpen(peer lnpeer.Peer,
isSynced, _, err := f.cfg.Wallet.IsSynced() isSynced, _, err := f.cfg.Wallet.IsSynced()
if err != nil || !isSynced { if err != nil || !isSynced {
if err != nil { if err != nil {
fndgLog.Errorf("unable to query wallet: %v", err) log.Errorf("unable to query wallet: %v", err)
} }
f.failFundingFlow( f.failFundingFlow(
peer, msg.PendingChannelID, peer, msg.PendingChannelID,
@ -1300,7 +1294,7 @@ func (f *fundingManager) handleFundingOpen(peer lnpeer.Peer,
return return
} }
fndgLog.Infof("Recv'd fundingRequest(amt=%v, push=%v, delay=%v, "+ log.Infof("Recv'd fundingRequest(amt=%v, push=%v, delay=%v, "+
"pendingId=%x) from peer(%x)", amt, msg.PushAmount, "pendingId=%x) from peer(%x)", amt, msg.PushAmount,
msg.CsvDelay, msg.PendingChannelID, msg.CsvDelay, msg.PendingChannelID,
peer.IdentityKey().SerializeCompressed()) peer.IdentityKey().SerializeCompressed())
@ -1335,7 +1329,7 @@ func (f *fundingManager) handleFundingOpen(peer lnpeer.Peer,
reservation, err := f.cfg.Wallet.InitChannelReservation(req) reservation, err := f.cfg.Wallet.InitChannelReservation(req)
if err != nil { if err != nil {
fndgLog.Errorf("Unable to initialize reservation: %v", err) log.Errorf("Unable to initialize reservation: %v", err)
f.failFundingFlow(peer, msg.PendingChannelID, err) f.failFundingFlow(peer, msg.PendingChannelID, err)
return return
} }
@ -1366,7 +1360,7 @@ func (f *fundingManager) handleFundingOpen(peer lnpeer.Peer,
channelConstraints, f.cfg.MaxLocalCSVDelay, channelConstraints, f.cfg.MaxLocalCSVDelay,
) )
if err != nil { if err != nil {
fndgLog.Errorf("Unacceptable channel constraints: %v", err) log.Errorf("Unacceptable channel constraints: %v", err)
f.failFundingFlow(peer, msg.PendingChannelID, err) f.failFundingFlow(peer, msg.PendingChannelID, err)
return return
} }
@ -1394,7 +1388,7 @@ func (f *fundingManager) handleFundingOpen(peer lnpeer.Peer,
} }
reservation.SetOurUpfrontShutdown(shutdown) reservation.SetOurUpfrontShutdown(shutdown)
fndgLog.Infof("Requiring %v confirmations for pendingChan(%x): "+ log.Infof("Requiring %v confirmations for pendingChan(%x): "+
"amt=%v, push_amt=%v, committype=%v, upfrontShutdown=%x", numConfsReq, "amt=%v, push_amt=%v, committype=%v, upfrontShutdown=%x", numConfsReq,
msg.PendingChannelID, amt, msg.PushAmount, msg.PendingChannelID, amt, msg.PushAmount,
commitType, msg.UpfrontShutdownScript) commitType, msg.UpfrontShutdownScript)
@ -1486,14 +1480,14 @@ func (f *fundingManager) handleFundingOpen(peer lnpeer.Peer,
} }
err = reservation.ProcessSingleContribution(remoteContribution) err = reservation.ProcessSingleContribution(remoteContribution)
if err != nil { if err != nil {
fndgLog.Errorf("unable to add contribution reservation: %v", err) log.Errorf("unable to add contribution reservation: %v", err)
f.failFundingFlow(peer, msg.PendingChannelID, err) f.failFundingFlow(peer, msg.PendingChannelID, err)
return return
} }
fndgLog.Infof("Sending fundingResp for pending_id(%x)", log.Infof("Sending fundingResp for pending_id(%x)",
msg.PendingChannelID) msg.PendingChannelID)
fndgLog.Debugf("Remote party accepted commitment constraints: %v", log.Debugf("Remote party accepted commitment constraints: %v",
spew.Sdump(remoteContribution.ChannelConfig.ChannelConstraints)) spew.Sdump(remoteContribution.ChannelConfig.ChannelConstraints))
// With the initiator's contribution recorded, respond with our // With the initiator's contribution recorded, respond with our
@ -1518,7 +1512,7 @@ func (f *fundingManager) handleFundingOpen(peer lnpeer.Peer,
} }
if err := peer.SendMessage(true, &fundingAccept); err != nil { if err := peer.SendMessage(true, &fundingAccept); err != nil {
fndgLog.Errorf("unable to send funding response to peer: %v", err) log.Errorf("unable to send funding response to peer: %v", err)
f.failFundingFlow(peer, msg.PendingChannelID, err) f.failFundingFlow(peer, msg.PendingChannelID, err)
return return
} }
@ -1527,7 +1521,7 @@ func (f *fundingManager) handleFundingOpen(peer lnpeer.Peer,
// handleFundingAccept processes a response to the workflow initiation sent by // handleFundingAccept processes a response to the workflow initiation sent by
// the remote peer. This message then queues a message with the funding // the remote peer. This message then queues a message with the funding
// outpoint, and a commitment signature to the remote peer. // outpoint, and a commitment signature to the remote peer.
func (f *fundingManager) handleFundingAccept(peer lnpeer.Peer, func (f *Manager) handleFundingAccept(peer lnpeer.Peer,
msg *lnwire.AcceptChannel) { msg *lnwire.AcceptChannel) {
pendingChanID := msg.PendingChannelID pendingChanID := msg.PendingChannelID
@ -1535,7 +1529,7 @@ func (f *fundingManager) handleFundingAccept(peer lnpeer.Peer,
resCtx, err := f.getReservationCtx(peerKey, pendingChanID) resCtx, err := f.getReservationCtx(peerKey, pendingChanID)
if err != nil { if err != nil {
fndgLog.Warnf("Can't find reservation (peerKey:%v, chan_id:%v)", log.Warnf("Can't find reservation (peerKey:%v, chan_id:%v)",
peerKey, pendingChanID) peerKey, pendingChanID)
return return
} }
@ -1543,7 +1537,7 @@ func (f *fundingManager) handleFundingAccept(peer lnpeer.Peer,
// Update the timestamp once the fundingAcceptMsg has been handled. // Update the timestamp once the fundingAcceptMsg has been handled.
defer resCtx.updateTimestamp() defer resCtx.updateTimestamp()
fndgLog.Infof("Recv'd fundingResponse for pending_id(%x)", log.Infof("Recv'd fundingResponse for pending_id(%x)",
pendingChanID[:]) pendingChanID[:])
// The required number of confirmations should not be greater than the // The required number of confirmations should not be greater than the
@ -1553,7 +1547,7 @@ func (f *fundingManager) handleFundingAccept(peer lnpeer.Peer,
err := lnwallet.ErrNumConfsTooLarge( err := lnwallet.ErrNumConfsTooLarge(
msg.MinAcceptDepth, chainntnfs.MaxNumConfs, msg.MinAcceptDepth, chainntnfs.MaxNumConfs,
) )
fndgLog.Warnf("Unacceptable channel constraints: %v", err) log.Warnf("Unacceptable channel constraints: %v", err)
f.failFundingFlow(peer, msg.PendingChannelID, err) f.failFundingFlow(peer, msg.PendingChannelID, err)
return return
} }
@ -1574,7 +1568,7 @@ func (f *fundingManager) handleFundingAccept(peer lnpeer.Peer,
channelConstraints, resCtx.maxLocalCsv, channelConstraints, resCtx.maxLocalCsv,
) )
if err != nil { if err != nil {
fndgLog.Warnf("Unacceptable channel constraints: %v", err) log.Warnf("Unacceptable channel constraints: %v", err)
f.failFundingFlow(peer, msg.PendingChannelID, err) f.failFundingFlow(peer, msg.PendingChannelID, err)
return return
} }
@ -1629,7 +1623,7 @@ func (f *fundingManager) handleFundingAccept(peer lnpeer.Peer,
// construct the PSBT back to the caller. // construct the PSBT back to the caller.
addr, amt, packet, err := psbtErr.Intent.FundingParams() addr, amt, packet, err := psbtErr.Intent.FundingParams()
if err != nil { if err != nil {
fndgLog.Errorf("Unable to process PSBT funding params "+ log.Errorf("Unable to process PSBT funding params "+
"for contribution from %v: %v", peerKey, err) "for contribution from %v: %v", peerKey, err)
f.failFundingFlow(peer, msg.PendingChannelID, err) f.failFundingFlow(peer, msg.PendingChannelID, err)
return return
@ -1637,7 +1631,7 @@ func (f *fundingManager) handleFundingAccept(peer lnpeer.Peer,
var buf bytes.Buffer var buf bytes.Buffer
err = packet.Serialize(&buf) err = packet.Serialize(&buf)
if err != nil { if err != nil {
fndgLog.Errorf("Unable to serialize PSBT for "+ log.Errorf("Unable to serialize PSBT for "+
"contribution from %v: %v", peerKey, err) "contribution from %v: %v", peerKey, err)
f.failFundingFlow(peer, msg.PendingChannelID, err) f.failFundingFlow(peer, msg.PendingChannelID, err)
return return
@ -1654,15 +1648,15 @@ func (f *fundingManager) handleFundingAccept(peer lnpeer.Peer,
} }
psbtIntent = psbtErr.Intent psbtIntent = psbtErr.Intent
} else if err != nil { } else if err != nil {
fndgLog.Errorf("Unable to process contribution from %v: %v", log.Errorf("Unable to process contribution from %v: %v",
peerKey, err) peerKey, err)
f.failFundingFlow(peer, msg.PendingChannelID, err) f.failFundingFlow(peer, msg.PendingChannelID, err)
return return
} }
fndgLog.Infof("pendingChan(%x): remote party proposes num_confs=%v, "+ log.Infof("pendingChan(%x): remote party proposes num_confs=%v, "+
"csv_delay=%v", pendingChanID[:], msg.MinAcceptDepth, msg.CsvDelay) "csv_delay=%v", pendingChanID[:], msg.MinAcceptDepth, msg.CsvDelay)
fndgLog.Debugf("Remote party accepted commitment constraints: %v", log.Debugf("Remote party accepted commitment constraints: %v",
spew.Sdump(remoteContribution.ChannelConfig.ChannelConstraints)) spew.Sdump(remoteContribution.ChannelConfig.ChannelConstraints))
// If the user requested funding through a PSBT, we cannot directly // If the user requested funding through a PSBT, we cannot directly
@ -1691,14 +1685,14 @@ func (f *fundingManager) handleFundingAccept(peer lnpeer.Peer,
// is continued. // is continued.
// //
// NOTE: This method must be called as a goroutine. // NOTE: This method must be called as a goroutine.
func (f *fundingManager) waitForPsbt(intent *chanfunding.PsbtIntent, func (f *Manager) waitForPsbt(intent *chanfunding.PsbtIntent,
resCtx *reservationWithCtx, pendingChanID [32]byte) { resCtx *reservationWithCtx, pendingChanID [32]byte) {
// failFlow is a helper that logs an error message with the current // failFlow is a helper that logs an error message with the current
// context and then fails the funding flow. // context and then fails the funding flow.
peerKey := resCtx.peer.IdentityKey() peerKey := resCtx.peer.IdentityKey()
failFlow := func(errMsg string, cause error) { failFlow := func(errMsg string, cause error) {
fndgLog.Errorf("Unable to handle funding accept message "+ log.Errorf("Unable to handle funding accept message "+
"for peer_key=%x, pending_chan_id=%x: %s: %v", "for peer_key=%x, pending_chan_id=%x: %s: %v",
peerKey.SerializeCompressed(), pendingChanID, errMsg, peerKey.SerializeCompressed(), pendingChanID, errMsg,
cause) cause)
@ -1721,7 +1715,7 @@ func (f *fundingManager) waitForPsbt(intent *chanfunding.PsbtIntent,
// to send another fail message. But we want to inform the user // to send another fail message. But we want to inform the user
// about what happened. // about what happened.
case chanfunding.ErrRemoteCanceled: case chanfunding.ErrRemoteCanceled:
fndgLog.Infof("Remote canceled, aborting PSBT flow "+ log.Infof("Remote canceled, aborting PSBT flow "+
"for peer_key=%x, pending_chan_id=%x", "for peer_key=%x, pending_chan_id=%x",
peerKey.SerializeCompressed(), pendingChanID) peerKey.SerializeCompressed(), pendingChanID)
return return
@ -1750,7 +1744,7 @@ func (f *fundingManager) waitForPsbt(intent *chanfunding.PsbtIntent,
// Handle a server shutdown as well because the reservation won't // Handle a server shutdown as well because the reservation won't
// survive a restart as it's in memory only. // survive a restart as it's in memory only.
case <-f.quit: case <-f.quit:
fndgLog.Errorf("Unable to handle funding accept message "+ log.Errorf("Unable to handle funding accept message "+
"for peer_key=%x, pending_chan_id=%x: funding manager "+ "for peer_key=%x, pending_chan_id=%x: funding manager "+
"shutting down", peerKey.SerializeCompressed(), "shutting down", peerKey.SerializeCompressed(),
pendingChanID) pendingChanID)
@ -1761,7 +1755,7 @@ func (f *fundingManager) waitForPsbt(intent *chanfunding.PsbtIntent,
// continueFundingAccept continues the channel funding flow once our // continueFundingAccept continues the channel funding flow once our
// contribution is finalized, the channel output is known and the funding // contribution is finalized, the channel output is known and the funding
// transaction is signed. // transaction is signed.
func (f *fundingManager) continueFundingAccept(resCtx *reservationWithCtx, func (f *Manager) continueFundingAccept(resCtx *reservationWithCtx,
pendingChanID [32]byte) { pendingChanID [32]byte) {
// Now that we have their contribution, we can extract, then send over // Now that we have their contribution, we can extract, then send over
@ -1776,7 +1770,7 @@ func (f *fundingManager) continueFundingAccept(resCtx *reservationWithCtx,
// fully open. // fully open.
f.barrierMtx.Lock() f.barrierMtx.Lock()
channelID := lnwire.NewChanIDFromOutPoint(outPoint) channelID := lnwire.NewChanIDFromOutPoint(outPoint)
fndgLog.Debugf("Creating chan barrier for ChanID(%v)", channelID) log.Debugf("Creating chan barrier for ChanID(%v)", channelID)
f.newChanBarriers[channelID] = make(chan struct{}) f.newChanBarriers[channelID] = make(chan struct{})
f.barrierMtx.Unlock() f.barrierMtx.Unlock()
@ -1788,7 +1782,7 @@ func (f *fundingManager) continueFundingAccept(resCtx *reservationWithCtx,
f.signedReservations[channelID] = pendingChanID f.signedReservations[channelID] = pendingChanID
f.resMtx.Unlock() f.resMtx.Unlock()
fndgLog.Infof("Generated ChannelPoint(%v) for pending_id(%x)", outPoint, log.Infof("Generated ChannelPoint(%v) for pending_id(%x)", outPoint,
pendingChanID[:]) pendingChanID[:])
var err error var err error
@ -1798,12 +1792,12 @@ func (f *fundingManager) continueFundingAccept(resCtx *reservationWithCtx,
} }
fundingCreated.CommitSig, err = lnwire.NewSigFromSignature(sig) fundingCreated.CommitSig, err = lnwire.NewSigFromSignature(sig)
if err != nil { if err != nil {
fndgLog.Errorf("Unable to parse signature: %v", err) log.Errorf("Unable to parse signature: %v", err)
f.failFundingFlow(resCtx.peer, pendingChanID, err) f.failFundingFlow(resCtx.peer, pendingChanID, err)
return return
} }
if err := resCtx.peer.SendMessage(true, fundingCreated); err != nil { if err := resCtx.peer.SendMessage(true, fundingCreated); err != nil {
fndgLog.Errorf("Unable to send funding complete message: %v", err) log.Errorf("Unable to send funding complete message: %v", err)
f.failFundingFlow(resCtx.peer, pendingChanID, err) f.failFundingFlow(resCtx.peer, pendingChanID, err)
return return
} }
@ -1813,7 +1807,7 @@ func (f *fundingManager) continueFundingAccept(resCtx *reservationWithCtx,
// the responding side of a single funder workflow. Once this message has been // the responding side of a single funder workflow. Once this message has been
// processed, a signature is sent to the remote peer allowing it to broadcast // processed, a signature is sent to the remote peer allowing it to broadcast
// the funding transaction, progressing the workflow into the final stage. // the funding transaction, progressing the workflow into the final stage.
func (f *fundingManager) handleFundingCreated(peer lnpeer.Peer, func (f *Manager) handleFundingCreated(peer lnpeer.Peer,
msg *lnwire.FundingCreated) { msg *lnwire.FundingCreated) {
peerKey := peer.IdentityKey() peerKey := peer.IdentityKey()
@ -1821,7 +1815,7 @@ func (f *fundingManager) handleFundingCreated(peer lnpeer.Peer,
resCtx, err := f.getReservationCtx(peerKey, pendingChanID) resCtx, err := f.getReservationCtx(peerKey, pendingChanID)
if err != nil { if err != nil {
fndgLog.Warnf("can't find reservation (peer_id:%v, chan_id:%x)", log.Warnf("can't find reservation (peer_id:%v, chan_id:%x)",
peerKey, pendingChanID[:]) peerKey, pendingChanID[:])
return return
} }
@ -1832,12 +1826,12 @@ func (f *fundingManager) handleFundingCreated(peer lnpeer.Peer,
// initiator's commitment transaction, then send our own if it's valid. // initiator's commitment transaction, then send our own if it's valid.
// TODO(roasbeef): make case (p vs P) consistent throughout // TODO(roasbeef): make case (p vs P) consistent throughout
fundingOut := msg.FundingPoint fundingOut := msg.FundingPoint
fndgLog.Infof("completing pending_id(%x) with ChannelPoint(%v)", log.Infof("completing pending_id(%x) with ChannelPoint(%v)",
pendingChanID[:], fundingOut) pendingChanID[:], fundingOut)
commitSig, err := msg.CommitSig.ToSignature() commitSig, err := msg.CommitSig.ToSignature()
if err != nil { if err != nil {
fndgLog.Errorf("unable to parse signature: %v", err) log.Errorf("unable to parse signature: %v", err)
f.failFundingFlow(peer, pendingChanID, err) f.failFundingFlow(peer, pendingChanID, err)
return return
} }
@ -1852,7 +1846,7 @@ func (f *fundingManager) handleFundingCreated(peer lnpeer.Peer,
) )
if err != nil { if err != nil {
// TODO(roasbeef): better error logging: peerID, channelID, etc. // TODO(roasbeef): better error logging: peerID, channelID, etc.
fndgLog.Errorf("unable to complete single reservation: %v", err) log.Errorf("unable to complete single reservation: %v", err)
f.failFundingFlow(peer, pendingChanID, err) f.failFundingFlow(peer, pendingChanID, err)
return return
} }
@ -1883,7 +1877,7 @@ func (f *fundingManager) handleFundingCreated(peer lnpeer.Peer,
if err := completeChan.CloseChannel( if err := completeChan.CloseChannel(
closeInfo, channeldb.ChanStatusLocalCloseInitiator, closeInfo, channeldb.ChanStatusLocalCloseInitiator,
); err != nil { ); err != nil {
fndgLog.Errorf("Failed closing channel %v: %v", log.Errorf("Failed closing channel %v: %v",
completeChan.FundingOutpoint, err) completeChan.FundingOutpoint, err)
} }
} }
@ -1894,11 +1888,11 @@ func (f *fundingManager) handleFundingCreated(peer lnpeer.Peer,
// fully open. // fully open.
f.barrierMtx.Lock() f.barrierMtx.Lock()
channelID := lnwire.NewChanIDFromOutPoint(&fundingOut) channelID := lnwire.NewChanIDFromOutPoint(&fundingOut)
fndgLog.Debugf("Creating chan barrier for ChanID(%v)", channelID) log.Debugf("Creating chan barrier for ChanID(%v)", channelID)
f.newChanBarriers[channelID] = make(chan struct{}) f.newChanBarriers[channelID] = make(chan struct{})
f.barrierMtx.Unlock() f.barrierMtx.Unlock()
fndgLog.Infof("sending FundingSigned for pending_id(%x) over "+ log.Infof("sending FundingSigned for pending_id(%x) over "+
"ChannelPoint(%v)", pendingChanID[:], fundingOut) "ChannelPoint(%v)", pendingChanID[:], fundingOut)
// With their signature for our version of the commitment transaction // With their signature for our version of the commitment transaction
@ -1906,7 +1900,7 @@ func (f *fundingManager) handleFundingCreated(peer lnpeer.Peer,
_, sig := resCtx.reservation.OurSignatures() _, sig := resCtx.reservation.OurSignatures()
ourCommitSig, err := lnwire.NewSigFromSignature(sig) ourCommitSig, err := lnwire.NewSigFromSignature(sig)
if err != nil { if err != nil {
fndgLog.Errorf("unable to parse signature: %v", err) log.Errorf("unable to parse signature: %v", err)
f.failFundingFlow(peer, pendingChanID, err) f.failFundingFlow(peer, pendingChanID, err)
deleteFromDatabase() deleteFromDatabase()
return return
@ -1917,7 +1911,7 @@ func (f *fundingManager) handleFundingCreated(peer lnpeer.Peer,
CommitSig: ourCommitSig, CommitSig: ourCommitSig,
} }
if err := peer.SendMessage(true, fundingSigned); err != nil { if err := peer.SendMessage(true, fundingSigned); err != nil {
fndgLog.Errorf("unable to send FundingSigned message: %v", err) log.Errorf("unable to send FundingSigned message: %v", err)
f.failFundingFlow(peer, pendingChanID, err) f.failFundingFlow(peer, pendingChanID, err)
deleteFromDatabase() deleteFromDatabase()
return return
@ -1927,7 +1921,7 @@ func (f *fundingManager) handleFundingCreated(peer lnpeer.Peer,
// send it to the ChainArbitrator so it can watch for any on-chain // send it to the ChainArbitrator so it can watch for any on-chain
// actions during this final confirmation stage. // actions during this final confirmation stage.
if err := f.cfg.WatchNewChannel(completeChan, peerKey); err != nil { if err := f.cfg.WatchNewChannel(completeChan, peerKey); err != nil {
fndgLog.Errorf("Unable to send new ChannelPoint(%v) for "+ log.Errorf("Unable to send new ChannelPoint(%v) for "+
"arbitration: %v", fundingOut, err) "arbitration: %v", fundingOut, err)
} }
@ -1967,7 +1961,7 @@ func (f *fundingManager) handleFundingCreated(peer lnpeer.Peer,
// broadcast. Once the funding transaction reaches a sufficient number of // broadcast. Once the funding transaction reaches a sufficient number of
// confirmations, a message is sent to the responding peer along with a compact // confirmations, a message is sent to the responding peer along with a compact
// encoding of the location of the channel within the blockchain. // encoding of the location of the channel within the blockchain.
func (f *fundingManager) handleFundingSigned(peer lnpeer.Peer, func (f *Manager) handleFundingSigned(peer lnpeer.Peer,
msg *lnwire.FundingSigned) { msg *lnwire.FundingSigned) {
// As the funding signed message will reference the reservation by its // As the funding signed message will reference the reservation by its
@ -1980,7 +1974,7 @@ func (f *fundingManager) handleFundingSigned(peer lnpeer.Peer,
if !ok { if !ok {
err := fmt.Errorf("unable to find signed reservation for "+ err := fmt.Errorf("unable to find signed reservation for "+
"chan_id=%x", msg.ChanID) "chan_id=%x", msg.ChanID)
fndgLog.Warnf(err.Error()) log.Warnf(err.Error())
f.failFundingFlow(peer, msg.ChanID, err) f.failFundingFlow(peer, msg.ChanID, err)
return return
} }
@ -1988,7 +1982,7 @@ func (f *fundingManager) handleFundingSigned(peer lnpeer.Peer,
peerKey := peer.IdentityKey() peerKey := peer.IdentityKey()
resCtx, err := f.getReservationCtx(peerKey, pendingChanID) resCtx, err := f.getReservationCtx(peerKey, pendingChanID)
if err != nil { if err != nil {
fndgLog.Warnf("Unable to find reservation (peer_id:%v, "+ log.Warnf("Unable to find reservation (peer_id:%v, "+
"chan_id:%x)", peerKey, pendingChanID[:]) "chan_id:%x)", peerKey, pendingChanID[:])
// TODO: add ErrChanNotFound? // TODO: add ErrChanNotFound?
f.failFundingFlow(peer, pendingChanID, err) f.failFundingFlow(peer, pendingChanID, err)
@ -2009,7 +2003,7 @@ func (f *fundingManager) handleFundingSigned(peer lnpeer.Peer,
// the state to disk as we can now open the channel. // the state to disk as we can now open the channel.
commitSig, err := msg.CommitSig.ToSignature() commitSig, err := msg.CommitSig.ToSignature()
if err != nil { if err != nil {
fndgLog.Errorf("Unable to parse signature: %v", err) log.Errorf("Unable to parse signature: %v", err)
f.failFundingFlow(peer, pendingChanID, err) f.failFundingFlow(peer, pendingChanID, err)
return return
} }
@ -2018,7 +2012,7 @@ func (f *fundingManager) handleFundingSigned(peer lnpeer.Peer,
nil, commitSig, nil, commitSig,
) )
if err != nil { if err != nil {
fndgLog.Errorf("Unable to complete reservation sign "+ log.Errorf("Unable to complete reservation sign "+
"complete: %v", err) "complete: %v", err)
f.failFundingFlow(peer, pendingChanID, err) f.failFundingFlow(peer, pendingChanID, err)
return return
@ -2034,7 +2028,7 @@ func (f *fundingManager) handleFundingSigned(peer lnpeer.Peer,
fundingTx := completeChan.FundingTxn fundingTx := completeChan.FundingTxn
var fundingTxBuf bytes.Buffer var fundingTxBuf bytes.Buffer
if err := fundingTx.Serialize(&fundingTxBuf); err != nil { if err := fundingTx.Serialize(&fundingTxBuf); err != nil {
fndgLog.Errorf("Unable to serialize funding "+ log.Errorf("Unable to serialize funding "+
"transaction %v: %v", fundingTx.TxHash(), err) "transaction %v: %v", fundingTx.TxHash(), err)
// Clear the buffer of any bytes that were written // Clear the buffer of any bytes that were written
@ -2043,7 +2037,7 @@ func (f *fundingManager) handleFundingSigned(peer lnpeer.Peer,
fundingTxBuf.Reset() fundingTxBuf.Reset()
} }
fndgLog.Infof("Broadcasting funding tx for ChannelPoint(%v): %x", log.Infof("Broadcasting funding tx for ChannelPoint(%v): %x",
completeChan.FundingOutpoint, fundingTxBuf.Bytes()) completeChan.FundingOutpoint, fundingTxBuf.Bytes())
// Set a nil short channel ID at this stage because we do not // Set a nil short channel ID at this stage because we do not
@ -2054,7 +2048,7 @@ func (f *fundingManager) handleFundingSigned(peer lnpeer.Peer,
err = f.cfg.PublishTransaction(fundingTx, label) err = f.cfg.PublishTransaction(fundingTx, label)
if err != nil { if err != nil {
fndgLog.Errorf("Unable to broadcast funding tx %x for "+ log.Errorf("Unable to broadcast funding tx %x for "+
"ChannelPoint(%v): %v", fundingTxBuf.Bytes(), "ChannelPoint(%v): %v", fundingTxBuf.Bytes(),
completeChan.FundingOutpoint, err) completeChan.FundingOutpoint, err)
@ -2073,11 +2067,11 @@ func (f *fundingManager) handleFundingSigned(peer lnpeer.Peer,
// watch for any on-chain actions before the channel has fully // watch for any on-chain actions before the channel has fully
// confirmed. // confirmed.
if err := f.cfg.WatchNewChannel(completeChan, peerKey); err != nil { if err := f.cfg.WatchNewChannel(completeChan, peerKey); err != nil {
fndgLog.Errorf("Unable to send new ChannelPoint(%v) for "+ log.Errorf("Unable to send new ChannelPoint(%v) for "+
"arbitration: %v", fundingPoint, err) "arbitration: %v", fundingPoint, err)
} }
fndgLog.Infof("Finalizing pending_id(%x) over ChannelPoint(%v), "+ log.Infof("Finalizing pending_id(%x) over ChannelPoint(%v), "+
"waiting for channel open on-chain", pendingChanID[:], "waiting for channel open on-chain", pendingChanID[:],
fundingPoint) fundingPoint)
@ -2129,7 +2123,7 @@ type confirmedChannel struct {
// channel initiator and the maxWaitNumBlocksFundingConf has passed from the // channel initiator and the maxWaitNumBlocksFundingConf has passed from the
// funding broadcast height. In case of confirmation, the short channel ID of // funding broadcast height. In case of confirmation, the short channel ID of
// the channel and the funding transaction will be returned. // the channel and the funding transaction will be returned.
func (f *fundingManager) waitForFundingWithTimeout( func (f *Manager) waitForFundingWithTimeout(
ch *channeldb.OpenChannel) (*confirmedChannel, error) { ch *channeldb.OpenChannel) (*confirmedChannel, error) {
confChan := make(chan *confirmedChannel) confChan := make(chan *confirmedChannel)
@ -2192,7 +2186,7 @@ func makeFundingScript(channel *channeldb.OpenChannel) ([]byte, error) {
// a *lnwire.ShortChannelID will be passed to confChan. // a *lnwire.ShortChannelID will be passed to confChan.
// //
// NOTE: This MUST be run as a goroutine. // NOTE: This MUST be run as a goroutine.
func (f *fundingManager) waitForFundingConfirmation( func (f *Manager) waitForFundingConfirmation(
completeChan *channeldb.OpenChannel, cancelChan <-chan struct{}, completeChan *channeldb.OpenChannel, cancelChan <-chan struct{},
confChan chan<- *confirmedChannel) { confChan chan<- *confirmedChannel) {
@ -2204,7 +2198,7 @@ func (f *fundingManager) waitForFundingConfirmation(
txid := completeChan.FundingOutpoint.Hash txid := completeChan.FundingOutpoint.Hash
fundingScript, err := makeFundingScript(completeChan) fundingScript, err := makeFundingScript(completeChan)
if err != nil { if err != nil {
fndgLog.Errorf("unable to create funding script for "+ log.Errorf("unable to create funding script for "+
"ChannelPoint(%v): %v", completeChan.FundingOutpoint, "ChannelPoint(%v): %v", completeChan.FundingOutpoint,
err) err)
return return
@ -2215,13 +2209,13 @@ func (f *fundingManager) waitForFundingConfirmation(
completeChan.FundingBroadcastHeight, completeChan.FundingBroadcastHeight,
) )
if err != nil { if err != nil {
fndgLog.Errorf("Unable to register for confirmation of "+ log.Errorf("Unable to register for confirmation of "+
"ChannelPoint(%v): %v", completeChan.FundingOutpoint, "ChannelPoint(%v): %v", completeChan.FundingOutpoint,
err) err)
return return
} }
fndgLog.Infof("Waiting for funding tx (%v) to reach %v confirmations", log.Infof("Waiting for funding tx (%v) to reach %v confirmations",
txid, numConfs) txid, numConfs)
var confDetails *chainntnfs.TxConfirmation var confDetails *chainntnfs.TxConfirmation
@ -2234,27 +2228,27 @@ func (f *fundingManager) waitForFundingConfirmation(
// fallthrough // fallthrough
case <-cancelChan: case <-cancelChan:
fndgLog.Warnf("canceled waiting for funding confirmation, "+ log.Warnf("canceled waiting for funding confirmation, "+
"stopping funding flow for ChannelPoint(%v)", "stopping funding flow for ChannelPoint(%v)",
completeChan.FundingOutpoint) completeChan.FundingOutpoint)
return return
case <-f.quit: case <-f.quit:
fndgLog.Warnf("fundingManager shutting down, stopping funding "+ log.Warnf("fundingManager shutting down, stopping funding "+
"flow for ChannelPoint(%v)", "flow for ChannelPoint(%v)",
completeChan.FundingOutpoint) completeChan.FundingOutpoint)
return return
} }
if !ok { if !ok {
fndgLog.Warnf("ChainNotifier shutting down, cannot complete "+ log.Warnf("ChainNotifier shutting down, cannot complete "+
"funding flow for ChannelPoint(%v)", "funding flow for ChannelPoint(%v)",
completeChan.FundingOutpoint) completeChan.FundingOutpoint)
return return
} }
fundingPoint := completeChan.FundingOutpoint fundingPoint := completeChan.FundingOutpoint
fndgLog.Infof("ChannelPoint(%v) is now active: ChannelID(%v)", log.Infof("ChannelPoint(%v) is now active: ChannelID(%v)",
fundingPoint, lnwire.NewChanIDFromOutPoint(&fundingPoint)) fundingPoint, lnwire.NewChanIDFromOutPoint(&fundingPoint))
// With the block height and the transaction index known, we can // With the block height and the transaction index known, we can
@ -2283,7 +2277,7 @@ func (f *fundingManager) waitForFundingConfirmation(
// //
// NOTE: timeoutChan MUST be buffered. // NOTE: timeoutChan MUST be buffered.
// NOTE: This MUST be run as a goroutine. // NOTE: This MUST be run as a goroutine.
func (f *fundingManager) waitForTimeout(completeChan *channeldb.OpenChannel, func (f *Manager) waitForTimeout(completeChan *channeldb.OpenChannel,
cancelChan <-chan struct{}, timeoutChan chan<- error) { cancelChan <-chan struct{}, timeoutChan chan<- error) {
defer f.wg.Done() defer f.wg.Done()
@ -2310,7 +2304,7 @@ func (f *fundingManager) waitForTimeout(completeChan *channeldb.OpenChannel,
// Close the timeout channel and exit if the block is // Close the timeout channel and exit if the block is
// aboce the max height. // aboce the max height.
if uint32(epoch.Height) >= maxHeight { if uint32(epoch.Height) >= maxHeight {
fndgLog.Warnf("Waited for %v blocks without "+ log.Warnf("Waited for %v blocks without "+
"seeing funding transaction confirmed,"+ "seeing funding transaction confirmed,"+
" cancelling.", " cancelling.",
maxWaitNumBlocksFundingConf) maxWaitNumBlocksFundingConf)
@ -2339,7 +2333,7 @@ func (f *fundingManager) waitForTimeout(completeChan *channeldb.OpenChannel,
// the channelOpeningState markedOpen. In addition it will report the now // the channelOpeningState markedOpen. In addition it will report the now
// decided short channel ID to the switch, and close the local discovery signal // decided short channel ID to the switch, and close the local discovery signal
// for this channel. // for this channel.
func (f *fundingManager) handleFundingConfirmation( func (f *Manager) handleFundingConfirmation(
completeChan *channeldb.OpenChannel, completeChan *channeldb.OpenChannel,
confChannel *confirmedChannel) error { confChannel *confirmedChannel) error {
@ -2389,7 +2383,7 @@ func (f *fundingManager) handleFundingConfirmation(
// short chan id from disk. // short chan id from disk.
err = f.cfg.ReportShortChanID(fundingPoint) err = f.cfg.ReportShortChanID(fundingPoint)
if err != nil { if err != nil {
fndgLog.Errorf("unable to report short chan id: %v", err) log.Errorf("unable to report short chan id: %v", err)
} }
// If we opened the channel, and lnd's wallet published our funding tx // If we opened the channel, and lnd's wallet published our funding tx
@ -2407,7 +2401,7 @@ func (f *fundingManager) handleFundingConfirmation(
completeChan.FundingOutpoint.Hash, label, completeChan.FundingOutpoint.Hash, label,
) )
if err != nil { if err != nil {
fndgLog.Errorf("unable to update label: %v", err) log.Errorf("unable to update label: %v", err)
} }
} }
@ -2427,7 +2421,7 @@ func (f *fundingManager) handleFundingConfirmation(
// sendFundingLocked creates and sends the fundingLocked message. // sendFundingLocked creates and sends the fundingLocked message.
// This should be called after the funding transaction has been confirmed, // This should be called after the funding transaction has been confirmed,
// and the channelState is 'markedOpen'. // and the channelState is 'markedOpen'.
func (f *fundingManager) sendFundingLocked( func (f *Manager) sendFundingLocked(
completeChan *channeldb.OpenChannel, channel *lnwallet.LightningChannel, completeChan *channeldb.OpenChannel, channel *lnwallet.LightningChannel,
shortChanID *lnwire.ShortChannelID) error { shortChanID *lnwire.ShortChannelID) error {
@ -2468,7 +2462,7 @@ func (f *fundingManager) sendFundingLocked(
return ErrFundingManagerShuttingDown return ErrFundingManagerShuttingDown
} }
fndgLog.Infof("Peer(%x) is online, sending FundingLocked "+ log.Infof("Peer(%x) is online, sending FundingLocked "+
"for ChannelID(%v)", peerKey, chanID) "for ChannelID(%v)", peerKey, chanID)
if err := peer.SendMessage(true, fundingLockedMsg); err == nil { if err := peer.SendMessage(true, fundingLockedMsg); err == nil {
@ -2477,7 +2471,7 @@ func (f *fundingManager) sendFundingLocked(
break break
} }
fndgLog.Warnf("Unable to send fundingLocked to peer %x: %v. "+ log.Warnf("Unable to send fundingLocked to peer %x: %v. "+
"Will retry when online", peerKey, err) "Will retry when online", peerKey, err)
} }
@ -2489,7 +2483,7 @@ func (f *fundingManager) sendFundingLocked(
// These announcement messages are NOT broadcasted to the greater network, // These announcement messages are NOT broadcasted to the greater network,
// only to the channel counter party. The proofs required to announce the // only to the channel counter party. The proofs required to announce the
// channel to the greater network will be created and sent in annAfterSixConfs. // channel to the greater network will be created and sent in annAfterSixConfs.
func (f *fundingManager) addToRouterGraph(completeChan *channeldb.OpenChannel, func (f *Manager) addToRouterGraph(completeChan *channeldb.OpenChannel,
shortChanID *lnwire.ShortChannelID) error { shortChanID *lnwire.ShortChannelID) error {
chanID := lnwire.NewChanIDFromOutPoint(&completeChan.FundingOutpoint) chanID := lnwire.NewChanIDFromOutPoint(&completeChan.FundingOutpoint)
@ -2537,7 +2531,7 @@ func (f *fundingManager) addToRouterGraph(completeChan *channeldb.OpenChannel,
if err != nil { if err != nil {
if routing.IsError(err, routing.ErrOutdated, if routing.IsError(err, routing.ErrOutdated,
routing.ErrIgnored) { routing.ErrIgnored) {
fndgLog.Debugf("Router rejected "+ log.Debugf("Router rejected "+
"ChannelAnnouncement: %v", err) "ChannelAnnouncement: %v", err)
} else { } else {
return fmt.Errorf("error sending channel "+ return fmt.Errorf("error sending channel "+
@ -2554,7 +2548,7 @@ func (f *fundingManager) addToRouterGraph(completeChan *channeldb.OpenChannel,
if err != nil { if err != nil {
if routing.IsError(err, routing.ErrOutdated, if routing.IsError(err, routing.ErrOutdated,
routing.ErrIgnored) { routing.ErrIgnored) {
fndgLog.Debugf("Router rejected "+ log.Debugf("Router rejected "+
"ChannelUpdate: %v", err) "ChannelUpdate: %v", err)
} else { } else {
return fmt.Errorf("error sending channel "+ return fmt.Errorf("error sending channel "+
@ -2574,7 +2568,7 @@ func (f *fundingManager) addToRouterGraph(completeChan *channeldb.OpenChannel,
// 'addedToRouterGraph') and the channel is ready to be used. This is the last // 'addedToRouterGraph') and the channel is ready to be used. This is the last
// step in the channel opening process, and the opening state will be deleted // step in the channel opening process, and the opening state will be deleted
// from the database if successful. // from the database if successful.
func (f *fundingManager) annAfterSixConfs(completeChan *channeldb.OpenChannel, func (f *Manager) annAfterSixConfs(completeChan *channeldb.OpenChannel,
shortChanID *lnwire.ShortChannelID) error { shortChanID *lnwire.ShortChannelID) error {
// If this channel is not meant to be announced to the greater network, // If this channel is not meant to be announced to the greater network,
@ -2582,7 +2576,7 @@ func (f *fundingManager) annAfterSixConfs(completeChan *channeldb.OpenChannel,
// don't leak any of our information. // don't leak any of our information.
announceChan := completeChan.ChannelFlags&lnwire.FFAnnounceChannel != 0 announceChan := completeChan.ChannelFlags&lnwire.FFAnnounceChannel != 0
if !announceChan { if !announceChan {
fndgLog.Debugf("Will not announce private channel %v.", log.Debugf("Will not announce private channel %v.",
shortChanID.ToUint64()) shortChanID.ToUint64())
peerChan := make(chan lnpeer.Peer, 1) peerChan := make(chan lnpeer.Peer, 1)
@ -2609,7 +2603,7 @@ func (f *fundingManager) annAfterSixConfs(completeChan *channeldb.OpenChannel,
&completeChan.FundingOutpoint, &completeChan.FundingOutpoint,
) )
pubKey := peer.PubKey() pubKey := peer.PubKey()
fndgLog.Debugf("Sending our NodeAnnouncement for "+ log.Debugf("Sending our NodeAnnouncement for "+
"ChannelID(%v) to %x", chanID, pubKey) "ChannelID(%v) to %x", chanID, pubKey)
// TODO(halseth): make reliable. If the peer is not online this // TODO(halseth): make reliable. If the peer is not online this
@ -2627,7 +2621,7 @@ func (f *fundingManager) annAfterSixConfs(completeChan *channeldb.OpenChannel,
numConfs = 6 numConfs = 6
} }
txid := completeChan.FundingOutpoint.Hash txid := completeChan.FundingOutpoint.Hash
fndgLog.Debugf("Will announce channel %v after ChannelPoint"+ log.Debugf("Will announce channel %v after ChannelPoint"+
"(%v) has gotten %d confirmations", "(%v) has gotten %d confirmations",
shortChanID.ToUint64(), completeChan.FundingOutpoint, shortChanID.ToUint64(), completeChan.FundingOutpoint,
numConfs) numConfs)
@ -2673,7 +2667,7 @@ func (f *fundingManager) annAfterSixConfs(completeChan *channeldb.OpenChannel,
fundingPoint := completeChan.FundingOutpoint fundingPoint := completeChan.FundingOutpoint
chanID := lnwire.NewChanIDFromOutPoint(&fundingPoint) chanID := lnwire.NewChanIDFromOutPoint(&fundingPoint)
fndgLog.Infof("Announcing ChannelPoint(%v), short_chan_id=%v", log.Infof("Announcing ChannelPoint(%v), short_chan_id=%v",
&fundingPoint, shortChanID) &fundingPoint, shortChanID)
// Create and broadcast the proofs required to make this channel // Create and broadcast the proofs required to make this channel
@ -2688,7 +2682,7 @@ func (f *fundingManager) annAfterSixConfs(completeChan *channeldb.OpenChannel,
return fmt.Errorf("channel announcement failed: %v", err) return fmt.Errorf("channel announcement failed: %v", err)
} }
fndgLog.Debugf("Channel with ChannelPoint(%v), short_chan_id=%v "+ log.Debugf("Channel with ChannelPoint(%v), short_chan_id=%v "+
"announced", &fundingPoint, shortChanID) "announced", &fundingPoint, shortChanID)
} }
@ -2697,11 +2691,11 @@ func (f *fundingManager) annAfterSixConfs(completeChan *channeldb.OpenChannel,
// handleFundingLocked finalizes the channel funding process and enables the // handleFundingLocked finalizes the channel funding process and enables the
// channel to enter normal operating mode. // channel to enter normal operating mode.
func (f *fundingManager) handleFundingLocked(peer lnpeer.Peer, func (f *Manager) handleFundingLocked(peer lnpeer.Peer,
msg *lnwire.FundingLocked) { msg *lnwire.FundingLocked) {
defer f.wg.Done() defer f.wg.Done()
fndgLog.Debugf("Received FundingLocked for ChannelID(%v) from "+ log.Debugf("Received FundingLocked for ChannelID(%v) from "+
"peer %x", msg.ChanID, "peer %x", msg.ChanID,
peer.IdentityKey().SerializeCompressed()) peer.IdentityKey().SerializeCompressed())
@ -2710,7 +2704,7 @@ func (f *fundingManager) handleFundingLocked(peer lnpeer.Peer,
f.handleFundingLockedMtx.Lock() f.handleFundingLockedMtx.Lock()
_, ok := f.handleFundingLockedBarriers[msg.ChanID] _, ok := f.handleFundingLockedBarriers[msg.ChanID]
if ok { if ok {
fndgLog.Infof("Already handling fundingLocked for "+ log.Infof("Already handling fundingLocked for "+
"ChannelID(%v), ignoring.", msg.ChanID) "ChannelID(%v), ignoring.", msg.ChanID)
f.handleFundingLockedMtx.Unlock() f.handleFundingLockedMtx.Unlock()
return return
@ -2757,7 +2751,7 @@ func (f *fundingManager) handleFundingLocked(peer lnpeer.Peer,
chanID := msg.ChanID chanID := msg.ChanID
channel, err := f.cfg.FindChannel(chanID) channel, err := f.cfg.FindChannel(chanID)
if err != nil { if err != nil {
fndgLog.Errorf("Unable to locate ChannelID(%v), cannot complete "+ log.Errorf("Unable to locate ChannelID(%v), cannot complete "+
"funding", chanID) "funding", chanID)
return return
} }
@ -2765,7 +2759,7 @@ func (f *fundingManager) handleFundingLocked(peer lnpeer.Peer,
// If the RemoteNextRevocation is non-nil, it means that we have // If the RemoteNextRevocation is non-nil, it means that we have
// already processed fundingLocked for this channel, so ignore. // already processed fundingLocked for this channel, so ignore.
if channel.RemoteNextRevocation != nil { if channel.RemoteNextRevocation != nil {
fndgLog.Infof("Received duplicate fundingLocked for "+ log.Infof("Received duplicate fundingLocked for "+
"ChannelID(%v), ignoring.", chanID) "ChannelID(%v), ignoring.", chanID)
return return
} }
@ -2776,7 +2770,7 @@ func (f *fundingManager) handleFundingLocked(peer lnpeer.Peer,
// other sub-systems. // other sub-systems.
err = channel.InsertNextRevocation(msg.NextPerCommitmentPoint) err = channel.InsertNextRevocation(msg.NextPerCommitmentPoint)
if err != nil { if err != nil {
fndgLog.Errorf("unable to insert next commitment point: %v", err) log.Errorf("unable to insert next commitment point: %v", err)
return return
} }
@ -2789,7 +2783,7 @@ func (f *fundingManager) handleFundingLocked(peer lnpeer.Peer,
f.barrierMtx.Lock() f.barrierMtx.Lock()
chanBarrier, ok := f.newChanBarriers[chanID] chanBarrier, ok := f.newChanBarriers[chanID]
if ok { if ok {
fndgLog.Tracef("Closing chan barrier for ChanID(%v)", log.Tracef("Closing chan barrier for ChanID(%v)",
chanID) chanID)
close(chanBarrier) close(chanBarrier)
delete(f.newChanBarriers, chanID) delete(f.newChanBarriers, chanID)
@ -2798,7 +2792,7 @@ func (f *fundingManager) handleFundingLocked(peer lnpeer.Peer,
}() }()
if err := peer.AddNewChannel(channel, f.quit); err != nil { if err := peer.AddNewChannel(channel, f.quit); err != nil {
fndgLog.Errorf("Unable to add new channel %v with peer %x: %v", log.Errorf("Unable to add new channel %v with peer %x: %v",
channel.FundingOutpoint, channel.FundingOutpoint,
peer.IdentityKey().SerializeCompressed(), err, peer.IdentityKey().SerializeCompressed(), err,
) )
@ -2820,7 +2814,7 @@ type chanAnnouncement struct {
// identity pub keys of both parties to the channel, and the second segment is // identity pub keys of both parties to the channel, and the second segment is
// authenticated only by us and contains our directional routing policy for the // authenticated only by us and contains our directional routing policy for the
// channel. // channel.
func (f *fundingManager) newChanAnnouncement(localPubKey, remotePubKey, func (f *Manager) newChanAnnouncement(localPubKey, remotePubKey,
localFundingKey, remoteFundingKey *btcec.PublicKey, localFundingKey, remoteFundingKey *btcec.PublicKey,
shortChanID lnwire.ShortChannelID, chanID lnwire.ChannelID, shortChanID lnwire.ShortChannelID, chanID lnwire.ChannelID,
fwdMinHTLC, fwdMaxHTLC lnwire.MilliSatoshi) (*chanAnnouncement, error) { fwdMinHTLC, fwdMaxHTLC lnwire.MilliSatoshi) (*chanAnnouncement, error) {
@ -2963,7 +2957,7 @@ func (f *fundingManager) newChanAnnouncement(localPubKey, remotePubKey,
// the network during its next trickle. // the network during its next trickle.
// This method is synchronous and will return when all the network requests // This method is synchronous and will return when all the network requests
// finish, either successfully or with an error. // finish, either successfully or with an error.
func (f *fundingManager) announceChannel(localIDKey, remoteIDKey, localFundingKey, func (f *Manager) announceChannel(localIDKey, remoteIDKey, localFundingKey,
remoteFundingKey *btcec.PublicKey, shortChanID lnwire.ShortChannelID, remoteFundingKey *btcec.PublicKey, shortChanID lnwire.ShortChannelID,
chanID lnwire.ChannelID) error { chanID lnwire.ChannelID) error {
@ -2979,7 +2973,7 @@ func (f *fundingManager) announceChannel(localIDKey, remoteIDKey, localFundingKe
0, 0, 0, 0,
) )
if err != nil { if err != nil {
fndgLog.Errorf("can't generate channel announcement: %v", err) log.Errorf("can't generate channel announcement: %v", err)
return err return err
} }
@ -2993,10 +2987,10 @@ func (f *fundingManager) announceChannel(localIDKey, remoteIDKey, localFundingKe
if err != nil { if err != nil {
if routing.IsError(err, routing.ErrOutdated, if routing.IsError(err, routing.ErrOutdated,
routing.ErrIgnored) { routing.ErrIgnored) {
fndgLog.Debugf("Router rejected "+ log.Debugf("Router rejected "+
"AnnounceSignatures: %v", err) "AnnounceSignatures: %v", err)
} else { } else {
fndgLog.Errorf("Unable to send channel "+ log.Errorf("Unable to send channel "+
"proof: %v", err) "proof: %v", err)
return err return err
} }
@ -3012,7 +3006,7 @@ func (f *fundingManager) announceChannel(localIDKey, remoteIDKey, localFundingKe
// particular node, and this might be our first channel. // particular node, and this might be our first channel.
nodeAnn, err := f.cfg.CurrentNodeAnnouncement() nodeAnn, err := f.cfg.CurrentNodeAnnouncement()
if err != nil { if err != nil {
fndgLog.Errorf("can't generate node announcement: %v", err) log.Errorf("can't generate node announcement: %v", err)
return err return err
} }
@ -3022,10 +3016,10 @@ func (f *fundingManager) announceChannel(localIDKey, remoteIDKey, localFundingKe
if err != nil { if err != nil {
if routing.IsError(err, routing.ErrOutdated, if routing.IsError(err, routing.ErrOutdated,
routing.ErrIgnored) { routing.ErrIgnored) {
fndgLog.Debugf("Router rejected "+ log.Debugf("Router rejected "+
"NodeAnnouncement: %v", err) "NodeAnnouncement: %v", err)
} else { } else {
fndgLog.Errorf("Unable to send node "+ log.Errorf("Unable to send node "+
"announcement: %v", err) "announcement: %v", err)
return err return err
} }
@ -3038,14 +3032,11 @@ func (f *fundingManager) announceChannel(localIDKey, remoteIDKey, localFundingKe
return nil return nil
} }
// initFundingWorkflow sends a message to the funding manager instructing it // InitFundingWorkflow sends a message to the funding manager instructing it
// to initiate a single funder workflow with the source peer. // to initiate a single funder workflow with the source peer.
// TODO(roasbeef): re-visit blocking nature.. // TODO(roasbeef): re-visit blocking nature..
func (f *fundingManager) initFundingWorkflow(peer lnpeer.Peer, req *openChanReq) { func (f *Manager) InitFundingWorkflow(msg *InitFundingMsg) {
f.fundingRequests <- &initFundingMsg{ f.fundingRequests <- msg
peer: peer,
openChanReq: req,
}
} }
// getUpfrontShutdownScript takes a user provided script and a getScript // getUpfrontShutdownScript takes a user provided script and a getScript
@ -3095,15 +3086,15 @@ func getUpfrontShutdownScript(enableUpfrontShutdown bool, peer lnpeer.Peer,
// handleInitFundingMsg creates a channel reservation within the daemon's // handleInitFundingMsg creates a channel reservation within the daemon's
// wallet, then sends a funding request to the remote peer kicking off the // wallet, then sends a funding request to the remote peer kicking off the
// funding workflow. // funding workflow.
func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) { func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
var ( var (
peerKey = msg.peer.IdentityKey() peerKey = msg.Peer.IdentityKey()
localAmt = msg.localFundingAmt localAmt = msg.LocalFundingAmt
minHtlcIn = msg.minHtlcIn minHtlcIn = msg.MinHtlcIn
remoteCsvDelay = msg.remoteCsvDelay remoteCsvDelay = msg.RemoteCsvDelay
maxValue = msg.maxValueInFlight maxValue = msg.MaxValueInFlight
maxHtlcs = msg.maxHtlcs maxHtlcs = msg.MaxHtlcs
maxCSV = msg.maxLocalCsv maxCSV = msg.MaxLocalCsv
) )
// If no maximum CSV delay was set for this channel, we use our default // If no maximum CSV delay was set for this channel, we use our default
@ -3120,16 +3111,16 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
case chainreg.LitecoinChain: case chainreg.LitecoinChain:
ourDustLimit = chainreg.DefaultLitecoinDustLimit ourDustLimit = chainreg.DefaultLitecoinDustLimit
} }
fndgLog.Infof("Initiating fundingRequest(local_amt=%v "+ log.Infof("Initiating fundingRequest(local_amt=%v "+
"(subtract_fees=%v), push_amt=%v, chain_hash=%v, peer=%x, "+ "(subtract_fees=%v), push_amt=%v, chain_hash=%v, peer=%x, "+
"dust_limit=%v, min_confs=%v)", localAmt, msg.subtractFees, "dust_limit=%v, min_confs=%v)", localAmt, msg.SubtractFees,
msg.pushAmt, msg.chainHash, peerKey.SerializeCompressed(), msg.PushAmt, msg.ChainHash, peerKey.SerializeCompressed(),
ourDustLimit, msg.minConfs) ourDustLimit, msg.MinConfs)
// We set the channel flags to indicate whether we want this channel to // We set the channel flags to indicate whether we want this channel to
// be announced to the network. // be announced to the network.
var channelFlags lnwire.FundingFlag var channelFlags lnwire.FundingFlag
if !msg.openChanReq.private { if !msg.Private {
// This channel will be announced. // This channel will be announced.
channelFlags = lnwire.FFAnnounceChannel channelFlags = lnwire.FFAnnounceChannel
} }
@ -3138,15 +3129,15 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
// Otherwise we'll generate a fresh one as normal. This will be used // Otherwise we'll generate a fresh one as normal. This will be used
// to track this reservation throughout its lifetime. // to track this reservation throughout its lifetime.
var chanID [32]byte var chanID [32]byte
if msg.pendingChanID == zeroID { if msg.PendingChanID == zeroID {
chanID = f.nextPendingChanID() chanID = f.nextPendingChanID()
} else { } else {
// If the user specified their own pending channel ID, then // If the user specified their own pending channel ID, then
// we'll ensure it doesn't collide with any existing pending // we'll ensure it doesn't collide with any existing pending
// channel ID. // channel ID.
chanID = msg.pendingChanID chanID = msg.PendingChanID
if _, err := f.getReservationCtx(peerKey, chanID); err == nil { if _, err := f.getReservationCtx(peerKey, chanID); err == nil {
msg.err <- fmt.Errorf("pendingChannelID(%x) "+ msg.Err <- fmt.Errorf("pendingChannelID(%x) "+
"already present", chanID[:]) "already present", chanID[:])
return return
} }
@ -3157,8 +3148,8 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
// address from the wallet if our node is configured to set shutdown // address from the wallet if our node is configured to set shutdown
// address by default). // address by default).
shutdown, err := getUpfrontShutdownScript( shutdown, err := getUpfrontShutdownScript(
f.cfg.EnableUpfrontShutdown, msg.peer, f.cfg.EnableUpfrontShutdown, msg.Peer,
msg.openChanReq.shutdownScript, msg.ShutdownScript,
func() (lnwire.DeliveryAddress, error) { func() (lnwire.DeliveryAddress, error) {
addr, err := f.cfg.Wallet.NewAddress( addr, err := f.cfg.Wallet.NewAddress(
lnwallet.WitnessPubKey, false, lnwallet.WitnessPubKey, false,
@ -3170,7 +3161,7 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
}, },
) )
if err != nil { if err != nil {
msg.err <- err msg.Err <- err
return return
} }
@ -3182,7 +3173,7 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
// format we can use with this peer. This is dependent on *both* us and // format we can use with this peer. This is dependent on *both* us and
// the remote peer are signaling the proper feature bit. // the remote peer are signaling the proper feature bit.
commitType := commitmentType( commitType := commitmentType(
msg.peer.LocalFeatures(), msg.peer.RemoteFeatures(), msg.Peer.LocalFeatures(), msg.Peer.RemoteFeatures(),
) )
// First, we'll query the fee estimator for a fee that should get the // First, we'll query the fee estimator for a fee that should get the
@ -3191,7 +3182,7 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
// to execute a timely unilateral channel closure if needed. // to execute a timely unilateral channel closure if needed.
commitFeePerKw, err := f.cfg.FeeEstimator.EstimateFeePerKW(3) commitFeePerKw, err := f.cfg.FeeEstimator.EstimateFeePerKW(3)
if err != nil { if err != nil {
msg.err <- err msg.Err <- err
return return
} }
@ -3204,25 +3195,25 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
} }
req := &lnwallet.InitFundingReserveMsg{ req := &lnwallet.InitFundingReserveMsg{
ChainHash: &msg.chainHash, ChainHash: &msg.ChainHash,
PendingChanID: chanID, PendingChanID: chanID,
NodeID: peerKey, NodeID: peerKey,
NodeAddr: msg.peer.Address(), NodeAddr: msg.Peer.Address(),
SubtractFees: msg.subtractFees, SubtractFees: msg.SubtractFees,
LocalFundingAmt: localAmt, LocalFundingAmt: localAmt,
RemoteFundingAmt: 0, RemoteFundingAmt: 0,
CommitFeePerKw: commitFeePerKw, CommitFeePerKw: commitFeePerKw,
FundingFeePerKw: msg.fundingFeePerKw, FundingFeePerKw: msg.FundingFeePerKw,
PushMSat: msg.pushAmt, PushMSat: msg.PushAmt,
Flags: channelFlags, Flags: channelFlags,
MinConfs: msg.minConfs, MinConfs: msg.MinConfs,
CommitType: commitType, CommitType: commitType,
ChanFunder: msg.chanFunder, ChanFunder: msg.ChanFunder,
} }
reservation, err := f.cfg.Wallet.InitChannelReservation(req) reservation, err := f.cfg.Wallet.InitChannelReservation(req)
if err != nil { if err != nil {
msg.err <- err msg.Err <- err
return return
} }
@ -3235,7 +3226,7 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
// SubtractFees=true. // SubtractFees=true.
capacity := reservation.Capacity() capacity := reservation.Capacity()
fndgLog.Infof("Target commit tx sat/kw for pendingID(%x): %v", chanID, log.Infof("Target commit tx sat/kw for pendingID(%x): %v", chanID,
int64(commitFeePerKw)) int64(commitFeePerKw))
// If the remote CSV delay was not set in the open channel request, // If the remote CSV delay was not set in the open channel request,
@ -3276,14 +3267,14 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
remoteMaxHtlcs: maxHtlcs, remoteMaxHtlcs: maxHtlcs,
maxLocalCsv: maxCSV, maxLocalCsv: maxCSV,
reservation: reservation, reservation: reservation,
peer: msg.peer, peer: msg.Peer,
updates: msg.updates, updates: msg.Updates,
err: msg.err, err: msg.Err,
} }
f.activeReservations[peerIDKey][chanID] = resCtx f.activeReservations[peerIDKey][chanID] = resCtx
f.resMtx.Unlock() f.resMtx.Unlock()
// Update the timestamp once the initFundingMsg has been handled. // Update the timestamp once the InitFundingMsg has been handled.
defer resCtx.updateTimestamp() defer resCtx.updateTimestamp()
// Once the reservation has been created, and indexed, queue a funding // Once the reservation has been created, and indexed, queue a funding
@ -3295,14 +3286,14 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
// remote party. // remote party.
chanReserve := f.cfg.RequiredRemoteChanReserve(capacity, ourDustLimit) chanReserve := f.cfg.RequiredRemoteChanReserve(capacity, ourDustLimit)
fndgLog.Infof("Starting funding workflow with %v for pending_id(%x), "+ log.Infof("Starting funding workflow with %v for pending_id(%x), "+
"committype=%v", msg.peer.Address(), chanID, commitType) "committype=%v", msg.Peer.Address(), chanID, commitType)
fundingOpen := lnwire.OpenChannel{ fundingOpen := lnwire.OpenChannel{
ChainHash: *f.cfg.Wallet.Cfg.NetParams.GenesisHash, ChainHash: *f.cfg.Wallet.Cfg.NetParams.GenesisHash,
PendingChannelID: chanID, PendingChannelID: chanID,
FundingAmount: capacity, FundingAmount: capacity,
PushAmount: msg.pushAmt, PushAmount: msg.PushAmt,
DustLimit: ourContribution.DustLimit, DustLimit: ourContribution.DustLimit,
MaxValueInFlight: maxValue, MaxValueInFlight: maxValue,
ChannelReserve: chanReserve, ChannelReserve: chanReserve,
@ -3319,19 +3310,19 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
ChannelFlags: channelFlags, ChannelFlags: channelFlags,
UpfrontShutdownScript: shutdown, UpfrontShutdownScript: shutdown,
} }
if err := msg.peer.SendMessage(true, &fundingOpen); err != nil { if err := msg.Peer.SendMessage(true, &fundingOpen); err != nil {
e := fmt.Errorf("unable to send funding request message: %v", e := fmt.Errorf("unable to send funding request message: %v",
err) err)
fndgLog.Errorf(e.Error()) log.Errorf(e.Error())
// Since we were unable to send the initial message to the peer // Since we were unable to send the initial message to the peer
// and start the funding flow, we'll cancel this reservation. // and start the funding flow, we'll cancel this reservation.
_, err := f.cancelReservationCtx(peerKey, chanID, false) _, err := f.cancelReservationCtx(peerKey, chanID, false)
if err != nil { if err != nil {
fndgLog.Errorf("unable to cancel reservation: %v", err) log.Errorf("unable to cancel reservation: %v", err)
} }
msg.err <- e msg.Err <- e
return return
} }
} }
@ -3339,7 +3330,7 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
// handleErrorMsg processes the error which was received from remote peer, // handleErrorMsg processes the error which was received from remote peer,
// depending on the type of error we should do different clean up steps and // depending on the type of error we should do different clean up steps and
// inform the user about it. // inform the user about it.
func (f *fundingManager) handleErrorMsg(peer lnpeer.Peer, func (f *Manager) handleErrorMsg(peer lnpeer.Peer,
msg *lnwire.Error) { msg *lnwire.Error) {
chanID := msg.ChanID chanID := msg.ChanID
@ -3350,7 +3341,7 @@ func (f *fundingManager) handleErrorMsg(peer lnpeer.Peer,
// exit early as this was an unwarranted error. // exit early as this was an unwarranted error.
resCtx, err := f.cancelReservationCtx(peerKey, chanID, true) resCtx, err := f.cancelReservationCtx(peerKey, chanID, true)
if err != nil { if err != nil {
fndgLog.Warnf("Received error for non-existent funding "+ log.Warnf("Received error for non-existent funding "+
"flow: %v (%v)", err, msg.Error()) "flow: %v (%v)", err, msg.Error())
return return
} }
@ -3360,7 +3351,7 @@ func (f *fundingManager) handleErrorMsg(peer lnpeer.Peer,
fundingErr := fmt.Errorf("received funding error from %x: %v", fundingErr := fmt.Errorf("received funding error from %x: %v",
peerKey.SerializeCompressed(), msg.Error(), peerKey.SerializeCompressed(), msg.Error(),
) )
fndgLog.Errorf(fundingErr.Error()) log.Errorf(fundingErr.Error())
// If this was a PSBT funding flow, the remote likely timed out because // If this was a PSBT funding flow, the remote likely timed out because
// we waited too long. Return a nice error message to the user in that // we waited too long. Return a nice error message to the user in that
@ -3376,7 +3367,7 @@ func (f *fundingManager) handleErrorMsg(peer lnpeer.Peer,
// pruneZombieReservations loops through all pending reservations and fails the // pruneZombieReservations loops through all pending reservations and fails the
// funding flow for any reservations that have not been updated since the // funding flow for any reservations that have not been updated since the
// ReservationTimeout and are not locked waiting for the funding transaction. // ReservationTimeout and are not locked waiting for the funding transaction.
func (f *fundingManager) pruneZombieReservations() { func (f *Manager) pruneZombieReservations() {
zombieReservations := make(pendingChannels) zombieReservations := make(pendingChannels)
f.resMtx.RLock() f.resMtx.RLock()
@ -3404,17 +3395,17 @@ func (f *fundingManager) pruneZombieReservations() {
err := fmt.Errorf("reservation timed out waiting for peer "+ err := fmt.Errorf("reservation timed out waiting for peer "+
"(peer_id:%x, chan_id:%x)", resCtx.peer.IdentityKey(), "(peer_id:%x, chan_id:%x)", resCtx.peer.IdentityKey(),
pendingChanID[:]) pendingChanID[:])
fndgLog.Warnf(err.Error()) log.Warnf(err.Error())
f.failFundingFlow(resCtx.peer, pendingChanID, err) f.failFundingFlow(resCtx.peer, pendingChanID, err)
} }
} }
// cancelReservationCtx does all needed work in order to securely cancel the // cancelReservationCtx does all needed work in order to securely cancel the
// reservation. // reservation.
func (f *fundingManager) cancelReservationCtx(peerKey *btcec.PublicKey, func (f *Manager) cancelReservationCtx(peerKey *btcec.PublicKey,
pendingChanID [32]byte, byRemote bool) (*reservationWithCtx, error) { pendingChanID [32]byte, byRemote bool) (*reservationWithCtx, error) {
fndgLog.Infof("Cancelling funding reservation for node_key=%x, "+ log.Infof("Cancelling funding reservation for node_key=%x, "+
"chan_id=%x", peerKey.SerializeCompressed(), pendingChanID[:]) "chan_id=%x", peerKey.SerializeCompressed(), pendingChanID[:])
peerIDKey := newSerializedKey(peerKey) peerIDKey := newSerializedKey(peerKey)
@ -3459,7 +3450,7 @@ func (f *fundingManager) cancelReservationCtx(peerKey *btcec.PublicKey,
// deleteReservationCtx deletes the reservation uniquely identified by the // deleteReservationCtx deletes the reservation uniquely identified by the
// target public key of the peer, and the specified pending channel ID. // target public key of the peer, and the specified pending channel ID.
func (f *fundingManager) deleteReservationCtx(peerKey *btcec.PublicKey, func (f *Manager) deleteReservationCtx(peerKey *btcec.PublicKey,
pendingChanID [32]byte) { pendingChanID [32]byte) {
// TODO(roasbeef): possibly cancel funding barrier in peer's // TODO(roasbeef): possibly cancel funding barrier in peer's
@ -3484,7 +3475,7 @@ func (f *fundingManager) deleteReservationCtx(peerKey *btcec.PublicKey,
// getReservationCtx returns the reservation context for a particular pending // getReservationCtx returns the reservation context for a particular pending
// channel ID for a target peer. // channel ID for a target peer.
func (f *fundingManager) getReservationCtx(peerKey *btcec.PublicKey, func (f *Manager) getReservationCtx(peerKey *btcec.PublicKey,
pendingChanID [32]byte) (*reservationWithCtx, error) { pendingChanID [32]byte) (*reservationWithCtx, error) {
peerIDKey := newSerializedKey(peerKey) peerIDKey := newSerializedKey(peerKey)
@ -3505,7 +3496,7 @@ func (f *fundingManager) getReservationCtx(peerKey *btcec.PublicKey,
// of being funded. After the funding transaction has been confirmed, the // of being funded. After the funding transaction has been confirmed, the
// channel will receive a new, permanent channel ID, and will no longer be // channel will receive a new, permanent channel ID, and will no longer be
// considered pending. // considered pending.
func (f *fundingManager) IsPendingChannel(pendingChanID [32]byte, func (f *Manager) IsPendingChannel(pendingChanID [32]byte,
peer lnpeer.Peer) bool { peer lnpeer.Peer) bool {
peerIDKey := newSerializedKey(peer.IdentityKey()) peerIDKey := newSerializedKey(peer.IdentityKey())
@ -3526,7 +3517,7 @@ func copyPubKey(pub *btcec.PublicKey) *btcec.PublicKey {
// saveChannelOpeningState saves the channelOpeningState for the provided // saveChannelOpeningState saves the channelOpeningState for the provided
// chanPoint to the channelOpeningStateBucket. // chanPoint to the channelOpeningStateBucket.
func (f *fundingManager) saveChannelOpeningState(chanPoint *wire.OutPoint, func (f *Manager) saveChannelOpeningState(chanPoint *wire.OutPoint,
state channelOpeningState, shortChanID *lnwire.ShortChannelID) error { state channelOpeningState, shortChanID *lnwire.ShortChannelID) error {
return kvdb.Update(f.cfg.Wallet.Cfg.Database, func(tx kvdb.RwTx) error { return kvdb.Update(f.cfg.Wallet.Cfg.Database, func(tx kvdb.RwTx) error {
@ -3536,7 +3527,7 @@ func (f *fundingManager) saveChannelOpeningState(chanPoint *wire.OutPoint,
} }
var outpointBytes bytes.Buffer var outpointBytes bytes.Buffer
if err = writeOutpoint(&outpointBytes, chanPoint); err != nil { if err = WriteOutpoint(&outpointBytes, chanPoint); err != nil {
return err return err
} }
@ -3553,7 +3544,7 @@ func (f *fundingManager) saveChannelOpeningState(chanPoint *wire.OutPoint,
// getChannelOpeningState fetches the channelOpeningState for the provided // getChannelOpeningState fetches the channelOpeningState for the provided
// chanPoint from the database, or returns ErrChannelNotFound if the channel // chanPoint from the database, or returns ErrChannelNotFound if the channel
// is not found. // is not found.
func (f *fundingManager) getChannelOpeningState(chanPoint *wire.OutPoint) ( func (f *Manager) getChannelOpeningState(chanPoint *wire.OutPoint) (
channelOpeningState, *lnwire.ShortChannelID, error) { channelOpeningState, *lnwire.ShortChannelID, error) {
var state channelOpeningState var state channelOpeningState
@ -3568,7 +3559,7 @@ func (f *fundingManager) getChannelOpeningState(chanPoint *wire.OutPoint) (
} }
var outpointBytes bytes.Buffer var outpointBytes bytes.Buffer
if err := writeOutpoint(&outpointBytes, chanPoint); err != nil { if err := WriteOutpoint(&outpointBytes, chanPoint); err != nil {
return err return err
} }
@ -3589,7 +3580,7 @@ func (f *fundingManager) getChannelOpeningState(chanPoint *wire.OutPoint) (
} }
// deleteChannelOpeningState removes any state for chanPoint from the database. // deleteChannelOpeningState removes any state for chanPoint from the database.
func (f *fundingManager) deleteChannelOpeningState(chanPoint *wire.OutPoint) error { func (f *Manager) deleteChannelOpeningState(chanPoint *wire.OutPoint) error {
return kvdb.Update(f.cfg.Wallet.Cfg.Database, func(tx kvdb.RwTx) error { return kvdb.Update(f.cfg.Wallet.Cfg.Database, func(tx kvdb.RwTx) error {
bucket := tx.ReadWriteBucket(channelOpeningStateBucket) bucket := tx.ReadWriteBucket(channelOpeningStateBucket)
if bucket == nil { if bucket == nil {
@ -3597,7 +3588,7 @@ func (f *fundingManager) deleteChannelOpeningState(chanPoint *wire.OutPoint) err
} }
var outpointBytes bytes.Buffer var outpointBytes bytes.Buffer
if err := writeOutpoint(&outpointBytes, chanPoint); err != nil { if err := WriteOutpoint(&outpointBytes, chanPoint); err != nil {
return err return err
} }

@ -1,6 +1,6 @@
// +build !rpctest // +build !rpctest
package lnd package funding
import ( import (
"bytes" "bytes"
@ -59,6 +59,10 @@ const (
// A dummy value to use for the funding broadcast height. // A dummy value to use for the funding broadcast height.
fundingBroadcastHeight = 123 fundingBroadcastHeight = 123
// defaultMaxLocalCSVDelay is the maximum delay we accept on our
// commitment output.
defaultMaxLocalCSVDelay = 10000
) )
var ( var (
@ -184,7 +188,7 @@ type testNode struct {
msgChan chan lnwire.Message msgChan chan lnwire.Message
announceChan chan lnwire.Message announceChan chan lnwire.Message
publTxChan chan *wire.MsgTx publTxChan chan *wire.MsgTx
fundingMgr *fundingManager fundingMgr *Manager
newChannels chan *newChannelMsg newChannels chan *newChannelMsg
mockNotifier *mockNotifier mockNotifier *mockNotifier
mockChanEvent *mockChanEvent mockChanEvent *mockChanEvent
@ -346,7 +350,7 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey,
chainedAcceptor := chanacceptor.NewChainedAcceptor() chainedAcceptor := chanacceptor.NewChainedAcceptor()
fundingCfg := fundingConfig{ fundingCfg := Config{
IDKey: privKey.PubKey(), IDKey: privKey.PubKey(),
Wallet: lnw, Wallet: lnw,
Notifier: chainNotifier, Notifier: chainNotifier,
@ -433,7 +437,7 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey,
}, },
ZombieSweeperInterval: 1 * time.Hour, ZombieSweeperInterval: 1 * time.Hour,
ReservationTimeout: 1 * time.Nanosecond, ReservationTimeout: 1 * time.Nanosecond,
MaxChanSize: MaxFundingAmount, MaxChanSize: MaxBtcFundingAmount,
MaxLocalCSVDelay: defaultMaxLocalCSVDelay, MaxLocalCSVDelay: defaultMaxLocalCSVDelay,
MaxPendingChannels: lncfg.DefaultMaxPendingChannels, MaxPendingChannels: lncfg.DefaultMaxPendingChannels,
NotifyOpenChannelEvent: evt.NotifyOpenChannelEvent, NotifyOpenChannelEvent: evt.NotifyOpenChannelEvent,
@ -446,7 +450,7 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey,
op(&fundingCfg) op(&fundingCfg)
} }
f, err := newFundingManager(fundingCfg) f, err := NewFundingManager(fundingCfg)
if err != nil { if err != nil {
t.Fatalf("failed creating fundingManager: %v", err) t.Fatalf("failed creating fundingManager: %v", err)
} }
@ -480,9 +484,7 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey,
func recreateAliceFundingManager(t *testing.T, alice *testNode) { func recreateAliceFundingManager(t *testing.T, alice *testNode) {
// Stop the old fundingManager before creating a new one. // Stop the old fundingManager before creating a new one.
close(alice.shutdownChannel) close(alice.shutdownChannel)
if err := alice.fundingMgr.Stop(); err != nil { alice.fundingMgr.Stop()
t.Fatalf("unable to stop old fundingManager: %v", err)
}
aliceMsgChan := make(chan lnwire.Message) aliceMsgChan := make(chan lnwire.Message)
aliceAnnounceChan := make(chan lnwire.Message) aliceAnnounceChan := make(chan lnwire.Message)
@ -493,7 +495,7 @@ func recreateAliceFundingManager(t *testing.T, alice *testNode) {
chainedAcceptor := chanacceptor.NewChainedAcceptor() chainedAcceptor := chanacceptor.NewChainedAcceptor()
f, err := newFundingManager(fundingConfig{ f, err := NewFundingManager(Config{
IDKey: oldCfg.IDKey, IDKey: oldCfg.IDKey,
Wallet: oldCfg.Wallet, Wallet: oldCfg.Wallet,
Notifier: oldCfg.Notifier, Notifier: oldCfg.Notifier,
@ -558,7 +560,7 @@ func recreateAliceFundingManager(t *testing.T, alice *testNode) {
} }
} }
type cfgOption func(*fundingConfig) type cfgOption func(*Config)
func setupFundingManagers(t *testing.T, func setupFundingManagers(t *testing.T,
options ...cfgOption) (*testNode, *testNode) { options ...cfgOption) (*testNode, *testNode) {
@ -620,12 +622,8 @@ func tearDownFundingManagers(t *testing.T, a, b *testNode) {
close(a.shutdownChannel) close(a.shutdownChannel)
close(b.shutdownChannel) close(b.shutdownChannel)
if err := a.fundingMgr.Stop(); err != nil { a.fundingMgr.Stop()
t.Fatalf("unable to stop fundingManager: %v", err) b.fundingMgr.Stop()
}
if err := b.fundingMgr.Stop(); err != nil {
t.Fatalf("unable to stop fundingManager: %v", err)
}
os.RemoveAll(a.testDir) os.RemoveAll(a.testDir)
os.RemoveAll(b.testDir) os.RemoveAll(b.testDir)
} }
@ -656,25 +654,26 @@ func fundChannel(t *testing.T, alice, bob *testNode, localFundingAmt,
// Create a funding request and start the workflow. // Create a funding request and start the workflow.
errChan := make(chan error, 1) errChan := make(chan error, 1)
initReq := &openChanReq{ initReq := &InitFundingMsg{
targetPubkey: bob.privKey.PubKey(), Peer: bob,
chainHash: *fundingNetParams.GenesisHash, TargetPubkey: bob.privKey.PubKey(),
subtractFees: subtractFees, ChainHash: *fundingNetParams.GenesisHash,
localFundingAmt: localFundingAmt, SubtractFees: subtractFees,
pushAmt: lnwire.NewMSatFromSatoshis(pushAmt), LocalFundingAmt: localFundingAmt,
fundingFeePerKw: 1000, PushAmt: lnwire.NewMSatFromSatoshis(pushAmt),
private: !announceChan, FundingFeePerKw: 1000,
updates: updateChan, Private: !announceChan,
err: errChan, Updates: updateChan,
Err: errChan,
} }
alice.fundingMgr.initFundingWorkflow(bob, initReq) alice.fundingMgr.InitFundingWorkflow(initReq)
// Alice should have sent the OpenChannel message to Bob. // Alice should have sent the OpenChannel message to Bob.
var aliceMsg lnwire.Message var aliceMsg lnwire.Message
select { select {
case aliceMsg = <-alice.msgChan: case aliceMsg = <-alice.msgChan:
case err := <-initReq.err: case err := <-initReq.Err:
t.Fatalf("error init funding workflow: %v", err) t.Fatalf("error init funding workflow: %v", err)
case <-time.After(time.Second * 5): case <-time.After(time.Second * 5):
t.Fatalf("alice did not send OpenChannel message") t.Fatalf("alice did not send OpenChannel message")
@ -1316,22 +1315,23 @@ func testLocalCSVLimit(t *testing.T, aliceMaxCSV, bobRequiredCSV uint16) {
// First, we will initiate an outgoing channel from Alice -> Bob. // First, we will initiate an outgoing channel from Alice -> Bob.
errChan := make(chan error, 1) errChan := make(chan error, 1)
updateChan := make(chan *lnrpc.OpenStatusUpdate) updateChan := make(chan *lnrpc.OpenStatusUpdate)
initReq := &openChanReq{ initReq := &InitFundingMsg{
targetPubkey: bob.privKey.PubKey(), Peer: bob,
chainHash: *fundingNetParams.GenesisHash, TargetPubkey: bob.privKey.PubKey(),
localFundingAmt: 200000, ChainHash: *fundingNetParams.GenesisHash,
fundingFeePerKw: 1000, LocalFundingAmt: 200000,
updates: updateChan, FundingFeePerKw: 1000,
err: errChan, Updates: updateChan,
Err: errChan,
} }
// Alice should have sent the OpenChannel message to Bob. // Alice should have sent the OpenChannel message to Bob.
alice.fundingMgr.initFundingWorkflow(bob, initReq) alice.fundingMgr.InitFundingWorkflow(initReq)
var aliceMsg lnwire.Message var aliceMsg lnwire.Message
select { select {
case aliceMsg = <-alice.msgChan: case aliceMsg = <-alice.msgChan:
case err := <-initReq.err: case err := <-initReq.Err:
t.Fatalf("error init funding workflow: %v", err) t.Fatalf("error init funding workflow: %v", err)
case <-time.After(time.Second * 5): case <-time.After(time.Second * 5):
@ -1381,23 +1381,24 @@ func testLocalCSVLimit(t *testing.T, aliceMaxCSV, bobRequiredCSV uint16) {
// handle incoming channels, opening a channel from Bob->Alice. // handle incoming channels, opening a channel from Bob->Alice.
errChan = make(chan error, 1) errChan = make(chan error, 1)
updateChan = make(chan *lnrpc.OpenStatusUpdate) updateChan = make(chan *lnrpc.OpenStatusUpdate)
initReq = &openChanReq{ initReq = &InitFundingMsg{
targetPubkey: alice.privKey.PubKey(), Peer: alice,
chainHash: *fundingNetParams.GenesisHash, TargetPubkey: alice.privKey.PubKey(),
localFundingAmt: 200000, ChainHash: *fundingNetParams.GenesisHash,
fundingFeePerKw: 1000, LocalFundingAmt: 200000,
updates: updateChan, FundingFeePerKw: 1000,
err: errChan, Updates: updateChan,
Err: errChan,
} }
bob.fundingMgr.initFundingWorkflow(alice, initReq) bob.fundingMgr.InitFundingWorkflow(initReq)
// Bob should have sent the OpenChannel message to Alice. // Bob should have sent the OpenChannel message to Alice.
var bobMsg lnwire.Message var bobMsg lnwire.Message
select { select {
case bobMsg = <-bob.msgChan: case bobMsg = <-bob.msgChan:
case err := <-initReq.err: case err := <-initReq.Err:
t.Fatalf("bob OpenChannel message failed: %v", err) t.Fatalf("bob OpenChannel message failed: %v", err)
case <-time.After(time.Second * 5): case <-time.After(time.Second * 5):
@ -1501,9 +1502,7 @@ func TestFundingManagerRestartBehavior(t *testing.T) {
// implementation, and expect it to retry sending the fundingLocked // implementation, and expect it to retry sending the fundingLocked
// message. We'll explicitly shut down Alice's funding manager to // message. We'll explicitly shut down Alice's funding manager to
// prevent a race when overriding the sendMessage implementation. // prevent a race when overriding the sendMessage implementation.
if err := alice.fundingMgr.Stop(); err != nil { alice.fundingMgr.Stop()
t.Fatalf("unable to stop alice's funding manager: %v", err)
}
bob.sendMessage = workingSendMessage bob.sendMessage = workingSendMessage
recreateAliceFundingManager(t, alice) recreateAliceFundingManager(t, alice)
@ -1721,7 +1720,7 @@ func TestFundingManagerOfflinePeer(t *testing.T) {
// TestFundingManagerPeerTimeoutAfterInitFunding checks that the zombie sweeper // TestFundingManagerPeerTimeoutAfterInitFunding checks that the zombie sweeper
// will properly clean up a zombie reservation that times out after the // will properly clean up a zombie reservation that times out after the
// initFundingMsg has been handled. // InitFundingMsg has been handled.
func TestFundingManagerPeerTimeoutAfterInitFunding(t *testing.T) { func TestFundingManagerPeerTimeoutAfterInitFunding(t *testing.T) {
t.Parallel() t.Parallel()
@ -1733,23 +1732,24 @@ func TestFundingManagerPeerTimeoutAfterInitFunding(t *testing.T) {
// Create a funding request and start the workflow. // Create a funding request and start the workflow.
errChan := make(chan error, 1) errChan := make(chan error, 1)
initReq := &openChanReq{ initReq := &InitFundingMsg{
targetPubkey: bob.privKey.PubKey(), Peer: bob,
chainHash: *fundingNetParams.GenesisHash, TargetPubkey: bob.privKey.PubKey(),
localFundingAmt: 500000, ChainHash: *fundingNetParams.GenesisHash,
pushAmt: lnwire.NewMSatFromSatoshis(0), LocalFundingAmt: 500000,
private: false, PushAmt: lnwire.NewMSatFromSatoshis(0),
updates: updateChan, Private: false,
err: errChan, Updates: updateChan,
Err: errChan,
} }
alice.fundingMgr.initFundingWorkflow(bob, initReq) alice.fundingMgr.InitFundingWorkflow(initReq)
// Alice should have sent the OpenChannel message to Bob. // Alice should have sent the OpenChannel message to Bob.
var aliceMsg lnwire.Message var aliceMsg lnwire.Message
select { select {
case aliceMsg = <-alice.msgChan: case aliceMsg = <-alice.msgChan:
case err := <-initReq.err: case err := <-initReq.Err:
t.Fatalf("error init funding workflow: %v", err) t.Fatalf("error init funding workflow: %v", err)
case <-time.After(time.Second * 5): case <-time.After(time.Second * 5):
t.Fatalf("alice did not send OpenChannel message") t.Fatalf("alice did not send OpenChannel message")
@ -1795,23 +1795,24 @@ func TestFundingManagerPeerTimeoutAfterFundingOpen(t *testing.T) {
// Create a funding request and start the workflow. // Create a funding request and start the workflow.
errChan := make(chan error, 1) errChan := make(chan error, 1)
initReq := &openChanReq{ initReq := &InitFundingMsg{
targetPubkey: bob.privKey.PubKey(), Peer: bob,
chainHash: *fundingNetParams.GenesisHash, TargetPubkey: bob.privKey.PubKey(),
localFundingAmt: 500000, ChainHash: *fundingNetParams.GenesisHash,
pushAmt: lnwire.NewMSatFromSatoshis(0), LocalFundingAmt: 500000,
private: false, PushAmt: lnwire.NewMSatFromSatoshis(0),
updates: updateChan, Private: false,
err: errChan, Updates: updateChan,
Err: errChan,
} }
alice.fundingMgr.initFundingWorkflow(bob, initReq) alice.fundingMgr.InitFundingWorkflow(initReq)
// Alice should have sent the OpenChannel message to Bob. // Alice should have sent the OpenChannel message to Bob.
var aliceMsg lnwire.Message var aliceMsg lnwire.Message
select { select {
case aliceMsg = <-alice.msgChan: case aliceMsg = <-alice.msgChan:
case err := <-initReq.err: case err := <-initReq.Err:
t.Fatalf("error init funding workflow: %v", err) t.Fatalf("error init funding workflow: %v", err)
case <-time.After(time.Second * 5): case <-time.After(time.Second * 5):
t.Fatalf("alice did not send OpenChannel message") t.Fatalf("alice did not send OpenChannel message")
@ -1866,23 +1867,24 @@ func TestFundingManagerPeerTimeoutAfterFundingAccept(t *testing.T) {
// Create a funding request and start the workflow. // Create a funding request and start the workflow.
errChan := make(chan error, 1) errChan := make(chan error, 1)
initReq := &openChanReq{ initReq := &InitFundingMsg{
targetPubkey: bob.privKey.PubKey(), Peer: bob,
chainHash: *fundingNetParams.GenesisHash, TargetPubkey: bob.privKey.PubKey(),
localFundingAmt: 500000, ChainHash: *fundingNetParams.GenesisHash,
pushAmt: lnwire.NewMSatFromSatoshis(0), LocalFundingAmt: 500000,
private: false, PushAmt: lnwire.NewMSatFromSatoshis(0),
updates: updateChan, Private: false,
err: errChan, Updates: updateChan,
Err: errChan,
} }
alice.fundingMgr.initFundingWorkflow(bob, initReq) alice.fundingMgr.InitFundingWorkflow(initReq)
// Alice should have sent the OpenChannel message to Bob. // Alice should have sent the OpenChannel message to Bob.
var aliceMsg lnwire.Message var aliceMsg lnwire.Message
select { select {
case aliceMsg = <-alice.msgChan: case aliceMsg = <-alice.msgChan:
case err := <-initReq.err: case err := <-initReq.Err:
t.Fatalf("error init funding workflow: %v", err) t.Fatalf("error init funding workflow: %v", err)
case <-time.After(time.Second * 5): case <-time.After(time.Second * 5):
t.Fatalf("alice did not send OpenChannel message") t.Fatalf("alice did not send OpenChannel message")
@ -2590,26 +2592,27 @@ func TestFundingManagerCustomChannelParameters(t *testing.T) {
// Create a funding request with the custom parameters and start the // Create a funding request with the custom parameters and start the
// workflow. // workflow.
errChan := make(chan error, 1) errChan := make(chan error, 1)
initReq := &openChanReq{ initReq := &InitFundingMsg{
targetPubkey: bob.privKey.PubKey(), Peer: bob,
chainHash: *fundingNetParams.GenesisHash, TargetPubkey: bob.privKey.PubKey(),
localFundingAmt: localAmt, ChainHash: *fundingNetParams.GenesisHash,
pushAmt: lnwire.NewMSatFromSatoshis(pushAmt), LocalFundingAmt: localAmt,
private: false, PushAmt: lnwire.NewMSatFromSatoshis(pushAmt),
maxValueInFlight: maxValueInFlight, Private: false,
minHtlcIn: minHtlcIn, MaxValueInFlight: maxValueInFlight,
remoteCsvDelay: csvDelay, MinHtlcIn: minHtlcIn,
updates: updateChan, RemoteCsvDelay: csvDelay,
err: errChan, Updates: updateChan,
Err: errChan,
} }
alice.fundingMgr.initFundingWorkflow(bob, initReq) alice.fundingMgr.InitFundingWorkflow(initReq)
// Alice should have sent the OpenChannel message to Bob. // Alice should have sent the OpenChannel message to Bob.
var aliceMsg lnwire.Message var aliceMsg lnwire.Message
select { select {
case aliceMsg = <-alice.msgChan: case aliceMsg = <-alice.msgChan:
case err := <-initReq.err: case err := <-initReq.Err:
t.Fatalf("error init funding workflow: %v", err) t.Fatalf("error init funding workflow: %v", err)
case <-time.After(time.Second * 5): case <-time.After(time.Second * 5):
t.Fatalf("alice did not send OpenChannel message") t.Fatalf("alice did not send OpenChannel message")
@ -2864,25 +2867,26 @@ func TestFundingManagerMaxPendingChannels(t *testing.T) {
t.Parallel() t.Parallel()
alice, bob := setupFundingManagers( alice, bob := setupFundingManagers(
t, func(cfg *fundingConfig) { t, func(cfg *Config) {
cfg.MaxPendingChannels = maxPending cfg.MaxPendingChannels = maxPending
}, },
) )
defer tearDownFundingManagers(t, alice, bob) defer tearDownFundingManagers(t, alice, bob)
// Create openChanReqs for maxPending+1 channels. // Create InitFundingMsg structs for maxPending+1 channels.
var initReqs []*openChanReq var initReqs []*InitFundingMsg
for i := 0; i < maxPending+1; i++ { for i := 0; i < maxPending+1; i++ {
updateChan := make(chan *lnrpc.OpenStatusUpdate) updateChan := make(chan *lnrpc.OpenStatusUpdate)
errChan := make(chan error, 1) errChan := make(chan error, 1)
initReq := &openChanReq{ initReq := &InitFundingMsg{
targetPubkey: bob.privKey.PubKey(), Peer: bob,
chainHash: *fundingNetParams.GenesisHash, TargetPubkey: bob.privKey.PubKey(),
localFundingAmt: 5000000, ChainHash: *fundingNetParams.GenesisHash,
pushAmt: lnwire.NewMSatFromSatoshis(0), LocalFundingAmt: 5000000,
private: false, PushAmt: lnwire.NewMSatFromSatoshis(0),
updates: updateChan, Private: false,
err: errChan, Updates: updateChan,
Err: errChan,
} }
initReqs = append(initReqs, initReq) initReqs = append(initReqs, initReq)
} }
@ -2891,13 +2895,13 @@ func TestFundingManagerMaxPendingChannels(t *testing.T) {
var accepts []*lnwire.AcceptChannel var accepts []*lnwire.AcceptChannel
var lastOpen *lnwire.OpenChannel var lastOpen *lnwire.OpenChannel
for i, initReq := range initReqs { for i, initReq := range initReqs {
alice.fundingMgr.initFundingWorkflow(bob, initReq) alice.fundingMgr.InitFundingWorkflow(initReq)
// Alice should have sent the OpenChannel message to Bob. // Alice should have sent the OpenChannel message to Bob.
var aliceMsg lnwire.Message var aliceMsg lnwire.Message
select { select {
case aliceMsg = <-alice.msgChan: case aliceMsg = <-alice.msgChan:
case err := <-initReq.err: case err := <-initReq.Err:
t.Fatalf("error init funding workflow: %v", err) t.Fatalf("error init funding workflow: %v", err)
case <-time.After(time.Second * 5): case <-time.After(time.Second * 5):
t.Fatalf("alice did not send OpenChannel message") t.Fatalf("alice did not send OpenChannel message")
@ -2973,7 +2977,7 @@ func TestFundingManagerMaxPendingChannels(t *testing.T) {
// publish a funding tx to the network. // publish a funding tx to the network.
var pendingUpdate *lnrpc.OpenStatusUpdate var pendingUpdate *lnrpc.OpenStatusUpdate
select { select {
case pendingUpdate = <-initReqs[i].updates: case pendingUpdate = <-initReqs[i].Updates:
case <-time.After(time.Second * 5): case <-time.After(time.Second * 5):
t.Fatalf("alice did not send OpenStatusUpdate_ChanPending") t.Fatalf("alice did not send OpenStatusUpdate_ChanPending")
} }
@ -3036,7 +3040,7 @@ func TestFundingManagerRejectPush(t *testing.T) {
// Enable 'rejectpush' option and initialize funding managers. // Enable 'rejectpush' option and initialize funding managers.
alice, bob := setupFundingManagers( alice, bob := setupFundingManagers(
t, func(cfg *fundingConfig) { t, func(cfg *Config) {
cfg.RejectPush = true cfg.RejectPush = true
}, },
) )
@ -3045,23 +3049,24 @@ func TestFundingManagerRejectPush(t *testing.T) {
// Create a funding request and start the workflow. // Create a funding request and start the workflow.
updateChan := make(chan *lnrpc.OpenStatusUpdate) updateChan := make(chan *lnrpc.OpenStatusUpdate)
errChan := make(chan error, 1) errChan := make(chan error, 1)
initReq := &openChanReq{ initReq := &InitFundingMsg{
targetPubkey: bob.privKey.PubKey(), Peer: bob,
chainHash: *fundingNetParams.GenesisHash, TargetPubkey: bob.privKey.PubKey(),
localFundingAmt: 500000, ChainHash: *fundingNetParams.GenesisHash,
pushAmt: lnwire.NewMSatFromSatoshis(10), LocalFundingAmt: 500000,
private: true, PushAmt: lnwire.NewMSatFromSatoshis(10),
updates: updateChan, Private: true,
err: errChan, Updates: updateChan,
Err: errChan,
} }
alice.fundingMgr.initFundingWorkflow(bob, initReq) alice.fundingMgr.InitFundingWorkflow(initReq)
// Alice should have sent the OpenChannel message to Bob. // Alice should have sent the OpenChannel message to Bob.
var aliceMsg lnwire.Message var aliceMsg lnwire.Message
select { select {
case aliceMsg = <-alice.msgChan: case aliceMsg = <-alice.msgChan:
case err := <-initReq.err: case err := <-initReq.Err:
t.Fatalf("error init funding workflow: %v", err) t.Fatalf("error init funding workflow: %v", err)
case <-time.After(time.Second * 5): case <-time.After(time.Second * 5):
t.Fatalf("alice did not send OpenChannel message") t.Fatalf("alice did not send OpenChannel message")
@ -3102,23 +3107,24 @@ func TestFundingManagerMaxConfs(t *testing.T) {
// Create a funding request and start the workflow. // Create a funding request and start the workflow.
updateChan := make(chan *lnrpc.OpenStatusUpdate) updateChan := make(chan *lnrpc.OpenStatusUpdate)
errChan := make(chan error, 1) errChan := make(chan error, 1)
initReq := &openChanReq{ initReq := &InitFundingMsg{
targetPubkey: bob.privKey.PubKey(), Peer: bob,
chainHash: *fundingNetParams.GenesisHash, TargetPubkey: bob.privKey.PubKey(),
localFundingAmt: 500000, ChainHash: *fundingNetParams.GenesisHash,
pushAmt: lnwire.NewMSatFromSatoshis(10), LocalFundingAmt: 500000,
private: false, PushAmt: lnwire.NewMSatFromSatoshis(10),
updates: updateChan, Private: false,
err: errChan, Updates: updateChan,
Err: errChan,
} }
alice.fundingMgr.initFundingWorkflow(bob, initReq) alice.fundingMgr.InitFundingWorkflow(initReq)
// Alice should have sent the OpenChannel message to Bob. // Alice should have sent the OpenChannel message to Bob.
var aliceMsg lnwire.Message var aliceMsg lnwire.Message
select { select {
case aliceMsg = <-alice.msgChan: case aliceMsg = <-alice.msgChan:
case err := <-initReq.err: case err := <-initReq.Err:
t.Fatalf("error init funding workflow: %v", err) t.Fatalf("error init funding workflow: %v", err)
case <-time.After(time.Second * 5): case <-time.After(time.Second * 5):
t.Fatalf("alice did not send OpenChannel message") t.Fatalf("alice did not send OpenChannel message")
@ -3374,29 +3380,30 @@ func TestMaxChannelSizeConfig(t *testing.T) {
// Create a set of funding managers that will reject wumbo // Create a set of funding managers that will reject wumbo
// channels but set --maxchansize explicitly lower than soft-limit. // channels but set --maxchansize explicitly lower than soft-limit.
// Verify that wumbo rejecting funding managers will respect --maxchansize // Verify that wumbo rejecting funding managers will respect --maxchansize
// below 16777215 satoshi (MaxFundingAmount) limit. // below 16777215 satoshi (MaxBtcFundingAmount) limit.
alice, bob := setupFundingManagers(t, func(cfg *fundingConfig) { alice, bob := setupFundingManagers(t, func(cfg *Config) {
cfg.NoWumboChans = true cfg.NoWumboChans = true
cfg.MaxChanSize = MaxFundingAmount - 1 cfg.MaxChanSize = MaxBtcFundingAmount - 1
}) })
// Attempt to create a channel above the limit // Attempt to create a channel above the limit
// imposed by --maxchansize, which should be rejected. // imposed by --maxchansize, which should be rejected.
updateChan := make(chan *lnrpc.OpenStatusUpdate) updateChan := make(chan *lnrpc.OpenStatusUpdate)
errChan := make(chan error, 1) errChan := make(chan error, 1)
initReq := &openChanReq{ initReq := &InitFundingMsg{
targetPubkey: bob.privKey.PubKey(), Peer: bob,
chainHash: *fundingNetParams.GenesisHash, TargetPubkey: bob.privKey.PubKey(),
localFundingAmt: MaxFundingAmount, ChainHash: *fundingNetParams.GenesisHash,
pushAmt: lnwire.NewMSatFromSatoshis(0), LocalFundingAmt: MaxBtcFundingAmount,
private: false, PushAmt: lnwire.NewMSatFromSatoshis(0),
updates: updateChan, Private: false,
err: errChan, Updates: updateChan,
Err: errChan,
} }
// After processing the funding open message, bob should respond with // After processing the funding open message, bob should respond with
// an error rejecting the channel that exceeds size limit. // an error rejecting the channel that exceeds size limit.
alice.fundingMgr.initFundingWorkflow(bob, initReq) alice.fundingMgr.InitFundingWorkflow(initReq)
openChanMsg := expectOpenChannelMsg(t, alice.msgChan) openChanMsg := expectOpenChannelMsg(t, alice.msgChan)
bob.fundingMgr.ProcessFundingMsg(openChanMsg, alice) bob.fundingMgr.ProcessFundingMsg(openChanMsg, alice)
assertErrorSent(t, bob.msgChan) assertErrorSent(t, bob.msgChan)
@ -3405,13 +3412,16 @@ func TestMaxChannelSizeConfig(t *testing.T) {
// channels but set --maxchansize explicitly higher than soft-limit // channels but set --maxchansize explicitly higher than soft-limit
// A --maxchansize greater than this limit should have no effect. // A --maxchansize greater than this limit should have no effect.
tearDownFundingManagers(t, alice, bob) tearDownFundingManagers(t, alice, bob)
alice, bob = setupFundingManagers(t, func(cfg *fundingConfig) { alice, bob = setupFundingManagers(t, func(cfg *Config) {
cfg.NoWumboChans = true cfg.NoWumboChans = true
cfg.MaxChanSize = MaxFundingAmount + 1 cfg.MaxChanSize = MaxBtcFundingAmount + 1
}) })
// Reset the Peer to the newly created one.
initReq.Peer = bob
// We expect Bob to respond with an Accept channel message. // We expect Bob to respond with an Accept channel message.
alice.fundingMgr.initFundingWorkflow(bob, initReq) alice.fundingMgr.InitFundingWorkflow(initReq)
openChanMsg = expectOpenChannelMsg(t, alice.msgChan) openChanMsg = expectOpenChannelMsg(t, alice.msgChan)
bob.fundingMgr.ProcessFundingMsg(openChanMsg, alice) bob.fundingMgr.ProcessFundingMsg(openChanMsg, alice)
assertFundingMsgSent(t, bob.msgChan, "AcceptChannel") assertFundingMsgSent(t, bob.msgChan, "AcceptChannel")
@ -3420,18 +3430,21 @@ func TestMaxChannelSizeConfig(t *testing.T) {
// Create the funding managers, this time allowing // Create the funding managers, this time allowing
// wumbo channels but setting --maxchansize explicitly. // wumbo channels but setting --maxchansize explicitly.
tearDownFundingManagers(t, alice, bob) tearDownFundingManagers(t, alice, bob)
alice, bob = setupFundingManagers(t, func(cfg *fundingConfig) { alice, bob = setupFundingManagers(t, func(cfg *Config) {
cfg.NoWumboChans = false cfg.NoWumboChans = false
cfg.MaxChanSize = btcutil.Amount(100000000) cfg.MaxChanSize = btcutil.Amount(100000000)
}) })
// Reset the Peer to the newly created one.
initReq.Peer = bob
// Attempt to create a channel above the limit // Attempt to create a channel above the limit
// imposed by --maxchansize, which should be rejected. // imposed by --maxchansize, which should be rejected.
initReq.localFundingAmt = btcutil.SatoshiPerBitcoin + 1 initReq.LocalFundingAmt = btcutil.SatoshiPerBitcoin + 1
// After processing the funding open message, bob should respond with // After processing the funding open message, bob should respond with
// an error rejecting the channel that exceeds size limit. // an error rejecting the channel that exceeds size limit.
alice.fundingMgr.initFundingWorkflow(bob, initReq) alice.fundingMgr.InitFundingWorkflow(initReq)
openChanMsg = expectOpenChannelMsg(t, alice.msgChan) openChanMsg = expectOpenChannelMsg(t, alice.msgChan)
bob.fundingMgr.ProcessFundingMsg(openChanMsg, alice) bob.fundingMgr.ProcessFundingMsg(openChanMsg, alice)
assertErrorSent(t, bob.msgChan) assertErrorSent(t, bob.msgChan)
@ -3444,7 +3457,7 @@ func TestWumboChannelConfig(t *testing.T) {
// First we'll create a set of funding managers that will reject wumbo // First we'll create a set of funding managers that will reject wumbo
// channels. // channels.
alice, bob := setupFundingManagers(t, func(cfg *fundingConfig) { alice, bob := setupFundingManagers(t, func(cfg *Config) {
cfg.NoWumboChans = true cfg.NoWumboChans = true
}) })
@ -3453,29 +3466,30 @@ func TestWumboChannelConfig(t *testing.T) {
// funding process w/o issue. // funding process w/o issue.
updateChan := make(chan *lnrpc.OpenStatusUpdate) updateChan := make(chan *lnrpc.OpenStatusUpdate)
errChan := make(chan error, 1) errChan := make(chan error, 1)
initReq := &openChanReq{ initReq := &InitFundingMsg{
targetPubkey: bob.privKey.PubKey(), Peer: bob,
chainHash: *fundingNetParams.GenesisHash, TargetPubkey: bob.privKey.PubKey(),
localFundingAmt: MaxFundingAmount, ChainHash: *fundingNetParams.GenesisHash,
pushAmt: lnwire.NewMSatFromSatoshis(0), LocalFundingAmt: MaxBtcFundingAmount,
private: false, PushAmt: lnwire.NewMSatFromSatoshis(0),
updates: updateChan, Private: false,
err: errChan, Updates: updateChan,
Err: errChan,
} }
// We expect Bob to respond with an Accept channel message. // We expect Bob to respond with an Accept channel message.
alice.fundingMgr.initFundingWorkflow(bob, initReq) alice.fundingMgr.InitFundingWorkflow(initReq)
openChanMsg := expectOpenChannelMsg(t, alice.msgChan) openChanMsg := expectOpenChannelMsg(t, alice.msgChan)
bob.fundingMgr.ProcessFundingMsg(openChanMsg, alice) bob.fundingMgr.ProcessFundingMsg(openChanMsg, alice)
assertFundingMsgSent(t, bob.msgChan, "AcceptChannel") assertFundingMsgSent(t, bob.msgChan, "AcceptChannel")
// We'll now attempt to create a channel above the wumbo mark, which // We'll now attempt to create a channel above the wumbo mark, which
// should be rejected. // should be rejected.
initReq.localFundingAmt = btcutil.SatoshiPerBitcoin initReq.LocalFundingAmt = btcutil.SatoshiPerBitcoin
// After processing the funding open message, bob should respond with // After processing the funding open message, bob should respond with
// an error rejecting the channel. // an error rejecting the channel.
alice.fundingMgr.initFundingWorkflow(bob, initReq) alice.fundingMgr.InitFundingWorkflow(initReq)
openChanMsg = expectOpenChannelMsg(t, alice.msgChan) openChanMsg = expectOpenChannelMsg(t, alice.msgChan)
bob.fundingMgr.ProcessFundingMsg(openChanMsg, alice) bob.fundingMgr.ProcessFundingMsg(openChanMsg, alice)
assertErrorSent(t, bob.msgChan) assertErrorSent(t, bob.msgChan)
@ -3483,14 +3497,17 @@ func TestWumboChannelConfig(t *testing.T) {
// Next, we'll re-create the funding managers, but this time allowing // Next, we'll re-create the funding managers, but this time allowing
// wumbo channels explicitly. // wumbo channels explicitly.
tearDownFundingManagers(t, alice, bob) tearDownFundingManagers(t, alice, bob)
alice, bob = setupFundingManagers(t, func(cfg *fundingConfig) { alice, bob = setupFundingManagers(t, func(cfg *Config) {
cfg.NoWumboChans = false cfg.NoWumboChans = false
cfg.MaxChanSize = MaxBtcFundingAmountWumbo cfg.MaxChanSize = MaxBtcFundingAmountWumbo
}) })
// Reset the Peer to the newly created one.
initReq.Peer = bob
// We should now be able to initiate a wumbo channel funding w/o any // We should now be able to initiate a wumbo channel funding w/o any
// issues. // issues.
alice.fundingMgr.initFundingWorkflow(bob, initReq) alice.fundingMgr.InitFundingWorkflow(initReq)
openChanMsg = expectOpenChannelMsg(t, alice.msgChan) openChanMsg = expectOpenChannelMsg(t, alice.msgChan)
bob.fundingMgr.ProcessFundingMsg(openChanMsg, alice) bob.fundingMgr.ProcessFundingMsg(openChanMsg, alice)
assertFundingMsgSent(t, bob.msgChan, "AcceptChannel") assertFundingMsgSent(t, bob.msgChan, "AcceptChannel")

@ -8,7 +8,7 @@ import (
"strings" "strings"
"github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil"
"github.com/lightningnetwork/lnd" "github.com/lightningnetwork/lnd/funding"
"github.com/lightningnetwork/lnd/lntest" "github.com/lightningnetwork/lnd/lntest"
) )
@ -49,7 +49,7 @@ func testMaxChannelSize(net *lntest.NetworkHarness, t *harnessTest) {
t.Fatalf("unable to connect peers: %v", err) t.Fatalf("unable to connect peers: %v", err)
} }
chanAmt := lnd.MaxBtcFundingAmountWumbo + 1 chanAmt := funding.MaxBtcFundingAmountWumbo + 1
_, err = net.OpenChannel( _, err = net.OpenChannel(
ctxb, wumboNode, wumboNode2, lntest.OpenChannelParams{ ctxb, wumboNode, wumboNode2, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
@ -97,7 +97,7 @@ func testMaxChannelSize(net *lntest.NetworkHarness, t *harnessTest) {
// to accept our wumbo channel funding. // to accept our wumbo channel funding.
wumboNode3, err := net.NewNode( wumboNode3, err := net.NewNode(
"wumbo3", []string{"--protocol.wumbo-channels", "wumbo3", []string{"--protocol.wumbo-channels",
fmt.Sprintf("--maxchansize=%v", int64(lnd.MaxBtcFundingAmountWumbo+1))}, fmt.Sprintf("--maxchansize=%v", int64(funding.MaxBtcFundingAmountWumbo+1))},
) )
if err != nil { if err != nil {
t.Fatalf("unable to create new node: %v", err) t.Fatalf("unable to create new node: %v", err)

@ -6,7 +6,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/lightningnetwork/lnd" "github.com/lightningnetwork/lnd/funding"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lntest" "github.com/lightningnetwork/lnd/lntest"
@ -19,7 +19,7 @@ func testHtlcErrorPropagation(net *lntest.NetworkHarness, t *harnessTest) {
// In this test we wish to exercise the daemon's correct parsing, // In this test we wish to exercise the daemon's correct parsing,
// handling, and propagation of errors that occur while processing a // handling, and propagation of errors that occur while processing a
// multi-hop payment. // multi-hop payment.
const chanAmt = lnd.MaxBtcFundingAmount const chanAmt = funding.MaxBtcFundingAmount
// First establish a channel with a capacity of 0.5 BTC between Alice // First establish a channel with a capacity of 0.5 BTC between Alice
// and Bob. // and Bob.
@ -102,7 +102,7 @@ func testHtlcErrorPropagation(net *lntest.NetworkHarness, t *harnessTest) {
t.Fatalf("unable to connect bob to carol: %v", err) t.Fatalf("unable to connect bob to carol: %v", err)
} }
ctxt, _ = context.WithTimeout(ctxb, channelOpenTimeout) ctxt, _ = context.WithTimeout(ctxb, channelOpenTimeout)
const bobChanAmt = lnd.MaxBtcFundingAmount const bobChanAmt = funding.MaxBtcFundingAmount
chanPointBob := openChannelAndAssert( chanPointBob := openChannelAndAssert(
ctxt, t, net, net.Bob, carol, ctxt, t, net, net.Bob, carol,
lntest.OpenChannelParams{ lntest.OpenChannelParams{

@ -8,7 +8,7 @@ import (
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil"
"github.com/lightningnetwork/lnd" "github.com/lightningnetwork/lnd/funding"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/walletrpc" "github.com/lightningnetwork/lnd/lnrpc/walletrpc"
"github.com/lightningnetwork/lnd/lntest" "github.com/lightningnetwork/lnd/lntest"
@ -20,7 +20,7 @@ import (
// multisig funding output. // multisig funding output.
func testPsbtChanFunding(net *lntest.NetworkHarness, t *harnessTest) { func testPsbtChanFunding(net *lntest.NetworkHarness, t *harnessTest) {
ctxb := context.Background() ctxb := context.Background()
const chanSize = lnd.MaxBtcFundingAmount const chanSize = funding.MaxBtcFundingAmount
// First, we'll create two new nodes that we'll use to open channels // First, we'll create two new nodes that we'll use to open channels
// between for this test. Dave gets some coins that will be used to // between for this test. Dave gets some coins that will be used to

@ -32,6 +32,7 @@ import (
"github.com/lightningnetwork/lnd" "github.com/lightningnetwork/lnd"
"github.com/lightningnetwork/lnd/chainreg" "github.com/lightningnetwork/lnd/chainreg"
"github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/funding"
"github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/labels" "github.com/lightningnetwork/lnd/labels"
"github.com/lightningnetwork/lnd/lncfg" "github.com/lightningnetwork/lnd/lncfg"
@ -1250,7 +1251,7 @@ func basicChannelFundingTest(t *harnessTest, net *lntest.NetworkHarness,
alice *lntest.HarnessNode, bob *lntest.HarnessNode, alice *lntest.HarnessNode, bob *lntest.HarnessNode,
fundingShim *lnrpc.FundingShim) (*lnrpc.Channel, *lnrpc.Channel, func(), error) { fundingShim *lnrpc.FundingShim) (*lnrpc.Channel, *lnrpc.Channel, func(), error) {
chanAmt := lnd.MaxBtcFundingAmount chanAmt := funding.MaxBtcFundingAmount
pushAmt := btcutil.Amount(100000) pushAmt := btcutil.Amount(100000)
// Record nodes' channel balance before testing. // Record nodes' channel balance before testing.
@ -1493,7 +1494,7 @@ func testUnconfirmedChannelFunding(net *lntest.NetworkHarness, t *harnessTest) {
ctxb := context.Background() ctxb := context.Background()
const ( const (
chanAmt = lnd.MaxBtcFundingAmount chanAmt = funding.MaxBtcFundingAmount
pushAmt = btcutil.Amount(100000) pushAmt = btcutil.Amount(100000)
) )
@ -1945,7 +1946,7 @@ func testUpdateChannelPolicy(net *lntest.NetworkHarness, t *harnessTest) {
defaultTimeLockDelta = chainreg.DefaultBitcoinTimeLockDelta defaultTimeLockDelta = chainreg.DefaultBitcoinTimeLockDelta
defaultMinHtlc = 1000 defaultMinHtlc = 1000
) )
defaultMaxHtlc := calculateMaxHtlc(lnd.MaxBtcFundingAmount) defaultMaxHtlc := calculateMaxHtlc(funding.MaxBtcFundingAmount)
// Launch notification clients for all nodes, such that we can // Launch notification clients for all nodes, such that we can
// get notified when they discover new channels and updates in the // get notified when they discover new channels and updates in the
@ -1955,7 +1956,7 @@ func testUpdateChannelPolicy(net *lntest.NetworkHarness, t *harnessTest) {
bobSub := subscribeGraphNotifications(t, ctxb, net.Bob) bobSub := subscribeGraphNotifications(t, ctxb, net.Bob)
defer close(bobSub.quit) defer close(bobSub.quit)
chanAmt := lnd.MaxBtcFundingAmount chanAmt := funding.MaxBtcFundingAmount
pushAmt := chanAmt / 2 pushAmt := chanAmt / 2
// Create a channel Alice->Bob. // Create a channel Alice->Bob.
@ -2518,7 +2519,7 @@ func testOpenChannelAfterReorg(net *lntest.NetworkHarness, t *harnessTest) {
// Create a new channel that requires 1 confs before it's considered // Create a new channel that requires 1 confs before it's considered
// open, then broadcast the funding transaction // open, then broadcast the funding transaction
chanAmt := lnd.MaxBtcFundingAmount chanAmt := funding.MaxBtcFundingAmount
pushAmt := btcutil.Amount(0) pushAmt := btcutil.Amount(0)
ctxt, _ := context.WithTimeout(ctxb, channelOpenTimeout) ctxt, _ := context.WithTimeout(ctxb, channelOpenTimeout)
pendingUpdate, err := net.OpenPendingChannel(ctxt, net.Alice, net.Bob, pendingUpdate, err := net.OpenPendingChannel(ctxt, net.Alice, net.Bob,
@ -2738,7 +2739,7 @@ func testDisconnectingTargetPeer(net *lntest.NetworkHarness, t *harnessTest) {
t.Fatalf("unable to send coins to alice: %v", err) t.Fatalf("unable to send coins to alice: %v", err)
} }
chanAmt := lnd.MaxBtcFundingAmount chanAmt := funding.MaxBtcFundingAmount
pushAmt := btcutil.Amount(0) pushAmt := btcutil.Amount(0)
// Create a new channel that requires 1 confs before it's considered // Create a new channel that requires 1 confs before it's considered
@ -2873,7 +2874,7 @@ func testDisconnectingTargetPeer(net *lntest.NetworkHarness, t *harnessTest) {
func testChannelFundingPersistence(net *lntest.NetworkHarness, t *harnessTest) { func testChannelFundingPersistence(net *lntest.NetworkHarness, t *harnessTest) {
ctxb := context.Background() ctxb := context.Background()
chanAmt := lnd.MaxBtcFundingAmount chanAmt := funding.MaxBtcFundingAmount
pushAmt := btcutil.Amount(0) pushAmt := btcutil.Amount(0)
// As we need to create a channel that requires more than 1 // As we need to create a channel that requires more than 1
@ -3061,7 +3062,7 @@ func testChannelBalance(net *lntest.NetworkHarness, t *harnessTest) {
// Open a channel with 0.16 BTC between Alice and Bob, ensuring the // Open a channel with 0.16 BTC between Alice and Bob, ensuring the
// channel has been opened properly. // channel has been opened properly.
amount := lnd.MaxBtcFundingAmount amount := funding.MaxBtcFundingAmount
// Creates a helper closure to be used below which asserts the proper // Creates a helper closure to be used below which asserts the proper
// response to a channel balance RPC. // response to a channel balance RPC.
@ -6169,7 +6170,7 @@ func testSendToRouteErrorPropagation(net *lntest.NetworkHarness, t *harnessTest)
func testUnannouncedChannels(net *lntest.NetworkHarness, t *harnessTest) { func testUnannouncedChannels(net *lntest.NetworkHarness, t *harnessTest) {
ctxb := context.Background() ctxb := context.Background()
amount := lnd.MaxBtcFundingAmount amount := funding.MaxBtcFundingAmount
// Open a channel between Alice and Bob, ensuring the // Open a channel between Alice and Bob, ensuring the
// channel has been opened properly. // channel has been opened properly.
@ -7408,7 +7409,7 @@ func testBasicChannelCreationAndUpdates(net *lntest.NetworkHarness, t *harnessTe
ctxb := context.Background() ctxb := context.Background()
const ( const (
numChannels = 2 numChannels = 2
amount = lnd.MaxBtcFundingAmount amount = funding.MaxBtcFundingAmount
) )
// Subscribe Bob and Alice to channel event notifications. // Subscribe Bob and Alice to channel event notifications.
@ -7572,7 +7573,7 @@ func testMaxPendingChannels(net *lntest.NetworkHarness, t *harnessTest) {
ctxb := context.Background() ctxb := context.Background()
maxPendingChannels := lncfg.DefaultMaxPendingChannels + 1 maxPendingChannels := lncfg.DefaultMaxPendingChannels + 1
amount := lnd.MaxBtcFundingAmount amount := funding.MaxBtcFundingAmount
// Create a new node (Carol) with greater number of max pending // Create a new node (Carol) with greater number of max pending
// channels. // channels.
@ -8183,7 +8184,7 @@ func testRevokedCloseRetribution(net *lntest.NetworkHarness, t *harnessTest) {
ctxb := context.Background() ctxb := context.Background()
const ( const (
chanAmt = lnd.MaxBtcFundingAmount chanAmt = funding.MaxBtcFundingAmount
paymentAmt = 10000 paymentAmt = 10000
numInvoices = 6 numInvoices = 6
) )
@ -8452,7 +8453,7 @@ func testRevokedCloseRetributionZeroValueRemoteOutput(net *lntest.NetworkHarness
ctxb := context.Background() ctxb := context.Background()
const ( const (
chanAmt = lnd.MaxBtcFundingAmount chanAmt = funding.MaxBtcFundingAmount
paymentAmt = 10000 paymentAmt = 10000
numInvoices = 6 numInvoices = 6
) )
@ -8701,7 +8702,7 @@ func testRevokedCloseRetributionRemoteHodl(net *lntest.NetworkHarness,
ctxb := context.Background() ctxb := context.Background()
const ( const (
chanAmt = lnd.MaxBtcFundingAmount chanAmt = funding.MaxBtcFundingAmount
pushAmt = 200000 pushAmt = 200000
paymentAmt = 10000 paymentAmt = 10000
numInvoices = 6 numInvoices = 6
@ -8747,7 +8748,7 @@ func testRevokedCloseRetributionRemoteHodl(net *lntest.NetworkHarness,
// In order to test Dave's response to an uncooperative channel closure // In order to test Dave's response to an uncooperative channel closure
// by Carol, we'll first open up a channel between them with a // by Carol, we'll first open up a channel between them with a
// lnd.MaxBtcFundingAmount (2^24) satoshis value. // funding.MaxBtcFundingAmount (2^24) satoshis value.
ctxt, _ = context.WithTimeout(ctxb, channelOpenTimeout) ctxt, _ = context.WithTimeout(ctxb, channelOpenTimeout)
chanPoint := openChannelAndAssert( chanPoint := openChannelAndAssert(
ctxt, t, net, dave, carol, ctxt, t, net, dave, carol,
@ -9165,7 +9166,7 @@ func testRevokedCloseRetributionAltruistWatchtowerCase(
ctxb := context.Background() ctxb := context.Background()
const ( const (
chanAmt = lnd.MaxBtcFundingAmount chanAmt = funding.MaxBtcFundingAmount
paymentAmt = 10000 paymentAmt = 10000
numInvoices = 6 numInvoices = 6
externalIP = "1.2.3.4" externalIP = "1.2.3.4"
@ -9739,7 +9740,7 @@ func assertDLPExecuted(net *lntest.NetworkHarness, t *harnessTest,
func testDataLossProtection(net *lntest.NetworkHarness, t *harnessTest) { func testDataLossProtection(net *lntest.NetworkHarness, t *harnessTest) {
ctxb := context.Background() ctxb := context.Background()
const ( const (
chanAmt = lnd.MaxBtcFundingAmount chanAmt = funding.MaxBtcFundingAmount
paymentAmt = 10000 paymentAmt = 10000
numInvoices = 6 numInvoices = 6
) )
@ -10329,7 +10330,7 @@ func subscribeGraphNotifications(t *harnessTest, ctxb context.Context,
func testGraphTopologyNotifications(net *lntest.NetworkHarness, t *harnessTest) { func testGraphTopologyNotifications(net *lntest.NetworkHarness, t *harnessTest) {
ctxb := context.Background() ctxb := context.Background()
const chanAmt = lnd.MaxBtcFundingAmount const chanAmt = funding.MaxBtcFundingAmount
// Let Alice subscribe to graph notifications. // Let Alice subscribe to graph notifications.
graphSub := subscribeGraphNotifications( graphSub := subscribeGraphNotifications(
@ -10656,7 +10657,7 @@ func testNodeAnnouncement(net *lntest.NetworkHarness, t *harnessTest) {
func testNodeSignVerify(net *lntest.NetworkHarness, t *harnessTest) { func testNodeSignVerify(net *lntest.NetworkHarness, t *harnessTest) {
ctxb := context.Background() ctxb := context.Background()
chanAmt := lnd.MaxBtcFundingAmount chanAmt := funding.MaxBtcFundingAmount
pushAmt := btcutil.Amount(100000) pushAmt := btcutil.Amount(100000)
// Create a channel between alice and bob. // Create a channel between alice and bob.
@ -13198,7 +13199,7 @@ func testAbandonChannel(net *lntest.NetworkHarness, t *harnessTest) {
// First establish a channel between Alice and Bob. // First establish a channel between Alice and Bob.
channelParam := lntest.OpenChannelParams{ channelParam := lntest.OpenChannelParams{
Amt: lnd.MaxBtcFundingAmount, Amt: funding.MaxBtcFundingAmount,
PushAmt: btcutil.Amount(100000), PushAmt: btcutil.Amount(100000),
} }
@ -13991,7 +13992,7 @@ func testExternalFundingChanPoint(net *lntest.NetworkHarness, t *harnessTest) {
// flow. To start with, we'll create a pending channel with a shim for // flow. To start with, we'll create a pending channel with a shim for
// a transaction that will never be published. // a transaction that will never be published.
const thawHeight uint32 = 10 const thawHeight uint32 = 10
const chanSize = lnd.MaxBtcFundingAmount const chanSize = funding.MaxBtcFundingAmount
fundingShim1, chanPoint1, _ := deriveFundingShim( fundingShim1, chanPoint1, _ := deriveFundingShim(
net, t, carol, dave, chanSize, thawHeight, 1, false, net, t, carol, dave, chanSize, thawHeight, 1, false,
) )

@ -5,7 +5,7 @@ import (
"strings" "strings"
"github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil"
"github.com/lightningnetwork/lnd" "github.com/lightningnetwork/lnd/funding"
"github.com/lightningnetwork/lnd/lntest" "github.com/lightningnetwork/lnd/lntest"
) )
@ -48,7 +48,7 @@ func testWumboChannels(net *lntest.NetworkHarness, t *harnessTest) {
t.Fatalf("unable to connect peers: %v", err) t.Fatalf("unable to connect peers: %v", err)
} }
chanAmt := lnd.MaxBtcFundingAmount + 1 chanAmt := funding.MaxBtcFundingAmount + 1
_, err = net.OpenChannel( _, err = net.OpenChannel(
ctxb, wumboNode, miniNode, lntest.OpenChannelParams{ ctxb, wumboNode, miniNode, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,

3
log.go

@ -18,6 +18,7 @@ import (
"github.com/lightningnetwork/lnd/channelnotifier" "github.com/lightningnetwork/lnd/channelnotifier"
"github.com/lightningnetwork/lnd/contractcourt" "github.com/lightningnetwork/lnd/contractcourt"
"github.com/lightningnetwork/lnd/discovery" "github.com/lightningnetwork/lnd/discovery"
"github.com/lightningnetwork/lnd/funding"
"github.com/lightningnetwork/lnd/healthcheck" "github.com/lightningnetwork/lnd/healthcheck"
"github.com/lightningnetwork/lnd/htlcswitch" "github.com/lightningnetwork/lnd/htlcswitch"
"github.com/lightningnetwork/lnd/invoices" "github.com/lightningnetwork/lnd/invoices"
@ -81,7 +82,6 @@ var (
ltndLog = addLndPkgLogger("LTND") ltndLog = addLndPkgLogger("LTND")
rpcsLog = addLndPkgLogger("RPCS") rpcsLog = addLndPkgLogger("RPCS")
srvrLog = addLndPkgLogger("SRVR") srvrLog = addLndPkgLogger("SRVR")
fndgLog = addLndPkgLogger("FNDG")
utxnLog = addLndPkgLogger("UTXN") utxnLog = addLndPkgLogger("UTXN")
brarLog = addLndPkgLogger("BRAR") brarLog = addLndPkgLogger("BRAR")
atplLog = addLndPkgLogger("ATPL") atplLog = addLndPkgLogger("ATPL")
@ -135,6 +135,7 @@ func SetupLoggers(root *build.RotatingLogWriter) {
AddSubLogger(root, healthcheck.Subsystem, healthcheck.UseLogger) AddSubLogger(root, healthcheck.Subsystem, healthcheck.UseLogger)
AddSubLogger(root, chainreg.Subsystem, chainreg.UseLogger) AddSubLogger(root, chainreg.Subsystem, chainreg.UseLogger)
AddSubLogger(root, chanacceptor.Subsystem, chanacceptor.UseLogger) AddSubLogger(root, chanacceptor.Subsystem, chanacceptor.UseLogger)
AddSubLogger(root, funding.Subsystem, funding.UseLogger)
} }
// AddSubLogger is a helper method to conveniently create and register the // AddSubLogger is a helper method to conveniently create and register the

@ -24,7 +24,7 @@ import (
"github.com/lightningnetwork/lnd/contractcourt" "github.com/lightningnetwork/lnd/contractcourt"
"github.com/lightningnetwork/lnd/discovery" "github.com/lightningnetwork/lnd/discovery"
"github.com/lightningnetwork/lnd/feature" "github.com/lightningnetwork/lnd/feature"
"github.com/lightningnetwork/lnd/fmgr" "github.com/lightningnetwork/lnd/funding"
"github.com/lightningnetwork/lnd/htlcswitch" "github.com/lightningnetwork/lnd/htlcswitch"
"github.com/lightningnetwork/lnd/htlcswitch/hodl" "github.com/lightningnetwork/lnd/htlcswitch/hodl"
"github.com/lightningnetwork/lnd/htlcswitch/hop" "github.com/lightningnetwork/lnd/htlcswitch/hop"
@ -273,8 +273,8 @@ type Config struct {
FetchLastChanUpdate func(lnwire.ShortChannelID) (*lnwire.ChannelUpdate, FetchLastChanUpdate func(lnwire.ShortChannelID) (*lnwire.ChannelUpdate,
error) error)
// FundingManager is an implementation of the fmgr.Manager interface. // FundingManager is an implementation of the funding.Controller interface.
FundingManager fmgr.Manager FundingManager funding.Controller
// Hodl is used when creating ChannelLinks to specify HodlFlags as // Hodl is used when creating ChannelLinks to specify HodlFlags as
// breakpoints in dev builds. // breakpoints in dev builds.

@ -10,6 +10,7 @@ import (
"github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil"
"github.com/lightningnetwork/lnd/autopilot" "github.com/lightningnetwork/lnd/autopilot"
"github.com/lightningnetwork/lnd/chainreg" "github.com/lightningnetwork/lnd/chainreg"
"github.com/lightningnetwork/lnd/funding"
"github.com/lightningnetwork/lnd/lncfg" "github.com/lightningnetwork/lnd/lncfg"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/tor" "github.com/lightningnetwork/lnd/tor"
@ -97,18 +98,18 @@ func (c *chanController) OpenChannel(target *btcec.PublicKey,
// Construct the open channel request and send it to the server to begin // Construct the open channel request and send it to the server to begin
// the funding workflow. // the funding workflow.
req := &openChanReq{ req := &funding.InitFundingMsg{
targetPubkey: target, TargetPubkey: target,
chainHash: *c.netParams.GenesisHash, ChainHash: *c.netParams.GenesisHash,
subtractFees: true, SubtractFees: true,
localFundingAmt: amt, LocalFundingAmt: amt,
pushAmt: 0, PushAmt: 0,
minHtlcIn: c.chanMinHtlcIn, MinHtlcIn: c.chanMinHtlcIn,
fundingFeePerKw: feePerKw, FundingFeePerKw: feePerKw,
private: c.private, Private: c.private,
remoteCsvDelay: 0, RemoteCsvDelay: 0,
minConfs: c.minConfs, MinConfs: c.minConfs,
maxValueInFlight: 0, MaxValueInFlight: 0,
} }
updateStream, errChan := c.server.OpenChannel(req) updateStream, errChan := c.server.OpenChannel(req)

@ -42,6 +42,7 @@ import (
"github.com/lightningnetwork/lnd/contractcourt" "github.com/lightningnetwork/lnd/contractcourt"
"github.com/lightningnetwork/lnd/discovery" "github.com/lightningnetwork/lnd/discovery"
"github.com/lightningnetwork/lnd/feature" "github.com/lightningnetwork/lnd/feature"
"github.com/lightningnetwork/lnd/funding"
"github.com/lightningnetwork/lnd/htlcswitch" "github.com/lightningnetwork/lnd/htlcswitch"
"github.com/lightningnetwork/lnd/htlcswitch/hop" "github.com/lightningnetwork/lnd/htlcswitch/hop"
"github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/input"
@ -1760,11 +1761,11 @@ func (r *rpcServer) canOpenChannel() error {
return nil return nil
} }
// praseOpenChannelReq parses an OpenChannelRequest message into the server's // praseOpenChannelReq parses an OpenChannelRequest message into an InitFundingMsg
// native openChanReq struct. The logic is abstracted so that it can be shared // struct. The logic is abstracted so that it can be shared between OpenChannel
// between OpenChannel and OpenChannelSync. // and OpenChannelSync.
func (r *rpcServer) parseOpenChannelReq(in *lnrpc.OpenChannelRequest, func (r *rpcServer) parseOpenChannelReq(in *lnrpc.OpenChannelRequest,
isSync bool) (*openChanReq, error) { isSync bool) (*funding.InitFundingMsg, error) {
rpcsLog.Debugf("[openchannel] request to NodeKey(%x) "+ rpcsLog.Debugf("[openchannel] request to NodeKey(%x) "+
"allocation(us=%v, them=%v)", in.NodePubkey, "allocation(us=%v, them=%v)", in.NodePubkey,
@ -1803,9 +1804,9 @@ func (r *rpcServer) parseOpenChannelReq(in *lnrpc.OpenChannelRequest,
// Restrict the size of the channel we'll actually open. At a later // Restrict the size of the channel we'll actually open. At a later
// level, we'll ensure that the output we create after accounting for // level, we'll ensure that the output we create after accounting for
// fees that a dust output isn't created. // fees that a dust output isn't created.
if localFundingAmt < minChanFundingSize { if localFundingAmt < funding.MinChanFundingSize {
return nil, fmt.Errorf("channel is too small, the minimum "+ return nil, fmt.Errorf("channel is too small, the minimum "+
"channel size is: %v SAT", int64(minChanFundingSize)) "channel size is: %v SAT", int64(funding.MinChanFundingSize))
} }
// Prevent users from submitting a max-htlc value that would exceed the // Prevent users from submitting a max-htlc value that would exceed the
@ -1891,20 +1892,20 @@ func (r *rpcServer) parseOpenChannelReq(in *lnrpc.OpenChannelRequest,
// Instruct the server to trigger the necessary events to attempt to // Instruct the server to trigger the necessary events to attempt to
// open a new channel. A stream is returned in place, this stream will // open a new channel. A stream is returned in place, this stream will
// be used to consume updates of the state of the pending channel. // be used to consume updates of the state of the pending channel.
return &openChanReq{ return &funding.InitFundingMsg{
targetPubkey: nodePubKey, TargetPubkey: nodePubKey,
chainHash: *r.cfg.ActiveNetParams.GenesisHash, ChainHash: *r.cfg.ActiveNetParams.GenesisHash,
localFundingAmt: localFundingAmt, LocalFundingAmt: localFundingAmt,
pushAmt: lnwire.NewMSatFromSatoshis(remoteInitialBalance), PushAmt: lnwire.NewMSatFromSatoshis(remoteInitialBalance),
minHtlcIn: minHtlcIn, MinHtlcIn: minHtlcIn,
fundingFeePerKw: feeRate, FundingFeePerKw: feeRate,
private: in.Private, Private: in.Private,
remoteCsvDelay: remoteCsvDelay, RemoteCsvDelay: remoteCsvDelay,
minConfs: minConfs, MinConfs: minConfs,
shutdownScript: script, ShutdownScript: script,
maxValueInFlight: maxValue, MaxValueInFlight: maxValue,
maxHtlcs: maxHtlcs, MaxHtlcs: maxHtlcs,
maxLocalCsv: uint16(in.MaxLocalCsv), MaxLocalCsv: uint16(in.MaxLocalCsv),
}, nil }, nil
} }
@ -1935,8 +1936,8 @@ func (r *rpcServer) OpenChannel(in *lnrpc.OpenChannelRequest,
// Map the channel point shim into a new // Map the channel point shim into a new
// chanfunding.CannedAssembler that the wallet will use // chanfunding.CannedAssembler that the wallet will use
// to obtain the channel point details. // to obtain the channel point details.
copy(req.pendingChanID[:], chanPointShim.PendingChanId) copy(req.PendingChanID[:], chanPointShim.PendingChanId)
req.chanFunder, err = newFundingShimAssembler( req.ChanFunder, err = newFundingShimAssembler(
chanPointShim, true, r.server.cc.KeyRing, chanPointShim, true, r.server.cc.KeyRing,
) )
if err != nil { if err != nil {
@ -1953,9 +1954,9 @@ func (r *rpcServer) OpenChannel(in *lnrpc.OpenChannelRequest,
// Instruct the wallet to use the new // Instruct the wallet to use the new
// chanfunding.PsbtAssembler to construct the funding // chanfunding.PsbtAssembler to construct the funding
// transaction. // transaction.
copy(req.pendingChanID[:], psbtShim.PendingChanId) copy(req.PendingChanID[:], psbtShim.PendingChanId)
req.chanFunder, err = newPsbtAssembler( req.ChanFunder, err = newPsbtAssembler(
in, req.minConfs, psbtShim, in, req.MinConfs, psbtShim,
&r.server.cc.Wallet.Cfg.NetParams, &r.server.cc.Wallet.Cfg.NetParams,
) )
if err != nil { if err != nil {
@ -1972,7 +1973,7 @@ out:
select { select {
case err := <-errChan: case err := <-errChan:
rpcsLog.Errorf("unable to open channel to NodeKey(%x): %v", rpcsLog.Errorf("unable to open channel to NodeKey(%x): %v",
req.targetPubkey.SerializeCompressed(), err) req.TargetPubkey.SerializeCompressed(), err)
return err return err
case fundingUpdate := <-updateChan: case fundingUpdate := <-updateChan:
rpcsLog.Tracef("[openchannel] sending update: %v", rpcsLog.Tracef("[openchannel] sending update: %v",
@ -2004,7 +2005,7 @@ out:
} }
rpcsLog.Tracef("[openchannel] success NodeKey(%x), ChannelPoint(%v)", rpcsLog.Tracef("[openchannel] success NodeKey(%x), ChannelPoint(%v)",
req.targetPubkey.SerializeCompressed(), outpoint) req.TargetPubkey.SerializeCompressed(), outpoint)
return nil return nil
} }
@ -2029,7 +2030,7 @@ func (r *rpcServer) OpenChannelSync(ctx context.Context,
// If an error occurs them immediately return the error to the client. // If an error occurs them immediately return the error to the client.
case err := <-errChan: case err := <-errChan:
rpcsLog.Errorf("unable to open channel to NodeKey(%x): %v", rpcsLog.Errorf("unable to open channel to NodeKey(%x): %v",
req.targetPubkey.SerializeCompressed(), err) req.TargetPubkey.SerializeCompressed(), err)
return nil, err return nil, err
// Otherwise, wait for the first channel update. The first update sent // Otherwise, wait for the first channel update. The first update sent

115
server.go

@ -39,6 +39,7 @@ import (
"github.com/lightningnetwork/lnd/contractcourt" "github.com/lightningnetwork/lnd/contractcourt"
"github.com/lightningnetwork/lnd/discovery" "github.com/lightningnetwork/lnd/discovery"
"github.com/lightningnetwork/lnd/feature" "github.com/lightningnetwork/lnd/feature"
"github.com/lightningnetwork/lnd/funding"
"github.com/lightningnetwork/lnd/healthcheck" "github.com/lightningnetwork/lnd/healthcheck"
"github.com/lightningnetwork/lnd/htlcswitch" "github.com/lightningnetwork/lnd/htlcswitch"
"github.com/lightningnetwork/lnd/htlcswitch/hop" "github.com/lightningnetwork/lnd/htlcswitch/hop"
@ -51,7 +52,6 @@ import (
"github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/lnwallet/chainfee"
"github.com/lightningnetwork/lnd/lnwallet/chanfunding"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/nat" "github.com/lightningnetwork/lnd/nat"
"github.com/lightningnetwork/lnd/netann" "github.com/lightningnetwork/lnd/netann"
@ -114,6 +114,17 @@ var (
// validColorRegexp is a regexp that lets you check if a particular // validColorRegexp is a regexp that lets you check if a particular
// color string matches the standard hex color format #RRGGBB. // color string matches the standard hex color format #RRGGBB.
validColorRegexp = regexp.MustCompile("^#[A-Fa-f0-9]{6}$") validColorRegexp = regexp.MustCompile("^#[A-Fa-f0-9]{6}$")
// MaxFundingAmount is a soft-limit of the maximum channel size
// currently accepted within the Lightning Protocol. This is
// defined in BOLT-0002, and serves as an initial precautionary limit
// while implementations are battle tested in the real world.
//
// At the moment, this value depends on which chain is active. It is set
// to the value under the Bitcoin chain as default.
//
// TODO(roasbeef): add command line param to modify
MaxFundingAmount = funding.MaxBtcFundingAmount
) )
// errPeerAlreadyConnected is an error returned by the server when we're // errPeerAlreadyConnected is an error returned by the server when we're
@ -207,7 +218,7 @@ type server struct {
cc *chainreg.ChainControl cc *chainreg.ChainControl
fundingMgr *fundingManager fundingMgr *funding.Manager
localChanDB *channeldb.DB localChanDB *channeldb.DB
@ -977,12 +988,12 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
// Litecoin, depending on the primary registered chain. // Litecoin, depending on the primary registered chain.
primaryChain := cfg.registeredChains.PrimaryChain() primaryChain := cfg.registeredChains.PrimaryChain()
chainCfg := cfg.Bitcoin chainCfg := cfg.Bitcoin
minRemoteDelay := minBtcRemoteDelay minRemoteDelay := funding.MinBtcRemoteDelay
maxRemoteDelay := maxBtcRemoteDelay maxRemoteDelay := funding.MaxBtcRemoteDelay
if primaryChain == chainreg.LitecoinChain { if primaryChain == chainreg.LitecoinChain {
chainCfg = cfg.Litecoin chainCfg = cfg.Litecoin
minRemoteDelay = minLtcRemoteDelay minRemoteDelay = funding.MinLtcRemoteDelay
maxRemoteDelay = maxLtcRemoteDelay maxRemoteDelay = funding.MaxLtcRemoteDelay
} }
var chanIDSeed [32]byte var chanIDSeed [32]byte
@ -990,7 +1001,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
return nil, err return nil, err
} }
s.fundingMgr, err = newFundingManager(fundingConfig{ s.fundingMgr, err = funding.NewFundingManager(funding.Config{
NoWumboChans: !cfg.ProtocolOptions.Wumbo(), NoWumboChans: !cfg.ProtocolOptions.Wumbo(),
IDKey: nodeKeyECDH.PubKey(), IDKey: nodeKeyECDH.PubKey(),
Wallet: cc.Wallet, Wallet: cc.Wallet,
@ -3472,63 +3483,6 @@ func (s *server) removePeer(p *peer.Brontide) {
s.peerNotifier.NotifyPeerOffline(pubKey) s.peerNotifier.NotifyPeerOffline(pubKey)
} }
// openChanReq is a message sent to the server in order to request the
// initiation of a channel funding workflow to the peer with either the
// specified relative peer ID, or a global lightning ID.
type openChanReq struct {
targetPubkey *btcec.PublicKey
chainHash chainhash.Hash
subtractFees bool
localFundingAmt btcutil.Amount
pushAmt lnwire.MilliSatoshi
fundingFeePerKw chainfee.SatPerKWeight
private bool
// minHtlcIn is the minimum incoming htlc that we accept.
minHtlcIn lnwire.MilliSatoshi
remoteCsvDelay uint16
// minConfs indicates the minimum number of confirmations that each
// output selected to fund the channel should satisfy.
minConfs int32
// shutdownScript is an optional upfront shutdown script for the channel.
// This value is optional, so may be nil.
shutdownScript lnwire.DeliveryAddress
// maxValueInFlight is the maximum amount of coins in millisatoshi that can
// be pending within the channel. It only applies to the remote party.
maxValueInFlight lnwire.MilliSatoshi
maxHtlcs uint16
// maxLocalCsv is the maximum local csv delay we will accept from our
// peer.
maxLocalCsv uint16
// TODO(roasbeef): add ability to specify channel constraints as well
// chanFunder is an optional channel funder that allows the caller to
// control exactly how the channel funding is carried out. If not
// specified, then the default chanfunding.WalletAssembler will be
// used.
chanFunder chanfunding.Assembler
// pendingChanID is not all zeroes (the default value), then this will
// be the pending channel ID used for the funding flow within the wire
// protocol.
pendingChanID [32]byte
updates chan *lnrpc.OpenStatusUpdate
err chan error
}
// ConnectToPeer requests that the server connect to a Lightning Network peer // ConnectToPeer requests that the server connect to a Lightning Network peer
// at the specified address. This function will *block* until either a // at the specified address. This function will *block* until either a
// connection is established, or the initial handshake process fails. // connection is established, or the initial handshake process fails.
@ -3673,25 +3627,26 @@ func (s *server) DisconnectPeer(pubKey *btcec.PublicKey) error {
// //
// NOTE: This function is safe for concurrent access. // NOTE: This function is safe for concurrent access.
func (s *server) OpenChannel( func (s *server) OpenChannel(
req *openChanReq) (chan *lnrpc.OpenStatusUpdate, chan error) { req *funding.InitFundingMsg) (chan *lnrpc.OpenStatusUpdate, chan error) {
// The updateChan will have a buffer of 2, since we expect a ChanPending // The updateChan will have a buffer of 2, since we expect a ChanPending
// + a ChanOpen update, and we want to make sure the funding process is // + a ChanOpen update, and we want to make sure the funding process is
// not blocked if the caller is not reading the updates. // not blocked if the caller is not reading the updates.
req.updates = make(chan *lnrpc.OpenStatusUpdate, 2) req.Updates = make(chan *lnrpc.OpenStatusUpdate, 2)
req.err = make(chan error, 1) req.Err = make(chan error, 1)
// First attempt to locate the target peer to open a channel with, if // First attempt to locate the target peer to open a channel with, if
// we're unable to locate the peer then this request will fail. // we're unable to locate the peer then this request will fail.
pubKeyBytes := req.targetPubkey.SerializeCompressed() pubKeyBytes := req.TargetPubkey.SerializeCompressed()
s.mu.RLock() s.mu.RLock()
peer, ok := s.peersByPub[string(pubKeyBytes)] peer, ok := s.peersByPub[string(pubKeyBytes)]
if !ok { if !ok {
s.mu.RUnlock() s.mu.RUnlock()
req.err <- fmt.Errorf("peer %x is not online", pubKeyBytes) req.Err <- fmt.Errorf("peer %x is not online", pubKeyBytes)
return req.updates, req.err return req.Updates, req.Err
} }
req.Peer = peer
s.mu.RUnlock() s.mu.RUnlock()
// We'll wait until the peer is active before beginning the channel // We'll wait until the peer is active before beginning the channel
@ -3699,32 +3654,32 @@ func (s *server) OpenChannel(
select { select {
case <-peer.ActiveSignal(): case <-peer.ActiveSignal():
case <-peer.QuitSignal(): case <-peer.QuitSignal():
req.err <- fmt.Errorf("peer %x disconnected", pubKeyBytes) req.Err <- fmt.Errorf("peer %x disconnected", pubKeyBytes)
return req.updates, req.err return req.Updates, req.Err
case <-s.quit: case <-s.quit:
req.err <- ErrServerShuttingDown req.Err <- ErrServerShuttingDown
return req.updates, req.err return req.Updates, req.Err
} }
// If the fee rate wasn't specified, then we'll use a default // If the fee rate wasn't specified, then we'll use a default
// confirmation target. // confirmation target.
if req.fundingFeePerKw == 0 { if req.FundingFeePerKw == 0 {
estimator := s.cc.FeeEstimator estimator := s.cc.FeeEstimator
feeRate, err := estimator.EstimateFeePerKW(6) feeRate, err := estimator.EstimateFeePerKW(6)
if err != nil { if err != nil {
req.err <- err req.Err <- err
return req.updates, req.err return req.Updates, req.Err
} }
req.fundingFeePerKw = feeRate req.FundingFeePerKw = feeRate
} }
// Spawn a goroutine to send the funding workflow request to the funding // Spawn a goroutine to send the funding workflow request to the funding
// manager. This allows the server to continue handling queries instead // manager. This allows the server to continue handling queries instead
// of blocking on this request which is exported as a synchronous // of blocking on this request which is exported as a synchronous
// request to the outside world. // request to the outside world.
go s.fundingMgr.initFundingWorkflow(peer, req) go s.fundingMgr.InitFundingWorkflow(req)
return req.updates, req.err return req.Updates, req.Err
} }
// Peers returns a slice of all active peers. // Peers returns a slice of all active peers.