Merge pull request from Roasbeef/v0-17-3-branch

release: create v0.17.3-beta.rc1 release branch
This commit is contained in:
Olaoluwa Osuntokun 2023-12-01 14:17:21 -08:00 committed by GitHub
commit d5b05d6930
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 251 additions and 24 deletions

@ -43,11 +43,11 @@ const (
AppMinor uint = 17
// AppPatch defines the application patch for this binary.
AppPatch uint = 2
AppPatch uint = 3
// AppPreRelease MUST only contain characters from semanticAlphabet per
// the semantic versioning spec.
AppPreRelease = "beta"
AppPreRelease = "beta.rc1"
)
func init() {

@ -849,6 +849,30 @@ type OpenChannel struct {
sync.RWMutex
}
// String returns a string representation of the channel.
func (c *OpenChannel) String() string {
indexStr := "height=%v, local_htlc_index=%v, local_log_index=%v, " +
"remote_htlc_index=%v, remote_log_index=%v"
commit := c.LocalCommitment
local := fmt.Sprintf(indexStr, commit.CommitHeight,
commit.LocalHtlcIndex, commit.LocalLogIndex,
commit.RemoteHtlcIndex, commit.RemoteLogIndex,
)
commit = c.RemoteCommitment
remote := fmt.Sprintf(indexStr, commit.CommitHeight,
commit.LocalHtlcIndex, commit.LocalLogIndex,
commit.RemoteHtlcIndex, commit.RemoteLogIndex,
)
return fmt.Sprintf("SCID=%v, status=%v, initiator=%v, pending=%v, "+
"local commitment has %s, remote commitment has %s",
c.ShortChannelID, c.chanStatus, c.IsInitiator, c.IsPending,
local, remote,
)
}
// ShortChanID returns the current ShortChannelID of this channel.
func (c *OpenChannel) ShortChanID() lnwire.ShortChannelID {
c.RLock()
@ -2100,6 +2124,10 @@ func (c *OpenChannel) ActiveHtlcs() []HTLC {
// which ones are present on their commitment.
remoteHtlcs := make(map[[32]byte]struct{})
for _, htlc := range c.RemoteCommitment.Htlcs {
log.Tracef("RemoteCommitment has htlc: id=%v, update=%v "+
"incoming=%v", htlc.HtlcIndex, htlc.LogIndex,
htlc.Incoming)
onionHash := sha256.Sum256(htlc.OnionBlob[:])
remoteHtlcs[onionHash] = struct{}{}
}
@ -2108,8 +2136,16 @@ func (c *OpenChannel) ActiveHtlcs() []HTLC {
// as active if *we* know them as well.
activeHtlcs := make([]HTLC, 0, len(remoteHtlcs))
for _, htlc := range c.LocalCommitment.Htlcs {
log.Tracef("LocalCommitment has htlc: id=%v, update=%v "+
"incoming=%v", htlc.HtlcIndex, htlc.LogIndex,
htlc.Incoming)
onionHash := sha256.Sum256(htlc.OnionBlob[:])
if _, ok := remoteHtlcs[onionHash]; !ok {
log.Tracef("Skipped htlc due to onion mismatched: "+
"id=%v, update=%v incoming=%v",
htlc.HtlcIndex, htlc.LogIndex, htlc.Incoming)
continue
}

@ -0,0 +1,57 @@
# Release Notes
- [Bug Fixes](#bug-fixes)
- [New Features](#new-features)
- [Functional Enhancements](#functional-enhancements)
- [RPC Additions](#rpc-additions)
- [lncli Additions](#lncli-additions)
- [Improvements](#improvements)
- [Functional Updates](#functional-updates)
- [RPC Updates](#rpc-updates)
- [lncli Updates](#lncli-updates)
- [Breaking Changes](#breaking-changes)
- [Performance Improvements](#performance-improvements)
- [Technical and Architectural Updates](#technical-and-architectural-updates)
- [BOLT Spec Updates](#bolt-spec-updates)
- [Testing](#testing)
- [Database](#database)
- [Code Health](#code-health)
- [Tooling and Documentation](#tooling-and-documentation)
# Bug Fixes
* [Replaced](https://github.com/lightningnetwork/lnd/pull/8224)
`musig2Sessions` with a `SyncMap` used in `input` package to avoid concurrent
write to this map.
* [Fixed](https://github.com/lightningnetwork/lnd/pull/8220) a loop variable
issue which may affect programs built using go `v1.20` and below.
* [An issue where LND would hang on shutdown has been fixed.](https://github.com/lightningnetwork/lnd/pull/8151)
# New Features
## Functional Enhancements
## RPC Additions
## lncli Additions
# Improvements
## Functional Updates
## RPC Updates
## lncli Updates
## Code Health
## Breaking Changes
## Performance Improvements
* [Optimized](https://github.com/lightningnetwork/lnd/pull/8232) the memoray
usage of `btcwallet`'s mempool. Users would need to use `bitcoind v25.0.0`
and above to take the advantage of this optimization.
# Technical and Architectural Updates
## BOLT Spec Updates
## Testing
## Database
## Code Health
## Tooling and Documentation
# Contributors (Alphabetical Order)
* Eugene Siegel
* Yong Yu

2
go.mod

@ -9,7 +9,7 @@ require (
github.com/btcsuite/btcd/btcutil/psbt v1.1.8
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f
github.com/btcsuite/btcwallet v0.16.10-0.20231017144732-e3ff37491e9c
github.com/btcsuite/btcwallet v0.16.10-0.20231129183218-5df09dd43358
github.com/btcsuite/btcwallet/wallet/txauthor v1.3.2
github.com/btcsuite/btcwallet/wallet/txrules v1.2.0
github.com/btcsuite/btcwallet/walletdb v1.4.0

4
go.sum

@ -95,8 +95,8 @@ github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2/go.mod h1:7SFka0XMvUgj3hfZtyd
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/btcwallet v0.16.10-0.20231017144732-e3ff37491e9c h1:+7tbYEUj0TYYIvuvE9YP+x5dU3FT/8J6Qh8d5YvQwrE=
github.com/btcsuite/btcwallet v0.16.10-0.20231017144732-e3ff37491e9c/go.mod h1:WSKhOJWUmUOHKCKEzdt+jWAHFAE/t4RqVbCwL2pEdiU=
github.com/btcsuite/btcwallet v0.16.10-0.20231129183218-5df09dd43358 h1:lZUSo6TISHUJQxpn/AniW5gqaN1iRNS87SDWvV3AHfg=
github.com/btcsuite/btcwallet v0.16.10-0.20231129183218-5df09dd43358/go.mod h1:WSKhOJWUmUOHKCKEzdt+jWAHFAE/t4RqVbCwL2pEdiU=
github.com/btcsuite/btcwallet/wallet/txauthor v1.3.2 h1:etuLgGEojecsDOYTII8rYiGHjGyV5xTqsXi+ZQ715UU=
github.com/btcsuite/btcwallet/wallet/txauthor v1.3.2/go.mod h1:Zpk/LOb2sKqwP2lmHjaZT9AdaKsHPSbNLm2Uql5IQ/0=
github.com/btcsuite/btcwallet/wallet/txrules v1.2.0 h1:BtEN5Empw62/RVnZ0VcJaVtVlBijnLlJY+dwjAye2Bg=

@ -649,12 +649,13 @@ func (l *channelLink) createFailureWithUpdate(incoming bool,
// flow. We'll compare out commitment chains with the remote party, and re-send
// either a danging commit signature, a revocation, or both.
func (l *channelLink) syncChanStates() error {
l.log.Info("attempting to re-synchronize")
chanState := l.channel.State()
l.log.Infof("Attempting to re-synchronize channel: %v", chanState)
// First, we'll generate our ChanSync message to send to the other
// side. Based on this message, the remote party will decide if they
// need to retransmit any data or not.
chanState := l.channel.State()
localChanSyncMsg, err := chanState.ChanSyncMsg()
if err != nil {
return fmt.Errorf("unable to generate chan sync message for "+

@ -8,6 +8,7 @@ import (
"github.com/btcsuite/btcd/btcec/v2/schnorr"
"github.com/btcsuite/btcd/btcec/v2/schnorr/musig2"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnutils"
"github.com/lightningnetwork/lnd/multimutex"
)
@ -38,16 +39,18 @@ type MusigSessionManager struct {
sessionMtx *multimutex.Mutex[MuSig2SessionID]
musig2Sessions map[MuSig2SessionID]*MuSig2State
musig2Sessions *lnutils.SyncMap[MuSig2SessionID, *MuSig2State]
}
// NewMusigSessionManager creates a new musig manager given an abstract key
// fetcher.
func NewMusigSessionManager(keyFetcher PrivKeyFetcher) *MusigSessionManager {
return &MusigSessionManager{
keyFetcher: keyFetcher,
musig2Sessions: make(map[MuSig2SessionID]*MuSig2State),
sessionMtx: multimutex.NewMutex[MuSig2SessionID](),
keyFetcher: keyFetcher,
musig2Sessions: &lnutils.SyncMap[
MuSig2SessionID, *MuSig2State,
]{},
sessionMtx: multimutex.NewMutex[MuSig2SessionID](),
}
}
@ -134,9 +137,7 @@ func (m *MusigSessionManager) MuSig2CreateSession(bipVersion MuSig2Version,
//
// We'll use just all zeroes as the session ID for the mutex, as this
// is a "global" action.
m.sessionMtx.Lock(MuSig2SessionID{})
m.musig2Sessions[session.SessionID] = session
m.sessionMtx.Unlock(MuSig2SessionID{})
m.musig2Sessions.Store(session.SessionID, session)
return &session.MuSig2SessionInfo, nil
}
@ -157,7 +158,7 @@ func (m *MusigSessionManager) MuSig2Sign(sessionID MuSig2SessionID,
m.sessionMtx.Lock(sessionID)
defer m.sessionMtx.Unlock(sessionID)
session, ok := m.musig2Sessions[sessionID]
session, ok := m.musig2Sessions.Load(sessionID)
if !ok {
return nil, fmt.Errorf("session with ID %x not found",
sessionID[:])
@ -178,7 +179,7 @@ func (m *MusigSessionManager) MuSig2Sign(sessionID MuSig2SessionID,
// Clean up our local state if requested.
if cleanUp {
delete(m.musig2Sessions, sessionID)
m.musig2Sessions.Delete(sessionID)
}
return partialSig, nil
@ -198,7 +199,7 @@ func (m *MusigSessionManager) MuSig2CombineSig(sessionID MuSig2SessionID,
m.sessionMtx.Lock(sessionID)
defer m.sessionMtx.Unlock(sessionID)
session, ok := m.musig2Sessions[sessionID]
session, ok := m.musig2Sessions.Load(sessionID)
if !ok {
return nil, false, fmt.Errorf("session with ID %x not found",
sessionID[:])
@ -231,7 +232,7 @@ func (m *MusigSessionManager) MuSig2CombineSig(sessionID MuSig2SessionID,
// there is nothing more left to do.
if session.HaveAllSigs {
finalSig = session.session.FinalSig()
delete(m.musig2Sessions, sessionID)
m.musig2Sessions.Delete(sessionID)
}
return finalSig, session.HaveAllSigs, nil
@ -245,12 +246,12 @@ func (m *MusigSessionManager) MuSig2Cleanup(sessionID MuSig2SessionID) error {
m.sessionMtx.Lock(sessionID)
defer m.sessionMtx.Unlock(sessionID)
_, ok := m.musig2Sessions[sessionID]
_, ok := m.musig2Sessions.Load(sessionID)
if !ok {
return fmt.Errorf("session with ID %x not found", sessionID[:])
}
delete(m.musig2Sessions, sessionID)
m.musig2Sessions.Delete(sessionID)
return nil
}
@ -267,7 +268,7 @@ func (m *MusigSessionManager) MuSig2RegisterNonces(sessionID MuSig2SessionID,
m.sessionMtx.Lock(sessionID)
defer m.sessionMtx.Unlock(sessionID)
session, ok := m.musig2Sessions[sessionID]
session, ok := m.musig2Sessions.Load(sessionID)
if !ok {
return false, fmt.Errorf("session with ID %x not found",
sessionID[:])

@ -495,7 +495,8 @@ func (h *HarnessTest) Shutdown(node *node.HarnessNode) {
return h.manager.shutdownNode(node)
}, DefaultTimeout)
require.NoErrorf(h, err, "unable to shutdown %v", node.Name())
require.NoErrorf(h, err, "unable to shutdown %v in %v", node.Name(),
h.manager.currentTestCase)
}
// SuspendNode stops the given node and returns a callback that can be used to

@ -904,6 +904,8 @@ func (lc *LightningChannel) extractPayDescs(commitHeight uint64,
// persist state w.r.t to if forwarded or not, or can
// inadvertently trigger replays
htlc := htlc
payDesc, err := lc.diskHtlcToPayDesc(
feeRate, commitHeight, &htlc,
localCommitKeys, remoteCommitKeys,

@ -10112,3 +10112,101 @@ func testNewBreachRetribution(t *testing.T, chanType channeldb.ChannelType) {
)
require.ErrorIs(t, err, channeldb.ErrLogEntryNotFound)
}
// TestExtractPayDescs asserts that `extractPayDescs` can correctly turn a
// slice of htlcs into two slices of PaymentDescriptors.
func TestExtractPayDescs(t *testing.T) {
t.Parallel()
// Create a testing LightningChannel.
lnChan, _, err := CreateTestChannels(
t, channeldb.SingleFunderTweaklessBit,
)
require.NoError(t, err)
// Create two incoming HTLCs.
incomings := []channeldb.HTLC{
createRandomHTLC(t, true),
createRandomHTLC(t, true),
}
// Create two outgoing HTLCs.
outgoings := []channeldb.HTLC{
createRandomHTLC(t, false),
createRandomHTLC(t, false),
}
// Concatenate incomings and outgoings into a single slice.
htlcs := []channeldb.HTLC{}
htlcs = append(htlcs, incomings...)
htlcs = append(htlcs, outgoings...)
// Run the method under test.
//
// NOTE: we use nil commitment key rings to avoid checking the htlc
// scripts(`genHtlcScript`) as it should be tested independently.
incomingPDs, outgoingPDs, err := lnChan.extractPayDescs(
0, 0, htlcs, nil, nil, true,
)
require.NoError(t, err)
// Assert the incoming PaymentDescriptors are matched.
for i, pd := range incomingPDs {
htlc := incomings[i]
assertPayDescMatchHTLC(t, pd, htlc)
}
// Assert the outgoing PaymentDescriptors are matched.
for i, pd := range outgoingPDs {
htlc := outgoings[i]
assertPayDescMatchHTLC(t, pd, htlc)
}
}
// assertPayDescMatchHTLC compares a PaymentDescriptor to a channeldb.HTLC and
// asserts that the fields are matched.
func assertPayDescMatchHTLC(t *testing.T, pd PaymentDescriptor,
htlc channeldb.HTLC) {
require := require.New(t)
require.EqualValues(htlc.RHash, pd.RHash, "RHash")
require.Equal(htlc.RefundTimeout, pd.Timeout, "Timeout")
require.Equal(htlc.Amt, pd.Amount, "Amount")
require.Equal(htlc.HtlcIndex, pd.HtlcIndex, "HtlcIndex")
require.Equal(htlc.LogIndex, pd.LogIndex, "LogIndex")
require.EqualValues(htlc.OnionBlob[:], pd.OnionBlob, "OnionBlob")
}
// createRandomHTLC creates an HTLC that has random value in every field except
// the `Incoming`.
func createRandomHTLC(t *testing.T, incoming bool) channeldb.HTLC {
var onionBlob [lnwire.OnionPacketSize]byte
_, err := rand.Read(onionBlob[:])
require.NoError(t, err)
var rHash [lntypes.HashSize]byte
_, err = rand.Read(rHash[:])
require.NoError(t, err)
sig := make([]byte, 64)
_, err = rand.Read(sig)
require.NoError(t, err)
extra := make([]byte, 1000)
_, err = rand.Read(extra)
require.NoError(t, err)
return channeldb.HTLC{
Signature: sig,
RHash: rHash,
Amt: lnwire.MilliSatoshi(rand.Uint64()),
RefundTimeout: rand.Uint32(),
OutputIndex: rand.Int31n(1000),
Incoming: incoming,
OnionBlob: onionBlob,
HtlcIndex: rand.Uint64(),
LogIndex: rand.Uint64(),
ExtraData: extra,
}
}

@ -1941,7 +1941,8 @@ func messageSummary(msg lnwire.Message) string {
msg.ChanID, int64(msg.FeePerKw))
case *lnwire.ChannelReestablish:
return fmt.Sprintf("next_local_height=%v, remote_tail_height=%v",
return fmt.Sprintf("chan_id=%v, next_local_height=%v, "+
"remote_tail_height=%v", msg.ChanID,
msg.NextLocalCommitHeight, msg.RemoteCommitTailHeight)
case *lnwire.ReplyShortChanIDsEnd:

@ -1552,7 +1552,7 @@ func (r *ChannelRouter) processUpdate(msg interface{},
// to obtain the full funding outpoint that's encoded within
// the channel ID.
channelID := lnwire.NewShortChanIDFromInt(msg.ChannelID)
fundingTx, err := r.fetchFundingTx(&channelID)
fundingTx, err := r.fetchFundingTxWrapper(&channelID)
if err != nil {
// In order to ensure we don't erroneously mark a
// channel as a zombie due to an RPC failure, we'll
@ -1762,6 +1762,36 @@ func (r *ChannelRouter) processUpdate(msg interface{},
return nil
}
// fetchFundingTxWrapper is a wrapper around fetchFundingTx, except that it
// will exit if the router has stopped.
func (r *ChannelRouter) fetchFundingTxWrapper(chanID *lnwire.ShortChannelID) (
*wire.MsgTx, error) {
txChan := make(chan *wire.MsgTx, 1)
errChan := make(chan error, 1)
go func() {
tx, err := r.fetchFundingTx(chanID)
if err != nil {
errChan <- err
return
}
txChan <- tx
}()
select {
case tx := <-txChan:
return tx, nil
case err := <-errChan:
return nil, err
case <-r.quit:
return nil, ErrRouterShuttingDown
}
}
// fetchFundingTx returns the funding transaction identified by the passed
// short channel ID.
//