mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-04-01 16:39:04 +02:00
Merge pull request #8241 from Roasbeef/v0-17-3-branch
release: create v0.17.3-beta.rc1 release branch
This commit is contained in:
commit
d5b05d6930
@ -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
|
||||
}
|
||||
|
||||
|
57
docs/release-notes/release-notes-0.17.3.md
Normal file
57
docs/release-notes/release-notes-0.17.3.md
Normal file
@ -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
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
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.
|
||||
//
|
||||
|
Loading…
x
Reference in New Issue
Block a user