lnwire+lnwallet+fundingmanager: general improvements
This commit is contained in:
parent
a6f7f05323
commit
5a82240c6a
@ -1,19 +1,18 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
|
"github.com/go-errors/errors"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
|
"github.com/lightningnetwork/lnd/routing/rt/graph"
|
||||||
"github.com/roasbeef/btcd/btcec"
|
"github.com/roasbeef/btcd/btcec"
|
||||||
"github.com/roasbeef/btcd/txscript"
|
"github.com/roasbeef/btcd/txscript"
|
||||||
"github.com/roasbeef/btcd/wire"
|
"github.com/roasbeef/btcd/wire"
|
||||||
"github.com/roasbeef/btcutil"
|
"github.com/roasbeef/btcutil"
|
||||||
|
|
||||||
"github.com/lightningnetwork/lnd/routing/rt/graph"
|
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -306,7 +305,7 @@ func (f *fundingManager) processFundingRequest(msg *lnwire.SingleFundingRequest,
|
|||||||
f.fundingMsgs <- &fundingRequestMsg{msg, peer}
|
f.fundingMsgs <- &fundingRequestMsg{msg, peer}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleSingleFundingRequest creates an initial 'ChannelReservation' within
|
// handleFundingRequest creates an initial 'ChannelReservation' within
|
||||||
// the wallet, then responds to the source peer with a single funder response
|
// the wallet, then responds to the source peer with a single funder response
|
||||||
// message progressing the funding workflow.
|
// message progressing the funding workflow.
|
||||||
// TODO(roasbeef): add error chan to all, let channelManager handle
|
// TODO(roasbeef): add error chan to all, let channelManager handle
|
||||||
@ -413,11 +412,16 @@ func (f *fundingManager) processFundingResponse(msg *lnwire.SingleFundingRespons
|
|||||||
// outpoint, and a commitment signature to the remote peer.
|
// outpoint, and a commitment signature to the remote peer.
|
||||||
func (f *fundingManager) handleFundingResponse(fmsg *fundingResponseMsg) {
|
func (f *fundingManager) handleFundingResponse(fmsg *fundingResponseMsg) {
|
||||||
msg := fmsg.msg
|
msg := fmsg.msg
|
||||||
|
peerID := fmsg.peer.id
|
||||||
|
chanID := fmsg.msg.ChannelID
|
||||||
sourcePeer := fmsg.peer
|
sourcePeer := fmsg.peer
|
||||||
|
|
||||||
f.resMtx.RLock()
|
resCtx, err := f.getReservationCtx(peerID, chanID)
|
||||||
resCtx := f.activeReservations[fmsg.peer.id][msg.ChannelID]
|
if err != nil {
|
||||||
f.resMtx.RUnlock()
|
fndgLog.Warnf("can' find reservation (peerID:%v, chanID:%v)",
|
||||||
|
peerID, chanID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
fndgLog.Infof("Recv'd fundingResponse for pendingID(%v)", msg.ChannelID)
|
fndgLog.Infof("Recv'd fundingResponse for pendingID(%v)", msg.ChannelID)
|
||||||
|
|
||||||
@ -463,14 +467,14 @@ func (f *fundingManager) handleFundingResponse(fmsg *fundingResponseMsg) {
|
|||||||
// the peer's readHandler once the channel is open.
|
// the peer's readHandler once the channel is open.
|
||||||
fmsg.peer.barrierInits <- *outPoint
|
fmsg.peer.barrierInits <- *outPoint
|
||||||
|
|
||||||
fndgLog.Infof("Generated ChannelPoint(%v) for pendingID(%v)",
|
fndgLog.Infof("Generated ChannelPoint(%v) for pendingID(%v)", outPoint,
|
||||||
outPoint, msg.ChannelID)
|
chanID)
|
||||||
|
|
||||||
revocationKey := resCtx.reservation.OurContribution().RevocationKey
|
revocationKey := resCtx.reservation.OurContribution().RevocationKey
|
||||||
obsfucator := resCtx.reservation.StateNumObfuscator()
|
obsfucator := resCtx.reservation.StateNumObfuscator()
|
||||||
|
|
||||||
fundingComplete := lnwire.NewSingleFundingComplete(msg.ChannelID,
|
fundingComplete := lnwire.NewSingleFundingComplete(chanID, outPoint,
|
||||||
outPoint, commitSig, revocationKey, obsfucator)
|
commitSig, revocationKey, obsfucator)
|
||||||
sourcePeer.queueMsg(fundingComplete, nil)
|
sourcePeer.queueMsg(fundingComplete, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -485,9 +489,12 @@ func (f *fundingManager) processFundingComplete(msg *lnwire.SingleFundingComplet
|
|||||||
// 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) handleFundingComplete(fmsg *fundingCompleteMsg) {
|
func (f *fundingManager) handleFundingComplete(fmsg *fundingCompleteMsg) {
|
||||||
f.resMtx.RLock()
|
resCtx, err := f.getReservationCtx(fmsg.peer.id, fmsg.msg.ChannelID)
|
||||||
resCtx := f.activeReservations[fmsg.peer.id][fmsg.msg.ChannelID]
|
if err != nil {
|
||||||
f.resMtx.RUnlock()
|
fndgLog.Warnf("can' find reservation (peerID:%v, chanID:%v)",
|
||||||
|
fmsg.peer.id, fmsg.msg.ChannelID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// The channel initiator has responded with the funding outpoint of the
|
// The channel initiator has responded with the funding outpoint of the
|
||||||
// final funding transaction, as well as a signature for our version of
|
// final funding transaction, as well as a signature for our version of
|
||||||
@ -507,8 +514,8 @@ func (f *fundingManager) handleFundingComplete(fmsg *fundingCompleteMsg) {
|
|||||||
// With all the necessary data available, attempt to advance the
|
// With all the necessary data available, attempt to advance the
|
||||||
// funding workflow to the next stage. If this succeeds then the
|
// funding workflow to the next stage. If this succeeds then the
|
||||||
// funding transaction will broadcast after our next message.
|
// funding transaction will broadcast after our next message.
|
||||||
err := resCtx.reservation.CompleteReservationSingle(revokeKey,
|
err = resCtx.reservation.CompleteReservationSingle(revokeKey, fundingOut,
|
||||||
fundingOut, commitSig, obsfucator)
|
commitSig, obsfucator)
|
||||||
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)
|
fndgLog.Errorf("unable to complete single reservation: %v", err)
|
||||||
@ -551,10 +558,14 @@ func (f *fundingManager) processFundingSignComplete(msg *lnwire.SingleFundingSig
|
|||||||
// proofs of transaction inclusion.
|
// proofs of transaction inclusion.
|
||||||
func (f *fundingManager) handleFundingSignComplete(fmsg *fundingSignCompleteMsg) {
|
func (f *fundingManager) handleFundingSignComplete(fmsg *fundingSignCompleteMsg) {
|
||||||
chanID := fmsg.msg.ChannelID
|
chanID := fmsg.msg.ChannelID
|
||||||
|
peerID := fmsg.peer.id
|
||||||
|
|
||||||
f.resMtx.RLock()
|
resCtx, err := f.getReservationCtx(peerID, chanID)
|
||||||
resCtx := f.activeReservations[fmsg.peer.id][chanID]
|
if err != nil {
|
||||||
f.resMtx.RUnlock()
|
fndgLog.Warnf("can' find reservation (peerID:%v, chanID:%v)",
|
||||||
|
peerID, chanID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// The remote peer has responded with a signature for our commitment
|
// The remote peer has responded with a signature for our commitment
|
||||||
// transaction. We'll verify the signature for validity, then commit
|
// transaction. We'll verify the signature for validity, then commit
|
||||||
@ -594,12 +605,10 @@ func (f *fundingManager) handleFundingSignComplete(fmsg *fundingSignCompleteMsg)
|
|||||||
case openChan := <-resCtx.reservation.DispatchChan():
|
case openChan := <-resCtx.reservation.DispatchChan():
|
||||||
// This reservation is no longer pending as the funding
|
// This reservation is no longer pending as the funding
|
||||||
// transaction has been fully confirmed.
|
// transaction has been fully confirmed.
|
||||||
f.resMtx.Lock()
|
f.deleteReservationCtx(peerID, chanID)
|
||||||
delete(f.activeReservations[fmsg.peer.id], chanID)
|
|
||||||
f.resMtx.Unlock()
|
|
||||||
|
|
||||||
fndgLog.Infof("ChannelPoint(%v) with peerID(%v) is now active",
|
fndgLog.Infof("ChannelPoint(%v) with peerID(%v) is now active",
|
||||||
fundingPoint, fmsg.peer.id)
|
fundingPoint, peerID)
|
||||||
|
|
||||||
// Now that the channel is open, we need to notify a
|
// Now that the channel is open, we need to notify a
|
||||||
// number of parties of this event.
|
// number of parties of this event.
|
||||||
@ -669,9 +678,15 @@ func (f *fundingManager) processFundingOpenProof(msg *lnwire.SingleFundingOpenPr
|
|||||||
// the initiating node is verified, which if correct, marks the channel as open
|
// the initiating node is verified, which if correct, marks the channel as open
|
||||||
// to the source peer.
|
// to the source peer.
|
||||||
func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
|
func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
|
||||||
f.resMtx.RLock()
|
chanID := fmsg.msg.ChannelID
|
||||||
resCtx := f.activeReservations[fmsg.peer.id][fmsg.msg.ChannelID]
|
peerID := fmsg.peer.id
|
||||||
f.resMtx.RUnlock()
|
|
||||||
|
resCtx, err := f.getReservationCtx(peerID, chanID)
|
||||||
|
if err != nil {
|
||||||
|
fndgLog.Warnf("can' find reservation (peerID:%v, chanID:%v)",
|
||||||
|
peerID, chanID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// The channel initiator has claimed the channel is now open, so we'll
|
// The channel initiator has claimed the channel is now open, so we'll
|
||||||
// verify the contained SPV proof for validity.
|
// verify the contained SPV proof for validity.
|
||||||
@ -690,12 +705,10 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
|
|||||||
|
|
||||||
// The reservation has been completed, therefore we can stop tracking
|
// The reservation has been completed, therefore we can stop tracking
|
||||||
// it within our active reservations map.
|
// it within our active reservations map.
|
||||||
f.resMtx.Lock()
|
f.deleteReservationCtx(peerID, chanID)
|
||||||
delete(f.activeReservations[fmsg.peer.id], fmsg.msg.ChannelID)
|
|
||||||
f.resMtx.Unlock()
|
|
||||||
|
|
||||||
fndgLog.Infof("FundingOpen: ChannelPoint(%v) with peerID(%v) is now open",
|
fndgLog.Infof("FundingOpen: ChannelPoint(%v) with peerID(%v) is now open",
|
||||||
resCtx.reservation.FundingOutpoint, fmsg.peer.id)
|
resCtx.reservation.FundingOutpoint, peerID)
|
||||||
|
|
||||||
// Notify the L3 routing manager of the newly active channel link.
|
// Notify the L3 routing manager of the newly active channel link.
|
||||||
capacity := int64(resCtx.reservation.OurContribution().FundingAmount +
|
capacity := int64(resCtx.reservation.OurContribution().FundingAmount +
|
||||||
@ -818,37 +831,67 @@ func (f *fundingManager) processErrorGeneric(err *lnwire.ErrorGeneric,
|
|||||||
// depends on the type of error we should do different clean up steps and
|
// depends on the type of error we should do different clean up steps and
|
||||||
// inform user about it.
|
// inform user about it.
|
||||||
func (f *fundingManager) handleErrorGenericMsg(fmsg *fundingErrorMsg) {
|
func (f *fundingManager) handleErrorGenericMsg(fmsg *fundingErrorMsg) {
|
||||||
switch fmsg.err.Code {
|
e := fmsg.err
|
||||||
|
|
||||||
|
switch e.Code {
|
||||||
case lnwire.ErrorMaxPendingChannels:
|
case lnwire.ErrorMaxPendingChannels:
|
||||||
peerID := fmsg.peer.id
|
peerID := fmsg.peer.id
|
||||||
chanID := fmsg.err.PendingChannelID
|
chanID := fmsg.err.PendingChannelID
|
||||||
|
|
||||||
f.resMtx.RLock()
|
if ctx, err := f.cancelReservationCtx(peerID, chanID); err != nil {
|
||||||
resCtx, ok := f.activeReservations[peerID][chanID]
|
fndgLog.Warnf("unable to delete reservation: %v", err)
|
||||||
f.resMtx.RUnlock()
|
return
|
||||||
|
} else {
|
||||||
if !ok {
|
ctx.err <- grpc.Errorf(e.Code.ToGrpcCode(), e.Problem)
|
||||||
fndgLog.Warnf("ErrorGeneric error was returned from " +
|
|
||||||
"remote peer for unknown channel (id: %v)")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := resCtx.reservation.Cancel(); err != nil {
|
|
||||||
resCtx.err <- fmt.Errorf("max pending channels "+
|
|
||||||
"exceeded -- unable to cancel reservation: %v",
|
|
||||||
err)
|
|
||||||
} else {
|
|
||||||
resCtx.err <- grpc.Errorf(ErrorMaxPendingChannels,
|
|
||||||
"unable to create channel, max number of "+
|
|
||||||
"pending channels exceeded.")
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(roasbeef): possibly cancel funding barrier in peer's
|
|
||||||
// channelManager?
|
|
||||||
f.resMtx.Lock()
|
|
||||||
delete(f.activeReservations[peerID], chanID)
|
|
||||||
f.resMtx.Unlock()
|
|
||||||
default:
|
default:
|
||||||
fndgLog.Warnf("unknown funding error %v", fmsg.err)
|
fndgLog.Warnf("unknown funding error (%v:%v)", e.Code, e.Problem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cancelReservationCtx do all needed work in order to securely cancel the
|
||||||
|
// reservation.
|
||||||
|
func (f *fundingManager) cancelReservationCtx(peerID int32,
|
||||||
|
chanID uint64) (*reservationWithCtx, error) {
|
||||||
|
|
||||||
|
ctx, err := f.getReservationCtx(peerID, chanID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Errorf("can't find reservation: %v",
|
||||||
|
err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ctx.reservation.Cancel(); err != nil {
|
||||||
|
ctx.err <- err
|
||||||
|
return nil, errors.Errorf("can't cancel reservation: %v",
|
||||||
|
err)
|
||||||
|
}
|
||||||
|
|
||||||
|
f.deleteReservationCtx(peerID, chanID)
|
||||||
|
return ctx, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// deleteReservationCtx is needed in order to securely delete the reservation.
|
||||||
|
func (f *fundingManager) deleteReservationCtx(peerID int32, chanID uint64) {
|
||||||
|
// TODO(roasbeef): possibly cancel funding barrier in peer's
|
||||||
|
// channelManager?
|
||||||
|
f.resMtx.Lock()
|
||||||
|
delete(f.activeReservations[peerID], chanID)
|
||||||
|
f.resMtx.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// getReservationCtx returns the reservation context by peer id and channel id.
|
||||||
|
func (f *fundingManager) getReservationCtx(peerID int32,
|
||||||
|
chanID uint64) (*reservationWithCtx, error) {
|
||||||
|
|
||||||
|
f.resMtx.RLock()
|
||||||
|
resCtx, ok := f.activeReservations[peerID][chanID]
|
||||||
|
f.resMtx.RUnlock()
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.Errorf("unknown channel (id: %v)", chanID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resCtx, nil
|
||||||
|
}
|
||||||
|
35
lnd_test.go
35
lnd_test.go
@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/roasbeef/btcd/rpctest"
|
"github.com/roasbeef/btcd/rpctest"
|
||||||
"github.com/roasbeef/btcd/wire"
|
"github.com/roasbeef/btcd/wire"
|
||||||
"github.com/roasbeef/btcrpcclient"
|
"github.com/roasbeef/btcrpcclient"
|
||||||
@ -886,7 +887,7 @@ func testMaxPendingChannels(net *networkHarness, t *harnessTest) {
|
|||||||
_, err = net.OpenChannel(ctx, net.Alice, carol, amount, 1)
|
_, err = net.OpenChannel(ctx, net.Alice, carol, amount, 1)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("error wasn't received")
|
t.Fatalf("error wasn't received")
|
||||||
} else if grpc.Code(err) != ErrorMaxPendingChannels {
|
} else if grpc.Code(err) != lnwire.ErrorMaxPendingChannels.ToGrpcCode() {
|
||||||
t.Fatalf("not expected error was received: %v", err)
|
t.Fatalf("not expected error was received: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1243,6 +1244,22 @@ func TestLightningNetworkDaemon(t *testing.T) {
|
|||||||
OnTxAccepted: lndHarness.OnTxAccepted,
|
OnTxAccepted: lndHarness.OnTxAccepted,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Spawn a new goroutine to watch for any fatal errors that any of the
|
||||||
|
// running lnd processes encounter. If an error occurs, then the test
|
||||||
|
// fails immediately with a fatal error, as far as fatal is happening
|
||||||
|
// inside goroutine main goroutine would not be finished at the same
|
||||||
|
// time as we receive fatal error from lnd process.
|
||||||
|
testsFin := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
select {
|
||||||
|
case err := <-lndHarness.ProcessErrors():
|
||||||
|
ht.Fatalf("lnd finished with error (stderr): "+
|
||||||
|
"\n%v", err)
|
||||||
|
case <-testsFin:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
// First create an instance of the btcd's rpctest.Harness. This will be
|
// First create an instance of the btcd's rpctest.Harness. This will be
|
||||||
// used to fund the wallets of the nodes within the test network and to
|
// used to fund the wallets of the nodes within the test network and to
|
||||||
// drive blockchain related events within the network.
|
// drive blockchain related events within the network.
|
||||||
@ -1269,22 +1286,6 @@ func TestLightningNetworkDaemon(t *testing.T) {
|
|||||||
ht.Fatalf("unable to set up test lightning network: %v", err)
|
ht.Fatalf("unable to set up test lightning network: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spawn a new goroutine to watch for any fatal errors that any of the
|
|
||||||
// running lnd processes encounter. If an error occurs, then the test
|
|
||||||
// fails immediately with a fatal error, as far as fatal is happening
|
|
||||||
// inside goroutine main goroutine would not be finished at the same
|
|
||||||
// time as we receive fatal error from lnd process.
|
|
||||||
testsFin := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
select {
|
|
||||||
case err := <-lndHarness.ProcessErrors():
|
|
||||||
ht.Fatalf("lnd finished with error (stderr): "+
|
|
||||||
"\n%v", err)
|
|
||||||
case <-testsFin:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
t.Logf("Running %v integration tests", len(testsCases))
|
t.Logf("Running %v integration tests", len(testsCases))
|
||||||
for _, testCase := range testsCases {
|
for _, testCase := range testsCases {
|
||||||
ht.RunTestCase(testCase, lndHarness)
|
ht.RunTestCase(testCase, lndHarness)
|
||||||
|
@ -1585,7 +1585,7 @@ func (lc *LightningChannel) AddHTLC(htlc *lnwire.HTLCAddRequest) (uint32, error)
|
|||||||
EntryType: Add,
|
EntryType: Add,
|
||||||
RHash: PaymentHash(htlc.RedemptionHashes[0]),
|
RHash: PaymentHash(htlc.RedemptionHashes[0]),
|
||||||
Timeout: htlc.Expiry,
|
Timeout: htlc.Expiry,
|
||||||
Amount: btcutil.Amount(htlc.Amount),
|
Amount: htlc.Amount,
|
||||||
Index: lc.ourLogCounter,
|
Index: lc.ourLogCounter,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1611,7 +1611,7 @@ func (lc *LightningChannel) ReceiveHTLC(htlc *lnwire.HTLCAddRequest) (uint32, er
|
|||||||
EntryType: Add,
|
EntryType: Add,
|
||||||
RHash: PaymentHash(htlc.RedemptionHashes[0]),
|
RHash: PaymentHash(htlc.RedemptionHashes[0]),
|
||||||
Timeout: htlc.Expiry,
|
Timeout: htlc.Expiry,
|
||||||
Amount: btcutil.Amount(htlc.Amount),
|
Amount: htlc.Amount,
|
||||||
Index: lc.theirLogCounter,
|
Index: lc.theirLogCounter,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,7 +355,7 @@ func TestSimpleAddSettleWorkflow(t *testing.T) {
|
|||||||
htlc := &lnwire.HTLCAddRequest{
|
htlc := &lnwire.HTLCAddRequest{
|
||||||
RedemptionHashes: [][32]byte{paymentHash},
|
RedemptionHashes: [][32]byte{paymentHash},
|
||||||
// TODO(roasbeef): properly switch to credits: (1 msat)
|
// TODO(roasbeef): properly switch to credits: (1 msat)
|
||||||
Amount: lnwire.CreditsAmount(1e8),
|
Amount: btcutil.Amount(1e8),
|
||||||
Expiry: uint32(5),
|
Expiry: uint32(5),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -628,7 +628,7 @@ func TestCheckCommitTxSize(t *testing.T) {
|
|||||||
|
|
||||||
return &lnwire.HTLCAddRequest{
|
return &lnwire.HTLCAddRequest{
|
||||||
RedemptionHashes: [][32]byte{paymentHash},
|
RedemptionHashes: [][32]byte{paymentHash},
|
||||||
Amount: lnwire.CreditsAmount(1e7),
|
Amount: btcutil.Amount(1e7),
|
||||||
Expiry: uint32(5),
|
Expiry: uint32(5),
|
||||||
}, returnPreimage
|
}, returnPreimage
|
||||||
}
|
}
|
||||||
@ -742,7 +742,7 @@ func TestCheckHTLCNumberConstraint(t *testing.T) {
|
|||||||
paymentHash := fastsha256.Sum256(preimage)
|
paymentHash := fastsha256.Sum256(preimage)
|
||||||
return &lnwire.HTLCAddRequest{
|
return &lnwire.HTLCAddRequest{
|
||||||
RedemptionHashes: [][32]byte{paymentHash},
|
RedemptionHashes: [][32]byte{paymentHash},
|
||||||
Amount: lnwire.CreditsAmount(1e7),
|
Amount: btcutil.Amount(1e7),
|
||||||
Expiry: uint32(5),
|
Expiry: uint32(5),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -864,7 +864,7 @@ func TestStateUpdatePersistence(t *testing.T) {
|
|||||||
rHash := fastsha256.Sum256(alicePreimage[:])
|
rHash := fastsha256.Sum256(alicePreimage[:])
|
||||||
h := &lnwire.HTLCAddRequest{
|
h := &lnwire.HTLCAddRequest{
|
||||||
RedemptionHashes: [][32]byte{rHash},
|
RedemptionHashes: [][32]byte{rHash},
|
||||||
Amount: lnwire.CreditsAmount(1000),
|
Amount: btcutil.Amount(1000),
|
||||||
Expiry: uint32(10),
|
Expiry: uint32(10),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -874,7 +874,7 @@ func TestStateUpdatePersistence(t *testing.T) {
|
|||||||
rHash := fastsha256.Sum256(bobPreimage[:])
|
rHash := fastsha256.Sum256(bobPreimage[:])
|
||||||
bobh := &lnwire.HTLCAddRequest{
|
bobh := &lnwire.HTLCAddRequest{
|
||||||
RedemptionHashes: [][32]byte{rHash},
|
RedemptionHashes: [][32]byte{rHash},
|
||||||
Amount: lnwire.CreditsAmount(1000),
|
Amount: btcutil.Amount(1000),
|
||||||
Expiry: uint32(10),
|
Expiry: uint32(10),
|
||||||
}
|
}
|
||||||
bobChannel.AddHTLC(bobh)
|
bobChannel.AddHTLC(bobh)
|
||||||
|
@ -908,12 +908,6 @@ func testSingleFunderReservationWorkflowResponder(miner *rpctest.Harness,
|
|||||||
// TODO(roasbeef): bob verify alice's sig
|
// TODO(roasbeef): bob verify alice's sig
|
||||||
}
|
}
|
||||||
|
|
||||||
func testFundingReservationInvalidCounterpartySigs(miner *rpctest.Harness, lnwallet *lnwallet.LightningWallet, t *testing.T) {
|
|
||||||
}
|
|
||||||
|
|
||||||
func testFundingTransactionTxFees(miner *rpctest.Harness, lnwallet *lnwallet.LightningWallet, t *testing.T) {
|
|
||||||
}
|
|
||||||
|
|
||||||
func testListTransactionDetails(miner *rpctest.Harness, wallet *lnwallet.LightningWallet, t *testing.T) {
|
func testListTransactionDetails(miner *rpctest.Harness, wallet *lnwallet.LightningWallet, t *testing.T) {
|
||||||
t.Log("Running list transaction details test")
|
t.Log("Running list transaction details test")
|
||||||
|
|
||||||
@ -1234,10 +1228,10 @@ var walletTests = []func(miner *rpctest.Harness, w *lnwallet.LightningWallet, te
|
|||||||
testSingleFunderReservationWorkflowResponder,
|
testSingleFunderReservationWorkflowResponder,
|
||||||
testFundingTransactionLockedOutputs,
|
testFundingTransactionLockedOutputs,
|
||||||
testFundingCancellationNotEnoughFunds,
|
testFundingCancellationNotEnoughFunds,
|
||||||
testFundingReservationInvalidCounterpartySigs,
|
|
||||||
testTransactionSubscriptions,
|
testTransactionSubscriptions,
|
||||||
testListTransactionDetails,
|
testListTransactionDetails,
|
||||||
testSignOutputPrivateTweak,
|
testSignOutputPrivateTweak,
|
||||||
|
testCancelNonExistantReservation,
|
||||||
}
|
}
|
||||||
|
|
||||||
type testLnWallet struct {
|
type testLnWallet struct {
|
||||||
@ -1324,28 +1318,28 @@ func TestLightningWallet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Funding via 20 outputs with 4BTC each.
|
// Funding via 20 outputs with 4BTC each.
|
||||||
lnwallet, err := createTestWallet(tempTestDir, miningNode, netParams,
|
lnw, err := createTestWallet(tempTestDir, miningNode, netParams,
|
||||||
chainNotifier, wc, signer, bio)
|
chainNotifier, wc, signer, bio)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to create test ln wallet: %v", err)
|
t.Fatalf("unable to create test ln wallet: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The wallet should now have 80BTC available for spending.
|
// The wallet should now have 80BTC available for spending.
|
||||||
assertProperBalance(t, lnwallet, 1, 80)
|
assertProperBalance(t, lnw, 1, 80)
|
||||||
|
|
||||||
// Execute every test, clearing possibly mutated wallet state after
|
// Execute every test, clearing possibly mutated wallet state after
|
||||||
// each step.
|
// each step.
|
||||||
for _, walletTest := range walletTests {
|
for _, walletTest := range walletTests {
|
||||||
walletTest(miningNode, lnwallet, t)
|
walletTest(miningNode, lnw, t)
|
||||||
|
|
||||||
// TODO(roasbeef): possible reset mining node's chainstate to
|
// TODO(roasbeef): possible reset mining node's chainstate to
|
||||||
// initial level, cleanly wipe buckets
|
// initial level, cleanly wipe buckets
|
||||||
if err := clearWalletState(lnwallet); err != nil &&
|
if err := clearWalletState(lnw); err != nil &&
|
||||||
err != bolt.ErrBucketNotFound {
|
err != bolt.ErrBucketNotFound {
|
||||||
t.Fatalf("unable to wipe wallet state: %v", err)
|
t.Fatalf("unable to wipe wallet state: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lnwallet.Shutdown()
|
lnw.Shutdown()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ import (
|
|||||||
|
|
||||||
// ChannelContribution is the primary constituent of the funding workflow within
|
// ChannelContribution is the primary constituent of the funding workflow within
|
||||||
// lnwallet. Each side first exchanges their respective contributions along with
|
// lnwallet. Each side first exchanges their respective contributions along with
|
||||||
// channel specific paramters like the min fee/KB. Once contributions have been
|
// channel specific parameters like the min fee/KB. Once contributions have been
|
||||||
// exchanged, each side will then produce signatures for all their inputs to the
|
// exchanged, each side will then produce signatures for all their inputs to the
|
||||||
// funding transactions, and finally a signature for the other party's version
|
// funding transactions, and finally a signature for the other party's version
|
||||||
// of the commitment transaction.
|
// of the commitment transaction.
|
||||||
@ -98,10 +98,6 @@ type ChannelReservation struct {
|
|||||||
// fundingTx is the funding transaction for this pending channel.
|
// fundingTx is the funding transaction for this pending channel.
|
||||||
fundingTx *wire.MsgTx
|
fundingTx *wire.MsgTx
|
||||||
|
|
||||||
// For CLTV it is nLockTime, for CSV it's nSequence, for segwit it's
|
|
||||||
// not needed
|
|
||||||
fundingLockTime uint32
|
|
||||||
|
|
||||||
// In order of sorted inputs. Sorting is done in accordance
|
// In order of sorted inputs. Sorting is done in accordance
|
||||||
// to BIP-69: https://github.com/bitcoin/bips/blob/master/bip-0069.mediawiki.
|
// to BIP-69: https://github.com/bitcoin/bips/blob/master/bip-0069.mediawiki.
|
||||||
ourFundingInputScripts []*InputScript
|
ourFundingInputScripts []*InputScript
|
||||||
@ -228,7 +224,7 @@ func (r *ChannelReservation) OurContribution() *ChannelContribution {
|
|||||||
return r.ourContribution
|
return r.ourContribution
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcesContribution verifies the counterparty's contribution to the pending
|
// ProcessContribution verifies the counterparty's contribution to the pending
|
||||||
// payment channel. As a result of this incoming message, lnwallet is able to
|
// payment channel. As a result of this incoming message, lnwallet is able to
|
||||||
// build the funding transaction, and both commitment transactions. Once this
|
// build the funding transaction, and both commitment transactions. Once this
|
||||||
// message has been processed, all signatures to inputs to the funding
|
// message has been processed, all signatures to inputs to the funding
|
||||||
|
@ -768,7 +768,6 @@ func (l *LightningWallet) handleContributionMsg(req *addContributionMsg) {
|
|||||||
|
|
||||||
// With the funding tx complete, create both commitment transactions.
|
// With the funding tx complete, create both commitment transactions.
|
||||||
// TODO(roasbeef): much cleanup + de-duplication
|
// TODO(roasbeef): much cleanup + de-duplication
|
||||||
pendingReservation.fundingLockTime = theirContribution.CsvDelay
|
|
||||||
ourBalance := ourContribution.FundingAmount
|
ourBalance := ourContribution.FundingAmount
|
||||||
theirBalance := theirContribution.FundingAmount
|
theirBalance := theirContribution.FundingAmount
|
||||||
ourCommitKey := ourContribution.CommitKey
|
ourCommitKey := ourContribution.CommitKey
|
||||||
|
@ -5,12 +5,21 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/roasbeef/btcd/wire"
|
"github.com/roasbeef/btcd/wire"
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrorCode represents the short error code for each of the defined errors
|
// ErrorCode represents the short error code for each of the defined errors
|
||||||
// within the Lightning Network protocol spec.
|
// within the Lightning Network protocol spec.
|
||||||
type ErrorCode uint16
|
type ErrorCode uint16
|
||||||
|
|
||||||
|
// ToGrpcCode is used to generate gRPC specific code which will be propagated
|
||||||
|
// to the ln rpc client. This code is used to have more detailed view of what
|
||||||
|
// goes wrong and also in order to have the ability pragmatically determine
|
||||||
|
// the error and take specific actions on the client side.
|
||||||
|
func (e ErrorCode) ToGrpcCode() codes.Code {
|
||||||
|
return (codes.Code)(e) + 100
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// ErrorMaxPendingChannels is returned by remote peer when the number
|
// ErrorMaxPendingChannels is returned by remote peer when the number
|
||||||
// of active pending channels exceeds their maximum policy limit.
|
// of active pending channels exceeds their maximum policy limit.
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/roasbeef/btcd/wire"
|
"github.com/roasbeef/btcd/wire"
|
||||||
|
"github.com/roasbeef/btcutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HTLCAddRequest is the message sent by Alice to Bob when she wishes to add an
|
// HTLCAddRequest is the message sent by Alice to Bob when she wishes to add an
|
||||||
@ -28,7 +29,7 @@ type HTLCAddRequest struct {
|
|||||||
// Difference between hop and first item in blob is the fee to complete
|
// Difference between hop and first item in blob is the fee to complete
|
||||||
|
|
||||||
// Amount is the number of credits this HTLC is worth.
|
// Amount is the number of credits this HTLC is worth.
|
||||||
Amount CreditsAmount
|
Amount btcutil.Amount
|
||||||
|
|
||||||
// RefundContext is for payment cancellation
|
// RefundContext is for payment cancellation
|
||||||
// TODO(j): not currently in use, add later
|
// TODO(j): not currently in use, add later
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
"github.com/roasbeef/btcutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHTLCAddRequestEncodeDecode(t *testing.T) {
|
func TestHTLCAddRequestEncodeDecode(t *testing.T) {
|
||||||
@ -14,7 +15,7 @@ func TestHTLCAddRequestEncodeDecode(t *testing.T) {
|
|||||||
addReq := &HTLCAddRequest{
|
addReq := &HTLCAddRequest{
|
||||||
ChannelPoint: outpoint1,
|
ChannelPoint: outpoint1,
|
||||||
Expiry: uint32(144),
|
Expiry: uint32(144),
|
||||||
Amount: CreditsAmount(123456000),
|
Amount: btcutil.Amount(123456000),
|
||||||
ContractType: uint8(17),
|
ContractType: uint8(17),
|
||||||
RedemptionHashes: redemptionHashes,
|
RedemptionHashes: redemptionHashes,
|
||||||
OnionBlob: []byte{255, 0, 255, 0, 255, 0, 255, 0},
|
OnionBlob: []byte{255, 0, 255, 0, 255, 0, 255, 0},
|
||||||
|
@ -32,7 +32,7 @@ type HTLCKey int64
|
|||||||
// HTLC lists on either side will increment this height. As a result this value
|
// HTLC lists on either side will increment this height. As a result this value
|
||||||
// should always be monotonically increasing. Any CommitSignature or
|
// should always be monotonically increasing. Any CommitSignature or
|
||||||
// CommitRevocation messages will reference a value for the commitment height
|
// CommitRevocation messages will reference a value for the commitment height
|
||||||
// up to which it covers. HTLC's are only explicltly excluded by sending
|
// up to which it covers. HTLC's are only explicitly excluded by sending
|
||||||
// HTLCReject messages referencing a particular HTLCKey.
|
// HTLCReject messages referencing a particular HTLCKey.
|
||||||
type CommitHeight uint64
|
type CommitHeight uint64
|
||||||
|
|
||||||
|
2
peer.go
2
peer.go
@ -1532,7 +1532,7 @@ func logEntryToHtlcPkt(chanPoint wire.OutPoint,
|
|||||||
}
|
}
|
||||||
|
|
||||||
msg = &lnwire.HTLCAddRequest{
|
msg = &lnwire.HTLCAddRequest{
|
||||||
Amount: lnwire.CreditsAmount(pd.Amount),
|
Amount: btcutil.Amount(pd.Amount),
|
||||||
RedemptionHashes: [][32]byte{pd.RHash},
|
RedemptionHashes: [][32]byte{pd.RHash},
|
||||||
OnionBlob: b.Bytes(),
|
OnionBlob: b.Bytes(),
|
||||||
}
|
}
|
||||||
|
@ -29,12 +29,6 @@ import (
|
|||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
// ErrorMaxPendingChannels is an additional gRPC error, which is
|
|
||||||
// returned if max pending channel restriction was violated.
|
|
||||||
ErrorMaxPendingChannels = 100
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
defaultAccount uint32 = waddrmgr.DefaultAccountNum
|
defaultAccount uint32 = waddrmgr.DefaultAccountNum
|
||||||
)
|
)
|
||||||
@ -771,7 +765,7 @@ func (r *rpcServer) constructPaymentRoute(destPubkey []byte, amt int64,
|
|||||||
// meta-data within this packet will be used to route the payment
|
// meta-data within this packet will be used to route the payment
|
||||||
// through the network.
|
// through the network.
|
||||||
htlcAdd := &lnwire.HTLCAddRequest{
|
htlcAdd := &lnwire.HTLCAddRequest{
|
||||||
Amount: lnwire.CreditsAmount(amt),
|
Amount: btcutil.Amount(amt),
|
||||||
RedemptionHashes: [][32]byte{rHash},
|
RedemptionHashes: [][32]byte{rHash},
|
||||||
OnionBlob: sphinxPacket,
|
OnionBlob: sphinxPacket,
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user