fundingmanager+lnwallet: add HTLC dust limit logic
This commit is contained in:
parent
c731156ac8
commit
d01f1b5ff4
@ -335,6 +335,8 @@ func (f *fundingManager) handleFundingRequest(fmsg *fundingRequestMsg) {
|
|||||||
fndgLog.Infof("Recv'd fundingRequest(amt=%v, delay=%v, pendingId=%v) "+
|
fndgLog.Infof("Recv'd fundingRequest(amt=%v, delay=%v, pendingId=%v) "+
|
||||||
"from peerID(%v)", amt, delay, msg.ChannelID, fmsg.peer.id)
|
"from peerID(%v)", amt, delay, msg.ChannelID, fmsg.peer.id)
|
||||||
|
|
||||||
|
ourDustLimit := lnwallet.DefaultDustLimit()
|
||||||
|
theirDustlimit := msg.DustLimit
|
||||||
// Attempt to initialize a reservation within the wallet. If the wallet
|
// Attempt to initialize a reservation within the wallet. If the wallet
|
||||||
// has insufficient resources to create the channel, then the reservation
|
// has insufficient resources to create the channel, then the reservation
|
||||||
// attempt may be rejected. Note that since we're on the responding
|
// attempt may be rejected. Note that since we're on the responding
|
||||||
@ -342,7 +344,8 @@ func (f *fundingManager) handleFundingRequest(fmsg *fundingRequestMsg) {
|
|||||||
// channel ourselves.
|
// channel ourselves.
|
||||||
// TODO(roasbeef): passing num confs 1 is irrelevant here, make signed?
|
// TODO(roasbeef): passing num confs 1 is irrelevant here, make signed?
|
||||||
reservation, err := f.wallet.InitChannelReservation(amt, 0,
|
reservation, err := f.wallet.InitChannelReservation(amt, 0,
|
||||||
fmsg.peer.addr.IdentityKey, fmsg.peer.addr.Address, 1, delay)
|
fmsg.peer.addr.IdentityKey, fmsg.peer.addr.Address, 1, delay,
|
||||||
|
ourDustLimit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO(roasbeef): push ErrorGeneric message
|
// TODO(roasbeef): push ErrorGeneric message
|
||||||
fndgLog.Errorf("Unable to initialize reservation: %v", err)
|
fndgLog.Errorf("Unable to initialize reservation: %v", err)
|
||||||
@ -350,6 +353,8 @@ func (f *fundingManager) handleFundingRequest(fmsg *fundingRequestMsg) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reservation.SetTheirDustLimit(theirDustlimit)
|
||||||
|
|
||||||
// Once the reservation has been created successfully, we add it to this
|
// Once the reservation has been created successfully, we add it to this
|
||||||
// peers map of pending reservations to track this particular reservation
|
// peers map of pending reservations to track this particular reservation
|
||||||
// until either abort or completion.
|
// until either abort or completion.
|
||||||
@ -396,7 +401,7 @@ func (f *fundingManager) handleFundingRequest(fmsg *fundingRequestMsg) {
|
|||||||
fundingResp := lnwire.NewSingleFundingResponse(msg.ChannelID,
|
fundingResp := lnwire.NewSingleFundingResponse(msg.ChannelID,
|
||||||
ourContribution.RevocationKey, ourContribution.CommitKey,
|
ourContribution.RevocationKey, ourContribution.CommitKey,
|
||||||
ourContribution.MultiSigKey, ourContribution.CsvDelay,
|
ourContribution.MultiSigKey, ourContribution.CsvDelay,
|
||||||
deliveryScript)
|
deliveryScript, ourDustLimit)
|
||||||
|
|
||||||
fmsg.peer.queueMsg(fundingResp, nil)
|
fmsg.peer.queueMsg(fundingResp, nil)
|
||||||
}
|
}
|
||||||
@ -425,6 +430,8 @@ func (f *fundingManager) handleFundingResponse(fmsg *fundingResponseMsg) {
|
|||||||
|
|
||||||
fndgLog.Infof("Recv'd fundingResponse for pendingID(%v)", msg.ChannelID)
|
fndgLog.Infof("Recv'd fundingResponse for pendingID(%v)", msg.ChannelID)
|
||||||
|
|
||||||
|
resCtx.reservation.SetTheirDustLimit(msg.DustLimit)
|
||||||
|
|
||||||
// The remote node has responded with their portion of the channel
|
// The remote node has responded with their portion of the channel
|
||||||
// contribution. At this point, we can process their contribution which
|
// contribution. At this point, we can process their contribution which
|
||||||
// allows us to construct and sign both the commitment transaction, and
|
// allows us to construct and sign both the commitment transaction, and
|
||||||
@ -747,22 +754,24 @@ func (f *fundingManager) initFundingWorkflow(targetPeer *peer, req *openChanReq)
|
|||||||
func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
|
func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
|
||||||
var (
|
var (
|
||||||
// TODO(roasbeef): add delay
|
// TODO(roasbeef): add delay
|
||||||
nodeID = msg.peer.addr.IdentityKey
|
nodeID = msg.peer.addr.IdentityKey
|
||||||
localAmt = msg.localFundingAmt
|
localAmt = msg.localFundingAmt
|
||||||
remoteAmt = msg.remoteFundingAmt
|
remoteAmt = msg.remoteFundingAmt
|
||||||
capacity = localAmt + remoteAmt
|
capacity = localAmt + remoteAmt
|
||||||
numConfs = msg.numConfs
|
numConfs = msg.numConfs
|
||||||
|
ourDustLimit = lnwallet.DefaultDustLimit()
|
||||||
)
|
)
|
||||||
|
|
||||||
fndgLog.Infof("Initiating fundingRequest(localAmt=%v, remoteAmt=%v, "+
|
fndgLog.Infof("Initiating fundingRequest(localAmt=%v, remoteAmt=%v, "+
|
||||||
"capacity=%v, numConfs=%v, addr=%v)", localAmt, remoteAmt,
|
"capacity=%v, numConfs=%v, addr=%v, dustLimit=%v)", localAmt,
|
||||||
capacity, numConfs, msg.peer.addr.Address)
|
remoteAmt, ourDustLimit, capacity, numConfs,
|
||||||
|
msg.peer.addr.Address)
|
||||||
|
|
||||||
// Initialize a funding reservation with the local wallet. If the
|
// Initialize a funding reservation with the local wallet. If the
|
||||||
// wallet doesn't have enough funds to commit to this channel, then
|
// wallet doesn't have enough funds to commit to this channel, then
|
||||||
// the request will fail, and be aborted.
|
// the request will fail, and be aborted.
|
||||||
reservation, err := f.wallet.InitChannelReservation(capacity, localAmt,
|
reservation, err := f.wallet.InitChannelReservation(capacity, localAmt,
|
||||||
nodeID, msg.peer.addr.Address, uint16(numConfs), 4)
|
nodeID, msg.peer.addr.Address, uint16(numConfs), 4, ourDustLimit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msg.err <- err
|
msg.err <- err
|
||||||
return
|
return
|
||||||
@ -815,6 +824,7 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
|
|||||||
contribution.CommitKey,
|
contribution.CommitKey,
|
||||||
contribution.MultiSigKey,
|
contribution.MultiSigKey,
|
||||||
deliveryScript,
|
deliveryScript,
|
||||||
|
ourDustLimit,
|
||||||
)
|
)
|
||||||
msg.peer.queueMsg(fundingReq, nil)
|
msg.peer.queueMsg(fundingReq, nil)
|
||||||
}
|
}
|
||||||
|
@ -881,19 +881,21 @@ func (lc *LightningChannel) fetchCommitmentView(remoteChain bool,
|
|||||||
var selfKey *btcec.PublicKey
|
var selfKey *btcec.PublicKey
|
||||||
var remoteKey *btcec.PublicKey
|
var remoteKey *btcec.PublicKey
|
||||||
var delay uint32
|
var delay uint32
|
||||||
var delayBalance, p2wkhBalance btcutil.Amount
|
var delayBalance, p2wkhBalance, dustLimit btcutil.Amount
|
||||||
if remoteChain {
|
if remoteChain {
|
||||||
selfKey = lc.channelState.TheirCommitKey
|
selfKey = lc.channelState.TheirCommitKey
|
||||||
remoteKey = lc.channelState.OurCommitKey
|
remoteKey = lc.channelState.OurCommitKey
|
||||||
delay = lc.channelState.RemoteCsvDelay
|
delay = lc.channelState.RemoteCsvDelay
|
||||||
delayBalance = theirBalance
|
delayBalance = theirBalance
|
||||||
p2wkhBalance = ourBalance
|
p2wkhBalance = ourBalance
|
||||||
|
dustLimit = lc.channelState.TheirDustLimit
|
||||||
} else {
|
} else {
|
||||||
selfKey = lc.channelState.OurCommitKey
|
selfKey = lc.channelState.OurCommitKey
|
||||||
remoteKey = lc.channelState.TheirCommitKey
|
remoteKey = lc.channelState.TheirCommitKey
|
||||||
delay = lc.channelState.LocalCsvDelay
|
delay = lc.channelState.LocalCsvDelay
|
||||||
delayBalance = ourBalance
|
delayBalance = ourBalance
|
||||||
p2wkhBalance = theirBalance
|
p2wkhBalance = theirBalance
|
||||||
|
dustLimit = lc.channelState.OurDustLimit
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a new commitment transaction with all the latest
|
// Generate a new commitment transaction with all the latest
|
||||||
@ -905,6 +907,10 @@ func (lc *LightningChannel) fetchCommitmentView(remoteChain bool,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, htlc := range filteredHTLCView.ourUpdates {
|
for _, htlc := range filteredHTLCView.ourUpdates {
|
||||||
|
if htlc.Amount < dustLimit {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
err := lc.addHTLC(commitTx, ourCommitTx, htlc,
|
err := lc.addHTLC(commitTx, ourCommitTx, htlc,
|
||||||
revocationHash, delay, false)
|
revocationHash, delay, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -912,6 +918,10 @@ func (lc *LightningChannel) fetchCommitmentView(remoteChain bool,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, htlc := range filteredHTLCView.theirUpdates {
|
for _, htlc := range filteredHTLCView.theirUpdates {
|
||||||
|
if htlc.Amount < dustLimit {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
err := lc.addHTLC(commitTx, ourCommitTx, htlc,
|
err := lc.addHTLC(commitTx, ourCommitTx, htlc,
|
||||||
revocationHash, delay, true)
|
revocationHash, delay, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -188,6 +188,8 @@ func createTestChannels(revocationWindow int) (*LightningChannel, *LightningChan
|
|||||||
|
|
||||||
channelCapacity := btcutil.Amount(10 * 1e8)
|
channelCapacity := btcutil.Amount(10 * 1e8)
|
||||||
channelBal := channelCapacity / 2
|
channelBal := channelCapacity / 2
|
||||||
|
aliceDustLimit := btcutil.Amount(200)
|
||||||
|
bobDustLimit := btcutil.Amount(800)
|
||||||
csvTimeoutAlice := uint32(5)
|
csvTimeoutAlice := uint32(5)
|
||||||
csvTimeoutBob := uint32(4)
|
csvTimeoutBob := uint32(4)
|
||||||
|
|
||||||
@ -265,6 +267,8 @@ func createTestChannels(revocationWindow int) (*LightningChannel, *LightningChan
|
|||||||
TheirCurrentRevocation: bobRevokeKey,
|
TheirCurrentRevocation: bobRevokeKey,
|
||||||
LocalElkrem: aliceElkrem,
|
LocalElkrem: aliceElkrem,
|
||||||
RemoteElkrem: &elkrem.ElkremReceiver{},
|
RemoteElkrem: &elkrem.ElkremReceiver{},
|
||||||
|
TheirDustLimit: bobDustLimit,
|
||||||
|
OurDustLimit: aliceDustLimit,
|
||||||
Db: dbAlice,
|
Db: dbAlice,
|
||||||
}
|
}
|
||||||
bobChannelState := &channeldb.OpenChannel{
|
bobChannelState := &channeldb.OpenChannel{
|
||||||
@ -289,6 +293,8 @@ func createTestChannels(revocationWindow int) (*LightningChannel, *LightningChan
|
|||||||
TheirCurrentRevocation: aliceRevokeKey,
|
TheirCurrentRevocation: aliceRevokeKey,
|
||||||
LocalElkrem: bobElkrem,
|
LocalElkrem: bobElkrem,
|
||||||
RemoteElkrem: &elkrem.ElkremReceiver{},
|
RemoteElkrem: &elkrem.ElkremReceiver{},
|
||||||
|
TheirDustLimit: aliceDustLimit,
|
||||||
|
OurDustLimit: bobDustLimit,
|
||||||
Db: dbBob,
|
Db: dbBob,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -833,6 +839,122 @@ func TestCheckHTLCNumberConstraint(t *testing.T) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestCheckDustLimit checks that unsettled HTLC with dust limit not included in
|
||||||
|
// commitment transaction as output, but sender balance is decreased (thereby all
|
||||||
|
// unsettled dust HTLCs will go to miners fee).
|
||||||
|
func TestCheckDustLimit(t *testing.T) {
|
||||||
|
createHTLC := func(data, amount btcutil.Amount) (*lnwire.HTLCAddRequest,
|
||||||
|
[32]byte) {
|
||||||
|
preimage := bytes.Repeat([]byte{byte(data)}, 32)
|
||||||
|
paymentHash := fastsha256.Sum256(preimage)
|
||||||
|
|
||||||
|
var returnPreimage [32]byte
|
||||||
|
copy(returnPreimage[:], preimage)
|
||||||
|
|
||||||
|
return &lnwire.HTLCAddRequest{
|
||||||
|
RedemptionHashes: [][32]byte{paymentHash},
|
||||||
|
Amount: amount,
|
||||||
|
Expiry: uint32(5),
|
||||||
|
}, returnPreimage
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a test channel which will be used for the duration of this
|
||||||
|
// unittest. The channel will be funded evenly with Alice having 5 BTC,
|
||||||
|
// and Bob having 5 BTC.
|
||||||
|
aliceChannel, bobChannel, cleanUp, err := createTestChannels(3)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create test channels: %v", err)
|
||||||
|
}
|
||||||
|
defer cleanUp()
|
||||||
|
|
||||||
|
aliceDustLimit := aliceChannel.channelState.OurDustLimit
|
||||||
|
bobDustLimit := bobChannel.channelState.OurDustLimit
|
||||||
|
htlcAmount := btcutil.Amount(500)
|
||||||
|
|
||||||
|
if !((htlcAmount > aliceDustLimit) && (bobDustLimit > htlcAmount)) {
|
||||||
|
t.Fatal("htlc amount needs to be above Alice's dust limit, but " +
|
||||||
|
"below Bob's dust limit .")
|
||||||
|
}
|
||||||
|
|
||||||
|
aliceAmount := aliceChannel.channelState.OurBalance
|
||||||
|
bobAmount := bobChannel.channelState.OurBalance
|
||||||
|
|
||||||
|
htlc, preimage := createHTLC(0, htlcAmount)
|
||||||
|
if _, err := aliceChannel.AddHTLC(htlc); err != nil {
|
||||||
|
t.Fatalf("alice unable to add htlc: %v", err)
|
||||||
|
}
|
||||||
|
if _, err := bobChannel.ReceiveHTLC(htlc); err != nil {
|
||||||
|
t.Fatalf("bob unable to receive htlc: %v", err)
|
||||||
|
}
|
||||||
|
if err := forceStateTransition(aliceChannel, bobChannel); err != nil {
|
||||||
|
t.Fatalf("Can't update the channel state: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// First two outputs are payment to them and to us. If we encounter
|
||||||
|
// third output it means that dust HTLC was included. Their channel
|
||||||
|
// balance shouldn't change because, it will be changed only after
|
||||||
|
// HTLC will be settled.
|
||||||
|
|
||||||
|
// From Alice point of view HTLC's amount is bigger then dust limit.
|
||||||
|
commitment := aliceChannel.localCommitChain.tip()
|
||||||
|
if len(commitment.txn.TxOut) != 3 {
|
||||||
|
t.Fatal("htlc wasn't added")
|
||||||
|
}
|
||||||
|
if commitment.ourBalance != aliceAmount-htlcAmount {
|
||||||
|
t.Fatal("our balance wasn't updated")
|
||||||
|
}
|
||||||
|
if commitment.theirBalance != bobAmount {
|
||||||
|
t.Fatal("their balance was updated")
|
||||||
|
}
|
||||||
|
|
||||||
|
// From Bob point of view HTLC's amount is lower then dust limit.
|
||||||
|
commitment = bobChannel.localCommitChain.tip()
|
||||||
|
if len(commitment.txn.TxOut) != 2 {
|
||||||
|
t.Fatal("HTLC with dust amount was added")
|
||||||
|
}
|
||||||
|
if commitment.theirBalance != aliceAmount-htlcAmount {
|
||||||
|
t.Fatal("their balance wasn't updated")
|
||||||
|
}
|
||||||
|
if commitment.ourBalance != bobAmount {
|
||||||
|
t.Fatal("our balance was updated")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Settle HTLC and sign new commitment.
|
||||||
|
settleIndex, err := bobChannel.SettleHTLC(preimage)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("bob unable to settle inbound htlc: %v", err)
|
||||||
|
}
|
||||||
|
err = aliceChannel.ReceiveHTLCSettle(preimage, settleIndex)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("alice unable to accept settle of outbound htlc: %v", err)
|
||||||
|
}
|
||||||
|
if err := forceStateTransition(aliceChannel, bobChannel); err != nil {
|
||||||
|
t.Fatalf("Can't update the channel state: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
commitment = aliceChannel.localCommitChain.tip()
|
||||||
|
if len(commitment.txn.TxOut) != 2 {
|
||||||
|
t.Fatal("HTLC wasn't settled")
|
||||||
|
}
|
||||||
|
if commitment.ourBalance != aliceAmount-htlcAmount {
|
||||||
|
t.Fatal("our balance wasn't updated")
|
||||||
|
}
|
||||||
|
if commitment.theirBalance != bobAmount+htlcAmount {
|
||||||
|
t.Fatal("their balance wasn't updated")
|
||||||
|
}
|
||||||
|
|
||||||
|
commitment = bobChannel.localCommitChain.tip()
|
||||||
|
if len(commitment.txn.TxOut) != 2 {
|
||||||
|
t.Fatal("HTLC with dust amount wasn't settled")
|
||||||
|
}
|
||||||
|
if commitment.ourBalance != bobAmount+htlcAmount {
|
||||||
|
t.Fatal("our balance wasn't updated")
|
||||||
|
}
|
||||||
|
if commitment.theirBalance != aliceAmount-htlcAmount {
|
||||||
|
t.Fatal("their balance wasn't updated")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestStateUpdatePersistence(t *testing.T) {
|
func TestStateUpdatePersistence(t *testing.T) {
|
||||||
// Create a test channel which will be used for the duration of this
|
// Create a test channel which will be used for the duration of this
|
||||||
// unittest. The channel will be funded evenly with Alice having 5 BTC,
|
// unittest. The channel will be funded evenly with Alice having 5 BTC,
|
||||||
|
@ -363,7 +363,7 @@ func testDualFundingReservationWorkflow(miner *rpctest.Harness, wallet *lnwallet
|
|||||||
// Bob initiates a channel funded with 5 BTC for each side, so 10
|
// Bob initiates a channel funded with 5 BTC for each side, so 10
|
||||||
// BTC total. He also generates 2 BTC in change.
|
// BTC total. He also generates 2 BTC in change.
|
||||||
chanReservation, err := wallet.InitChannelReservation(fundingAmount*2,
|
chanReservation, err := wallet.InitChannelReservation(fundingAmount*2,
|
||||||
fundingAmount, bobNode.id, bobAddr, numReqConfs, 4)
|
fundingAmount, bobNode.id, bobAddr, numReqConfs, 4, 540)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to initialize funding reservation: %v", err)
|
t.Fatalf("unable to initialize funding reservation: %v", err)
|
||||||
}
|
}
|
||||||
@ -522,7 +522,7 @@ func testFundingTransactionLockedOutputs(miner *rpctest.Harness,
|
|||||||
// Create a single channel asking for 16 BTC total.
|
// Create a single channel asking for 16 BTC total.
|
||||||
fundingAmount := btcutil.Amount(8 * 1e8)
|
fundingAmount := btcutil.Amount(8 * 1e8)
|
||||||
_, err := wallet.InitChannelReservation(fundingAmount, fundingAmount,
|
_, err := wallet.InitChannelReservation(fundingAmount, fundingAmount,
|
||||||
testPub, bobAddr, numReqConfs, 4)
|
testPub, bobAddr, numReqConfs, 4, 540)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to initialize funding reservation 1: %v", err)
|
t.Fatalf("unable to initialize funding reservation 1: %v", err)
|
||||||
}
|
}
|
||||||
@ -532,7 +532,7 @@ func testFundingTransactionLockedOutputs(miner *rpctest.Harness,
|
|||||||
// that aren't locked, so this should fail.
|
// that aren't locked, so this should fail.
|
||||||
amt := btcutil.Amount(900 * 1e8)
|
amt := btcutil.Amount(900 * 1e8)
|
||||||
failedReservation, err := wallet.InitChannelReservation(amt, amt,
|
failedReservation, err := wallet.InitChannelReservation(amt, amt,
|
||||||
testPub, bobAddr, numReqConfs, 4)
|
testPub, bobAddr, numReqConfs, 4, 540)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("not error returned, should fail on coin selection")
|
t.Fatalf("not error returned, should fail on coin selection")
|
||||||
}
|
}
|
||||||
@ -552,14 +552,14 @@ func testFundingCancellationNotEnoughFunds(miner *rpctest.Harness,
|
|||||||
// Create a reservation for 44 BTC.
|
// Create a reservation for 44 BTC.
|
||||||
fundingAmount := btcutil.Amount(44 * 1e8)
|
fundingAmount := btcutil.Amount(44 * 1e8)
|
||||||
chanReservation, err := wallet.InitChannelReservation(fundingAmount,
|
chanReservation, err := wallet.InitChannelReservation(fundingAmount,
|
||||||
fundingAmount, testPub, bobAddr, numReqConfs, 4)
|
fundingAmount, testPub, bobAddr, numReqConfs, 4, 540)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to initialize funding reservation: %v", err)
|
t.Fatalf("unable to initialize funding reservation: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to create another channel with 44 BTC, this should fail.
|
// Attempt to create another channel with 44 BTC, this should fail.
|
||||||
_, err = wallet.InitChannelReservation(fundingAmount,
|
_, err = wallet.InitChannelReservation(fundingAmount,
|
||||||
fundingAmount, testPub, bobAddr, numReqConfs, 4)
|
fundingAmount, testPub, bobAddr, numReqConfs, 4, 540)
|
||||||
if _, ok := err.(*lnwallet.ErrInsufficientFunds); !ok {
|
if _, ok := err.(*lnwallet.ErrInsufficientFunds); !ok {
|
||||||
t.Fatalf("coin selection succeded should have insufficient funds: %v",
|
t.Fatalf("coin selection succeded should have insufficient funds: %v",
|
||||||
err)
|
err)
|
||||||
@ -589,7 +589,7 @@ func testFundingCancellationNotEnoughFunds(miner *rpctest.Harness,
|
|||||||
|
|
||||||
// Request to fund a new channel should now succeed.
|
// Request to fund a new channel should now succeed.
|
||||||
_, err = wallet.InitChannelReservation(fundingAmount, fundingAmount,
|
_, err = wallet.InitChannelReservation(fundingAmount, fundingAmount,
|
||||||
testPub, bobAddr, numReqConfs, 4)
|
testPub, bobAddr, numReqConfs, 4, 540)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to initialize funding reservation: %v", err)
|
t.Fatalf("unable to initialize funding reservation: %v", err)
|
||||||
}
|
}
|
||||||
@ -628,7 +628,7 @@ func testSingleFunderReservationWorkflowInitiator(miner *rpctest.Harness,
|
|||||||
// Initialize a reservation for a channel with 4 BTC funded solely by us.
|
// Initialize a reservation for a channel with 4 BTC funded solely by us.
|
||||||
fundingAmt := btcutil.Amount(4 * 1e8)
|
fundingAmt := btcutil.Amount(4 * 1e8)
|
||||||
chanReservation, err := lnwallet.InitChannelReservation(fundingAmt,
|
chanReservation, err := lnwallet.InitChannelReservation(fundingAmt,
|
||||||
fundingAmt, bobNode.id, bobAddr, numReqConfs, 4)
|
fundingAmt, bobNode.id, bobAddr, numReqConfs, 4, 540)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to init channel reservation: %v", err)
|
t.Fatalf("unable to init channel reservation: %v", err)
|
||||||
}
|
}
|
||||||
@ -769,7 +769,7 @@ func testSingleFunderReservationWorkflowResponder(miner *rpctest.Harness,
|
|||||||
// contribution and the necessary resources.
|
// contribution and the necessary resources.
|
||||||
fundingAmt := btcutil.Amount(0)
|
fundingAmt := btcutil.Amount(0)
|
||||||
chanReservation, err := wallet.InitChannelReservation(capacity,
|
chanReservation, err := wallet.InitChannelReservation(capacity,
|
||||||
fundingAmt, bobNode.id, bobAddr, numReqConfs, 4)
|
fundingAmt, bobNode.id, bobAddr, numReqConfs, 4, 540)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to init channel reservation: %v", err)
|
t.Fatalf("unable to init channel reservation: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
package lnwallet
|
package lnwallet
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/roasbeef/btcwallet/wallet/txrules"
|
|
||||||
"github.com/roasbeef/btcutil"
|
"github.com/roasbeef/btcutil"
|
||||||
|
"github.com/roasbeef/btcwallet/wallet/txrules"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DefaultDustLimit is used to calculate the dust HTLC amount which will be
|
// DefaultDustLimit is used to calculate the dust HTLC amount which will be
|
||||||
// proposed to other node during channel creation.
|
// send to other node during funding process.
|
||||||
func DefaultDustLimit() btcutil.Amount {
|
func DefaultDustLimit() btcutil.Amount {
|
||||||
return txrules.GetDustThreshold(P2WSHSize, txrules.DefaultRelayFeePerKb)
|
return txrules.GetDustThreshold(P2WSHSize, txrules.DefaultRelayFeePerKb)
|
||||||
}
|
}
|
||||||
|
@ -382,6 +382,14 @@ func (r *ChannelReservation) LocalCommitTx() *wire.MsgTx {
|
|||||||
return r.partialState.OurCommitTx
|
return r.partialState.OurCommitTx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetDustLimit set dust limit of the remote party.
|
||||||
|
func (r *ChannelReservation) SetTheirDustLimit(dustLimit btcutil.Amount) {
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
|
||||||
|
r.partialState.TheirDustLimit = dustLimit
|
||||||
|
}
|
||||||
|
|
||||||
// FundingOutpoint returns the outpoint of the funding transaction.
|
// FundingOutpoint returns the outpoint of the funding transaction.
|
||||||
//
|
//
|
||||||
// NOTE: The pointer returned will only be set once the .ProcesContribution()
|
// NOTE: The pointer returned will only be set once the .ProcesContribution()
|
||||||
|
@ -100,6 +100,11 @@ type initFundingReserveMsg struct {
|
|||||||
// TODO(roasbeef): integrate fee estimation project...
|
// TODO(roasbeef): integrate fee estimation project...
|
||||||
minFeeRate btcutil.Amount
|
minFeeRate btcutil.Amount
|
||||||
|
|
||||||
|
// ourDustLimit is the threshold below which no HTLC output should be
|
||||||
|
// generated for our commitment transaction; ie. HTLCs below
|
||||||
|
// this amount are not enforceable onchain from our point of view.
|
||||||
|
ourDustLimit btcutil.Amount
|
||||||
|
|
||||||
// The delay on the "pay-to-self" output(s) of the commitment transaction.
|
// The delay on the "pay-to-self" output(s) of the commitment transaction.
|
||||||
csvDelay uint32
|
csvDelay uint32
|
||||||
|
|
||||||
@ -484,7 +489,7 @@ out:
|
|||||||
func (l *LightningWallet) InitChannelReservation(capacity,
|
func (l *LightningWallet) InitChannelReservation(capacity,
|
||||||
ourFundAmt btcutil.Amount, theirID *btcec.PublicKey,
|
ourFundAmt btcutil.Amount, theirID *btcec.PublicKey,
|
||||||
theirAddr *net.TCPAddr, numConfs uint16,
|
theirAddr *net.TCPAddr, numConfs uint16,
|
||||||
csvDelay uint32) (*ChannelReservation, error) {
|
csvDelay uint32, ourDustLimit btcutil.Amount) (*ChannelReservation, error) {
|
||||||
|
|
||||||
errChan := make(chan error, 1)
|
errChan := make(chan error, 1)
|
||||||
respChan := make(chan *ChannelReservation, 1)
|
respChan := make(chan *ChannelReservation, 1)
|
||||||
@ -494,6 +499,7 @@ func (l *LightningWallet) InitChannelReservation(capacity,
|
|||||||
numConfs: numConfs,
|
numConfs: numConfs,
|
||||||
fundingAmount: ourFundAmt,
|
fundingAmount: ourFundAmt,
|
||||||
csvDelay: csvDelay,
|
csvDelay: csvDelay,
|
||||||
|
ourDustLimit: ourDustLimit,
|
||||||
nodeID: theirID,
|
nodeID: theirID,
|
||||||
err: errChan,
|
err: errChan,
|
||||||
resp: respChan,
|
resp: respChan,
|
||||||
@ -522,11 +528,14 @@ func (l *LightningWallet) handleFundingReserveRequest(req *initFundingReserveMsg
|
|||||||
reservation.Lock()
|
reservation.Lock()
|
||||||
defer reservation.Unlock()
|
defer reservation.Unlock()
|
||||||
|
|
||||||
reservation.partialState.IdentityPub = req.nodeID
|
|
||||||
reservation.nodeAddr = req.nodeAddr
|
reservation.nodeAddr = req.nodeAddr
|
||||||
ourContribution := reservation.ourContribution
|
reservation.ourContribution.CsvDelay = req.csvDelay
|
||||||
ourContribution.CsvDelay = req.csvDelay
|
|
||||||
|
reservation.partialState.IdentityPub = req.nodeID
|
||||||
reservation.partialState.LocalCsvDelay = req.csvDelay
|
reservation.partialState.LocalCsvDelay = req.csvDelay
|
||||||
|
reservation.partialState.OurDustLimit = req.ourDustLimit
|
||||||
|
|
||||||
|
ourContribution := reservation.ourContribution
|
||||||
|
|
||||||
// If we're on the receiving end of a single funder channel then we
|
// If we're on the receiving end of a single funder channel then we
|
||||||
// don't need to perform any coin selection. Otherwise, attempt to
|
// don't need to perform any coin selection. Otherwise, attempt to
|
||||||
|
8
peer.go
8
peer.go
@ -390,13 +390,7 @@ out:
|
|||||||
// * .(CommitmentUpdater)
|
// * .(CommitmentUpdater)
|
||||||
|
|
||||||
case *lnwire.ErrorGeneric:
|
case *lnwire.ErrorGeneric:
|
||||||
switch msg.Code {
|
p.server.fundingMgr.processErrorGeneric(msg, p)
|
||||||
case lnwire.ErrorMaxPendingChannels:
|
|
||||||
p.server.fundingMgr.processErrorGeneric(msg, p)
|
|
||||||
default:
|
|
||||||
peerLog.Warnf("ErrorGeneric(%v) handling isn't"+
|
|
||||||
" implemented.", msg.Code)
|
|
||||||
}
|
|
||||||
case *lnwire.HTLCAddRequest:
|
case *lnwire.HTLCAddRequest:
|
||||||
isChanUpdate = true
|
isChanUpdate = true
|
||||||
targetChan = msg.ChannelPoint
|
targetChan = msg.ChannelPoint
|
||||||
|
@ -455,9 +455,9 @@ func (s *server) handleOpenChanReq(req *openChanReq) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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 of
|
// manager. This allows the server to continue handling queries instead
|
||||||
// blocking on this request which is exporeted as a synchronous request to
|
// of blocking on this request which is exported as a synchronous
|
||||||
// the outside world.
|
// request to the outside world.
|
||||||
// TODO(roasbeef): server semaphore to restrict num goroutines
|
// TODO(roasbeef): server semaphore to restrict num goroutines
|
||||||
go s.fundingMgr.initFundingWorkflow(targetPeer, req)
|
go s.fundingMgr.initFundingWorkflow(targetPeer, req)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user