diff --git a/chanbackup/log.go b/chanbackup/log.go index 730fbc9e4..34eb9e93f 100644 --- a/chanbackup/log.go +++ b/chanbackup/log.go @@ -27,19 +27,3 @@ func DisableLog() { func UseLogger(logger btclog.Logger) { log = logger } - -// logClosure is used to provide a closure over expensive logging operations so -// don't have to be performed when the logging level doesn't warrant it. -type logClosure func() string - -// String invokes the underlying function and returns the result. -func (c logClosure) String() string { - return c() -} - -// newLogClosure returns a new closure over a function that returns a string -// which itself provides a Stringer interface so that it can be used with the -// logging system. -func newLogClosure(c func() string) logClosure { - return logClosure(c) -} diff --git a/chanbackup/pubsub.go b/chanbackup/pubsub.go index 987678d92..7652d3654 100644 --- a/chanbackup/pubsub.go +++ b/chanbackup/pubsub.go @@ -10,6 +10,7 @@ import ( "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/keychain" + "github.com/lightningnetwork/lnd/lnutils" ) // Swapper is an interface that allows the chanbackup.SubSwapper to update the @@ -278,9 +279,8 @@ func (s *SubSwapper) backupUpdater() { ) for i, closedChan := range chanUpdate.ClosedChans { log.Debugf("Removing channel %v from backup "+ - "state", newLogClosure(func() string { - return chanUpdate.ClosedChans[i].String() - })) + "state", lnutils.NewLogClosure( + chanUpdate.ClosedChans[i].String)) delete(s.backupState, closedChan) diff --git a/chanbackup/recover.go b/chanbackup/recover.go index ebd48dccf..7f5502c4a 100644 --- a/chanbackup/recover.go +++ b/chanbackup/recover.go @@ -4,9 +4,9 @@ import ( "net" "github.com/btcsuite/btcd/btcec/v2" - "github.com/davecgh/go-spew/spew" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/keychain" + "github.com/lightningnetwork/lnd/lnutils" ) // ChannelRestorer is an interface that allows the Recover method to map the @@ -63,9 +63,8 @@ func Recover(backups []Single, restorer ChannelRestorer, log.Infof("Attempting to connect to node=%x (addrs=%v) to "+ "restore ChannelPoint(%v)", backup.RemoteNodePub.SerializeCompressed(), - newLogClosure(func() string { - return spew.Sdump(backups[i].Addresses) - }), backup.FundingOutpoint) + lnutils.SpewLogClosure(backups[i].Addresses), + backup.FundingOutpoint) err = peerConnector.ConnectPeer( backup.RemoteNodePub, backup.Addresses, diff --git a/contractcourt/breach_arbitrator.go b/contractcourt/breach_arbitrator.go index 96fa689c3..e3dd85ea6 100644 --- a/contractcourt/breach_arbitrator.go +++ b/contractcourt/breach_arbitrator.go @@ -13,13 +13,13 @@ import ( "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" - "github.com/davecgh/go-spew/spew" "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/kvdb" "github.com/lightningnetwork/lnd/labels" "github.com/lightningnetwork/lnd/lntypes" + "github.com/lightningnetwork/lnd/lnutils" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet/chainfee" ) @@ -732,9 +732,8 @@ justiceTxBroadcast: } finalTx := justiceTxs.spendAll - brarLog.Debugf("Broadcasting justice tx: %v", newLogClosure(func() string { - return spew.Sdump(finalTx) - })) + brarLog.Debugf("Broadcasting justice tx: %v", lnutils.SpewLogClosure( + finalTx)) // We'll now attempt to broadcast the transaction which finalized the // channel's retribution against the cheating counter party. @@ -857,9 +856,7 @@ Loop: brarLog.Debugf("Broadcasting justice tx "+ "spending commitment outs: %v", - newLogClosure(func() string { - return spew.Sdump(tx) - })) + lnutils.SpewLogClosure(tx)) err = b.cfg.PublishTransaction(tx, label) if err != nil { @@ -874,9 +871,7 @@ Loop: brarLog.Debugf("Broadcasting justice tx "+ "spending HTLC outs: %v", - newLogClosure(func() string { - return spew.Sdump(tx) - })) + lnutils.SpewLogClosure(tx)) err = b.cfg.PublishTransaction(tx, label) if err != nil { @@ -891,9 +886,7 @@ Loop: brarLog.Debugf("Broadcasting justice tx "+ "spending second-level HTLC output: %v", - newLogClosure(func() string { - return spew.Sdump(tx) - })) + lnutils.SpewLogClosure(tx)) err = b.cfg.PublishTransaction(tx, label) if err != nil { diff --git a/contractcourt/chain_watcher.go b/contractcourt/chain_watcher.go index f1733ad1f..962a239e7 100644 --- a/contractcourt/chain_watcher.go +++ b/contractcourt/chain_watcher.go @@ -20,6 +20,7 @@ import ( "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/fn" "github.com/lightningnetwork/lnd/input" + "github.com/lightningnetwork/lnd/lnutils" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwire" ) @@ -1254,7 +1255,7 @@ func (c *chainWatcher) dispatchContractBreach(spendEvent *chainntnfs.SpendDetail spendHeight := uint32(spendEvent.SpendingHeight) log.Debugf("Punishment breach retribution created: %v", - newLogClosure(func() string { + lnutils.NewLogClosure(func() string { retribution.KeyRing.LocalHtlcKey = nil retribution.KeyRing.RemoteHtlcKey = nil retribution.KeyRing.ToLocalKey = nil diff --git a/contractcourt/channel_arbitrator.go b/contractcourt/channel_arbitrator.go index cda0d4e1f..d544e989c 100644 --- a/contractcourt/channel_arbitrator.go +++ b/contractcourt/channel_arbitrator.go @@ -14,7 +14,6 @@ import ( "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" - "github.com/davecgh/go-spew/spew" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb/models" "github.com/lightningnetwork/lnd/fn" @@ -24,6 +23,7 @@ import ( "github.com/lightningnetwork/lnd/kvdb" "github.com/lightningnetwork/lnd/labels" "github.com/lightningnetwork/lnd/lntypes" + "github.com/lightningnetwork/lnd/lnutils" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/sweep" @@ -465,10 +465,8 @@ func (c *ChannelArbitrator) Start(state *chanArbStartState) error { } log.Debugf("Starting ChannelArbitrator(%v), htlc_set=%v, state=%v", - c.cfg.ChanPoint, newLogClosure(func() string { - return spew.Sdump(c.activeHTLCs) - }), state.currentState, - ) + c.cfg.ChanPoint, lnutils.SpewLogClosure(c.activeHTLCs), + state.currentState) // Set our state from our starting state. c.state = state.currentState @@ -958,10 +956,7 @@ func (c *ChannelArbitrator) stateStep( // Otherwise, we'll log that we checked the HTLC actions as the // commitment transaction has already been broadcast. log.Tracef("ChannelArbitrator(%v): logging chain_actions=%v", - c.cfg.ChanPoint, - newLogClosure(func() string { - return spew.Sdump(chainActions) - })) + c.cfg.ChanPoint, lnutils.SpewLogClosure(chainActions)) // Depending on the type of trigger, we'll either "tunnel" // through to a farther state, or just proceed linearly to the @@ -1096,10 +1091,7 @@ func (c *ChannelArbitrator) stateStep( // channel resolution state. log.Infof("Broadcasting force close transaction %v, "+ "ChannelPoint(%v): %v", closeTx.TxHash(), - c.cfg.ChanPoint, - newLogClosure(func() string { - return spew.Sdump(closeTx) - })) + c.cfg.ChanPoint, lnutils.SpewLogClosure(closeTx)) // At this point, we'll now broadcast the commitment // transaction itself. @@ -1224,9 +1216,7 @@ func (c *ChannelArbitrator) stateStep( if len(pktsToSend) != 0 { log.Debugf("ChannelArbitrator(%v): sending "+ "resolution message=%v", c.cfg.ChanPoint, - newLogClosure(func() string { - return spew.Sdump(pktsToSend) - })) + lnutils.SpewLogClosure(pktsToSend)) err := c.cfg.DeliverResolutionMsg(pktsToSend...) if err != nil { @@ -2741,11 +2731,7 @@ func (c *ChannelArbitrator) notifyContractUpdate(upd *ContractUpdate) { c.unmergedSet[upd.HtlcKey] = newHtlcSet(upd.Htlcs) log.Tracef("ChannelArbitrator(%v): fresh set of htlcs=%v", - c.cfg.ChanPoint, - newLogClosure(func() string { - return spew.Sdump(upd) - }), - ) + c.cfg.ChanPoint, lnutils.SpewLogClosure(upd)) } // updateActiveHTLCs merges the unmerged set of HTLCs from the link with diff --git a/contractcourt/log.go b/contractcourt/log.go index 2891781e8..2e52cc97d 100644 --- a/contractcourt/log.go +++ b/contractcourt/log.go @@ -51,19 +51,3 @@ func UseBreachLogger(logger btclog.Logger) { func UseNurseryLogger(logger btclog.Logger) { utxnLog = logger } - -// logClosure is used to provide a closure over expensive logging operations so -// don't have to be performed when the logging level doesn't warrant it. -type logClosure func() string - -// String invokes the underlying function and returns the result. -func (c logClosure) String() string { - return c() -} - -// newLogClosure returns a new closure over a function that returns a string -// which itself provides a Stringer interface so that it can be used with the -// logging system. -func newLogClosure(c func() string) logClosure { - return logClosure(c) -} diff --git a/contractcourt/utxonursery.go b/contractcourt/utxonursery.go index f419881da..407384162 100644 --- a/contractcourt/utxonursery.go +++ b/contractcourt/utxonursery.go @@ -18,6 +18,7 @@ import ( "github.com/lightningnetwork/lnd/fn" "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/labels" + "github.com/lightningnetwork/lnd/lnutils" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/sweep" ) @@ -947,10 +948,7 @@ func (u *UtxoNursery) waitForSweepConf(classHeight uint32, func (u *UtxoNursery) sweepCribOutput(classHeight uint32, baby *babyOutput) error { utxnLog.Infof("Publishing CLTV-delayed HTLC output using timeout tx "+ "(txid=%v): %v", baby.timeoutTx.TxHash(), - newLogClosure(func() string { - return spew.Sdump(baby.timeoutTx) - }), - ) + lnutils.SpewLogClosure(baby.timeoutTx)) // We'll now broadcast the HTLC transaction, then wait for it to be // confirmed before transitioning it to kindergarten. diff --git a/discovery/bootstrapper.go b/discovery/bootstrapper.go index 67dbc7e23..0d370663d 100644 --- a/discovery/bootstrapper.go +++ b/discovery/bootstrapper.go @@ -14,8 +14,8 @@ import ( "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcutil/bech32" - "github.com/davecgh/go-spew/spew" "github.com/lightningnetwork/lnd/autopilot" + "github.com/lightningnetwork/lnd/lnutils" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/tor" "github.com/miekg/dns" @@ -431,10 +431,7 @@ search: } log.Tracef("Retrieved SRV records from dns seed: %v", - newLogClosure(func() string { - return spew.Sdump(addrs) - }), - ) + lnutils.SpewLogClosure(addrs)) // Next, we'll need to issue an A record request for each of // the nodes, skipping it if nothing comes back. diff --git a/discovery/log.go b/discovery/log.go index bd2004d3d..f09e7fb71 100644 --- a/discovery/log.go +++ b/discovery/log.go @@ -27,19 +27,3 @@ func DisableLog() { func UseLogger(logger btclog.Logger) { log = logger } - -// logClosure is used to provide a closure over expensive logging operations -// so don't have to be performed when the logging level doesn't warrant it. -type logClosure func() string - -// String invokes the underlying function and returns the result. -func (c logClosure) String() string { - return c() -} - -// newLogClosure returns a new closure over a function that returns a string -// which itself provides a Stringer interface so that it can be used with the -// logging system. -func newLogClosure(c func() string) logClosure { - return logClosure(c) -} diff --git a/docs/release-notes/release-notes-0.18.3.md b/docs/release-notes/release-notes-0.18.3.md index 8d658624f..ba39d05e7 100644 --- a/docs/release-notes/release-notes-0.18.3.md +++ b/docs/release-notes/release-notes-0.18.3.md @@ -55,6 +55,24 @@ # Improvements ## Functional Updates + +* A new field, `min_relay_feerate`, is [now + expected](https://github.com/lightningnetwork/lnd/pull/8891) in the response + from querying the external fee estimation URL. The new response should have + the format, + ```json + { + "fee_by_block_target": { + "2": 5076, + "3": 4228, + "26": 4200 + }, + "min_relay_feerate": 1000 + } + ``` + All units are `sats/kvB`. If the new field `min_relay_feerate` is not set, + the default floor feerate (1012 sats/kvB) will be used. + ## RPC Updates * [`xImportMissionControl`](https://github.com/lightningnetwork/lnd/pull/8779) diff --git a/graph/builder.go b/graph/builder.go index 2436f3176..addec9e1b 100644 --- a/graph/builder.go +++ b/graph/builder.go @@ -12,7 +12,6 @@ import ( "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/wire" - "github.com/davecgh/go-spew/spew" "github.com/go-errors/errors" "github.com/lightningnetwork/lnd/batch" "github.com/lightningnetwork/lnd/chainntnfs" @@ -1432,7 +1431,7 @@ func (b *Builder) processUpdate(msg interface{}, } log.Tracef("New channel update applied: %v", - newLogClosure(func() string { return spew.Sdump(msg) })) + lnutils.SpewLogClosure(msg)) b.stats.incNumChannelUpdates() default: diff --git a/graph/log.go b/graph/log.go index cd31dae11..7d2f741c6 100644 --- a/graph/log.go +++ b/graph/log.go @@ -29,19 +29,3 @@ func DisableLog() { func UseLogger(logger btclog.Logger) { log = logger } - -// logClosure is used to provide a closure over expensive logging operations so -// don't have to be performed when the logging level doesn't warrant it. -type logClosure func() string - -// String invokes the underlying function and returns the result. -func (c logClosure) String() string { - return c() -} - -// newLogClosure returns a new closure over a function that returns a string -// which itself provides a Stringer interface so that it can be used with the -// logging system. -func newLogClosure(c func() string) logClosure { - return logClosure(c) -} diff --git a/htlcswitch/circuit_map.go b/htlcswitch/circuit_map.go index 9b26a1d07..076d6f284 100644 --- a/htlcswitch/circuit_map.go +++ b/htlcswitch/circuit_map.go @@ -5,11 +5,11 @@ import ( "fmt" "sync" - "github.com/davecgh/go-spew/spew" "github.com/go-errors/errors" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/htlcswitch/hop" "github.com/lightningnetwork/lnd/kvdb" + "github.com/lightningnetwork/lnd/lnutils" "github.com/lightningnetwork/lnd/lnwire" ) @@ -800,9 +800,8 @@ func (cm *circuitMap) CommitCircuits(circuits ...*PaymentCircuit) ( inKeys = append(inKeys, circuit.Incoming) } - log.Tracef("Committing fresh circuits: %v", newLogClosure(func() string { - return spew.Sdump(inKeys) - })) + log.Tracef("Committing fresh circuits: %v", lnutils.SpewLogClosure( + inKeys)) actions := &CircuitFwdActions{} @@ -948,9 +947,8 @@ func (cm *circuitMap) OpenCircuits(keystones ...Keystone) error { return nil } - log.Tracef("Opening finalized circuits: %v", newLogClosure(func() string { - return spew.Sdump(keystones) - })) + log.Tracef("Opening finalized circuits: %v", lnutils.SpewLogClosure( + keystones)) // Check that all keystones correspond to committed-but-unopened // circuits. @@ -1078,9 +1076,8 @@ func (cm *circuitMap) CloseCircuit(outKey CircuitKey) (*PaymentCircuit, error) { // circuit was already cleaned up at a different point in time. func (cm *circuitMap) DeleteCircuits(inKeys ...CircuitKey) error { - log.Tracef("Deleting resolved circuits: %v", newLogClosure(func() string { - return spew.Sdump(inKeys) - })) + log.Tracef("Deleting resolved circuits: %v", lnutils.SpewLogClosure( + inKeys)) var ( closingCircuits = make(map[CircuitKey]struct{}) diff --git a/htlcswitch/link.go b/htlcswitch/link.go index c0c828f83..712bbda9e 100644 --- a/htlcswitch/link.go +++ b/htlcswitch/link.go @@ -13,7 +13,6 @@ import ( "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btclog" - "github.com/davecgh/go-spew/spew" "github.com/go-errors/errors" "github.com/lightningnetwork/lnd/build" "github.com/lightningnetwork/lnd/channeldb" @@ -25,6 +24,7 @@ import ( "github.com/lightningnetwork/lnd/invoices" "github.com/lightningnetwork/lnd/lnpeer" "github.com/lightningnetwork/lnd/lntypes" + "github.com/lightningnetwork/lnd/lnutils" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/lnwire" @@ -2536,13 +2536,9 @@ func (l *channelLink) updateCommitTx() error { l.log.Tracef("revocation window exhausted, unable to send: "+ "%v, pend_updates=%v, dangling_closes%v", l.channel.PendingLocalUpdateCount(), - newLogClosure(func() string { - return spew.Sdump(l.openedCircuits) - }), - newLogClosure(func() string { - return spew.Sdump(l.closedCircuits) - }), - ) + lnutils.SpewLogClosure(l.openedCircuits), + lnutils.SpewLogClosure(l.closedCircuits)) + return nil } else if err != nil { return err diff --git a/htlcswitch/log.go b/htlcswitch/log.go index 5749de09e..79259be91 100644 --- a/htlcswitch/log.go +++ b/htlcswitch/log.go @@ -31,19 +31,3 @@ func UseLogger(logger btclog.Logger) { log = logger hop.UseLogger(logger) } - -// logClosure is used to provide a closure over expensive logging operations so -// don't have to be performed when the logging level doesn't warrant it. -type logClosure func() string - -// String invokes the underlying function and returns the result. -func (c logClosure) String() string { - return c() -} - -// newLogClosure returns a new closure over a function that returns a string -// which itself provides a Stringer interface so that it can be used with the -// logging system. -func newLogClosure(c func() string) logClosure { - return logClosure(c) -} diff --git a/htlcswitch/switch.go b/htlcswitch/switch.go index d473d8422..a78266113 100644 --- a/htlcswitch/switch.go +++ b/htlcswitch/switch.go @@ -21,6 +21,7 @@ import ( "github.com/lightningnetwork/lnd/htlcswitch/hop" "github.com/lightningnetwork/lnd/kvdb" "github.com/lightningnetwork/lnd/lntypes" + "github.com/lightningnetwork/lnd/lnutils" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/lnwire" @@ -613,9 +614,8 @@ func (s *Switch) SendHTLC(firstHop lnwire.ShortChannelID, attemptID uint64, func (s *Switch) UpdateForwardingPolicies( chanPolicies map[wire.OutPoint]models.ForwardingPolicy) { - log.Tracef("Updating link policies: %v", newLogClosure(func() string { - return spew.Sdump(chanPolicies) - })) + log.Tracef("Updating link policies: %v", lnutils.SpewLogClosure( + chanPolicies)) s.indexMtx.RLock() @@ -1213,9 +1213,8 @@ func (s *Switch) handlePacketForward(packet *htlcPacket) error { ) log.Warnf("unable to find err source for "+ "outgoing_link=%v, errors=%v", - packet.outgoingChanID, newLogClosure(func() string { - return spew.Sdump(linkErrs) - })) + packet.outgoingChanID, + lnutils.SpewLogClosure(linkErrs)) } log.Tracef("incoming HTLC(%x) violated "+ @@ -1994,10 +1993,9 @@ out: continue } - log.Tracef("Acked %d settle fails: %v", len(s.pendingSettleFails), - newLogClosure(func() string { - return spew.Sdump(s.pendingSettleFails) - })) + log.Tracef("Acked %d settle fails: %v", + len(s.pendingSettleFails), + lnutils.SpewLogClosure(s.pendingSettleFails)) // Reset the pendingSettleFails buffer while keeping acquired // memory. diff --git a/lnrpc/devrpc/log.go b/lnrpc/devrpc/log.go index 2ff536b84..9cae145e5 100644 --- a/lnrpc/devrpc/log.go +++ b/lnrpc/devrpc/log.go @@ -27,19 +27,3 @@ func DisableLog() { func UseLogger(logger btclog.Logger) { log = logger } - -// logClosure is used to provide a closure over expensive logging operations so -// don't have to be performed when the logging level doesn't warrant it. -type logClosure func() string // nolint:unused - -// String invokes the underlying function and returns the result. -func (c logClosure) String() string { - return c() -} - -// newLogClosure returns a new closure over a function that returns a string -// which itself provides a Stringer interface so that it can be used with the -// logging system. -func newLogClosure(c func() string) logClosure { // nolint:unused - return logClosure(c) -} diff --git a/lnrpc/invoicesrpc/addinvoice.go b/lnrpc/invoicesrpc/addinvoice.go index 4b55f3f0d..b85feefb6 100644 --- a/lnrpc/invoicesrpc/addinvoice.go +++ b/lnrpc/invoicesrpc/addinvoice.go @@ -15,11 +15,11 @@ import ( "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/wire" - "github.com/davecgh/go-spew/spew" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb/models" "github.com/lightningnetwork/lnd/invoices" "github.com/lightningnetwork/lnd/lntypes" + "github.com/lightningnetwork/lnd/lnutils" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/netann" "github.com/lightningnetwork/lnd/routing" @@ -473,10 +473,7 @@ func AddInvoice(ctx context.Context, cfg *AddInvoiceConfig, } log.Tracef("[addinvoice] adding new invoice %v", - newLogClosure(func() string { - return spew.Sdump(newInvoice) - }), - ) + lnutils.SpewLogClosure(newInvoice)) // With all sanity checks passed, write the invoice to the database. _, err = cfg.AddInvoice(ctx, newInvoice, paymentHash) diff --git a/lnrpc/invoicesrpc/log.go b/lnrpc/invoicesrpc/log.go index 8429ee51c..f3644fdb5 100644 --- a/lnrpc/invoicesrpc/log.go +++ b/lnrpc/invoicesrpc/log.go @@ -27,19 +27,3 @@ func DisableLog() { func UseLogger(logger btclog.Logger) { log = logger } - -// logClosure is used to provide a closure over expensive logging operations so -// don't have to be performed when the logging level doesn't warrant it. -type logClosure func() string - -// String invokes the underlying function and returns the result. -func (c logClosure) String() string { - return c() -} - -// newLogClosure returns a new closure over a function that returns a string -// which itself provides a Stringer interface so that it can be used with the -// logging system. -func newLogClosure(c func() string) logClosure { - return logClosure(c) -} diff --git a/lntest/fee_service.go b/lntest/fee_service.go index cee9ae0ab..0514a387e 100644 --- a/lntest/fee_service.go +++ b/lntest/fee_service.go @@ -33,6 +33,9 @@ type WebFeeService interface { // target. SetFeeRate(feeRate chainfee.SatPerKWeight, conf uint32) + // SetMinRelayFeerate sets a min relay feerate. + SetMinRelayFeerate(fee chainfee.SatPerKVByte) + // Reset resets the fee rate map to the default value. Reset() } @@ -52,8 +55,9 @@ const ( type FeeService struct { *testing.T - feeRateMap map[uint32]uint32 - url string + feeRateMap map[uint32]uint32 + minRelayFeerate chainfee.SatPerKVByte + url string srv *http.Server wg sync.WaitGroup @@ -79,6 +83,7 @@ func NewFeeService(t *testing.T) *FeeService { f.feeRateMap = map[uint32]uint32{ feeServiceTarget: DefaultFeeRateSatPerKw, } + f.minRelayFeerate = chainfee.FeePerKwFloor.FeePerKVByte() listenAddr := fmt.Sprintf(":%v", port) mux := http.NewServeMux() @@ -113,10 +118,9 @@ func (f *FeeService) handleRequest(w http.ResponseWriter, _ *http.Request) { defer f.lock.Unlock() bytes, err := json.Marshal( - struct { - Fees map[uint32]uint32 `json:"fee_by_block_target"` - }{ - Fees: f.feeRateMap, + chainfee.WebAPIResponse{ + FeeByBlockTarget: f.feeRateMap, + MinRelayFeerate: f.minRelayFeerate, }, ) require.NoErrorf(f, err, "cannot serialize estimates") @@ -143,6 +147,14 @@ func (f *FeeService) SetFeeRate(fee chainfee.SatPerKWeight, conf uint32) { f.feeRateMap[conf] = uint32(fee.FeePerKVByte()) } +// SetMinRelayFeerate sets a min relay feerate. +func (f *FeeService) SetMinRelayFeerate(fee chainfee.SatPerKVByte) { + f.lock.Lock() + defer f.lock.Unlock() + + f.minRelayFeerate = fee +} + // Reset resets the fee rate map to the default value. func (f *FeeService) Reset() { f.lock.Lock() diff --git a/lntest/harness.go b/lntest/harness.go index eefdcfec1..9a11eaa88 100644 --- a/lntest/harness.go +++ b/lntest/harness.go @@ -860,6 +860,12 @@ func (h *HarnessTest) SetFeeEstimateWithConf( h.feeService.SetFeeRate(fee, conf) } +// SetMinRelayFeerate sets a min relay fee rate to be returned from fee +// estimator. +func (h *HarnessTest) SetMinRelayFeerate(fee chainfee.SatPerKVByte) { + h.feeService.SetMinRelayFeerate(fee) +} + // validateNodeState checks that the node doesn't have any uncleaned states // which will affect its following tests. func (h *HarnessTest) validateNodeState(hn *node.HarnessNode) error { diff --git a/lnutils/log.go b/lnutils/log.go new file mode 100644 index 000000000..a32738bdf --- /dev/null +++ b/lnutils/log.go @@ -0,0 +1,27 @@ +package lnutils + +import "github.com/davecgh/go-spew/spew" + +// LogClosure is used to provide a closure over expensive logging operations so +// don't have to be performed when the logging level doesn't warrant it. +type LogClosure func() string + +// String invokes the underlying function and returns the result. +func (c LogClosure) String() string { + return c() +} + +// NewLogClosure returns a new closure over a function that returns a string +// which itself provides a Stringer interface so that it can be used with the +// logging system. +func NewLogClosure(c func() string) LogClosure { + return LogClosure(c) +} + +// SpewLogClosure takes an interface and returns the string of it created from +// `spew.Sdump` in a LogClosure. +func SpewLogClosure(a any) LogClosure { + return func() string { + return spew.Sdump(a) + } +} diff --git a/lnwallet/chainfee/estimator.go b/lnwallet/chainfee/estimator.go index 0ce9ae9b8..d9a402964 100644 --- a/lnwallet/chainfee/estimator.go +++ b/lnwallet/chainfee/estimator.go @@ -10,10 +10,12 @@ import ( "net" "net/http" "sync" + "sync/atomic" "time" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/rpcclient" + "github.com/lightningnetwork/lnd/lnutils" ) const ( @@ -628,9 +630,10 @@ var _ Estimator = (*BitcoindEstimator)(nil) // implementation of this interface in order to allow the WebAPIEstimator to // be fully generic in its logic. type WebAPIFeeSource interface { - // GetFeeMap will query the web API, parse the response and return a - // map of confirmation targets to sat/kw fees. - GetFeeMap() (map[uint32]uint32, error) + // GetFeeInfo will query the web API, parse the response into a + // WebAPIResponse which contains a map of confirmation targets to + // sat/kw fees and min relay feerate. + GetFeeInfo() (WebAPIResponse, error) } // SparseConfFeeSource is an implementation of the WebAPIFeeSource that utilizes @@ -642,30 +645,43 @@ type SparseConfFeeSource struct { URL string } +// WebAPIResponse is the response returned by the fee estimation API. +type WebAPIResponse struct { + // FeeByBlockTarget is a map of confirmation targets to sat/kvb fees. + FeeByBlockTarget map[uint32]uint32 `json:"fee_by_block_target"` + + // MinRelayFeerate is the minimum relay fee in sat/kvb. + MinRelayFeerate SatPerKVByte `json:"min_relay_feerate"` +} + // parseResponse attempts to parse the body of the response generated by the // above query URL. Typically this will be JSON, but the specifics are left to // the WebAPIFeeSource implementation. func (s SparseConfFeeSource) parseResponse(r io.Reader) ( - map[uint32]uint32, error) { + WebAPIResponse, error) { - type jsonResp struct { - FeeByBlockTarget map[uint32]uint32 `json:"fee_by_block_target"` - } - - resp := jsonResp{ + resp := WebAPIResponse{ FeeByBlockTarget: make(map[uint32]uint32), + MinRelayFeerate: 0, } jsonReader := json.NewDecoder(r) if err := jsonReader.Decode(&resp); err != nil { - return nil, err + return WebAPIResponse{}, err } - return resp.FeeByBlockTarget, nil + if resp.MinRelayFeerate == 0 { + log.Errorf("No min relay fee rate available, using default %v", + FeePerKwFloor) + resp.MinRelayFeerate = FeePerKwFloor.FeePerKVByte() + } + + return resp, nil } -// GetFeeMap will query the web API, parse the response and return a map of -// confirmation targets to sat/kw fees. -func (s SparseConfFeeSource) GetFeeMap() (map[uint32]uint32, error) { +// GetFeeInfo will query the web API, parse the response and return a map of +// confirmation targets to sat/kw fees and min relay feerate in a parsed +// response. +func (s SparseConfFeeSource) GetFeeInfo() (WebAPIResponse, error) { // Rather than use the default http.Client, we'll make a custom one // which will allow us to control how long we'll wait to read the // response from the service. This way, if the service is down or @@ -688,20 +704,20 @@ func (s SparseConfFeeSource) GetFeeMap() (map[uint32]uint32, error) { if err != nil { log.Errorf("unable to query web api for fee response: %v", err) - return nil, err + return WebAPIResponse{}, err } defer resp.Body.Close() // Once we've obtained the response, we'll instruct the WebAPIFeeSource // to parse out the body to obtain our final result. - feesByBlockTarget, err := s.parseResponse(resp.Body) + parsedResp, err := s.parseResponse(resp.Body) if err != nil { log.Errorf("unable to parse fee api response: %v", err) - return nil, err + return WebAPIResponse{}, err } - return feesByBlockTarget, nil + return parsedResp, nil } // A compile-time assertion to ensure that SparseConfFeeSource implements the @@ -711,8 +727,8 @@ var _ WebAPIFeeSource = (*SparseConfFeeSource)(nil) // WebAPIEstimator is an implementation of the Estimator interface that // queries an HTTP-based fee estimation from an existing web API. type WebAPIEstimator struct { - started sync.Once - stopped sync.Once + started atomic.Bool + stopped atomic.Bool // apiSource is the backing web API source we'll use for our queries. apiSource WebAPIFeeSource @@ -726,6 +742,7 @@ type WebAPIEstimator struct { // rather than re-querying the API, to prevent an inadvertent DoS attack. feesMtx sync.Mutex feeByBlockTarget map[uint32]uint32 + minRelayFeerate SatPerKVByte // noCache determines whether the web estimator should cache fee // estimates. @@ -777,6 +794,12 @@ func NewWebAPIEstimator(api WebAPIFeeSource, noCache bool, func (w *WebAPIEstimator) EstimateFeePerKW(numBlocks uint32) ( SatPerKWeight, error) { + // If the estimator hasn't been started yet, we'll return an error as + // we can't provide a fee estimate. + if !w.started.Load() { + return 0, fmt.Errorf("estimator not started") + } + if numBlocks > MaxBlockTarget { numBlocks = MaxBlockTarget } else if numBlocks < minBlockTarget { @@ -816,28 +839,33 @@ func (w *WebAPIEstimator) EstimateFeePerKW(numBlocks uint32) ( // // NOTE: This method is part of the Estimator interface. func (w *WebAPIEstimator) Start() error { + log.Infof("Starting Web API fee estimator...") + + // Return an error if it's already been started. + if w.started.Load() { + return fmt.Errorf("web API fee estimator already started") + } + defer w.started.Store(true) + + // During startup we'll query the API to initialize the fee map. + w.updateFeeEstimates() + // No update loop is needed when we don't cache. if w.noCache { return nil } - var err error - w.started.Do(func() { - log.Infof("Starting web API fee estimator") + feeUpdateTimeout := w.randomFeeUpdateTimeout() - feeUpdateTimeout := w.randomFeeUpdateTimeout() + log.Infof("Web API fee estimator using update timeout of %v", + feeUpdateTimeout) - log.Infof("Web API fee estimator using update timeout of %v", - feeUpdateTimeout) + w.updateFeeTicker = time.NewTicker(feeUpdateTimeout) - w.updateFeeTicker = time.NewTicker(feeUpdateTimeout) - w.updateFeeEstimates() + w.wg.Add(1) + go w.feeUpdateManager() - w.wg.Add(1) - go w.feeUpdateManager() - - }) - return err + return nil } // Stop stops any spawned goroutines and cleans up the resources used by the @@ -845,19 +873,22 @@ func (w *WebAPIEstimator) Start() error { // // NOTE: This method is part of the Estimator interface. func (w *WebAPIEstimator) Stop() error { + log.Infof("Stopping web API fee estimator") + + if w.stopped.Swap(true) { + return fmt.Errorf("web API fee estimator already stopped") + } + // Update loop is not running when we don't cache. if w.noCache { return nil } - w.stopped.Do(func() { - log.Infof("Stopping web API fee estimator") + w.updateFeeTicker.Stop() - w.updateFeeTicker.Stop() + close(w.quit) + w.wg.Wait() - close(w.quit) - w.wg.Wait() - }) return nil } @@ -866,7 +897,19 @@ func (w *WebAPIEstimator) Stop() error { // // NOTE: This method is part of the Estimator interface. func (w *WebAPIEstimator) RelayFeePerKW() SatPerKWeight { - return FeePerKwFloor + if !w.started.Load() { + log.Error("WebAPIEstimator not started") + } + + // Get fee estimates now if we don't refresh periodically. + if w.noCache { + w.updateFeeEstimates() + } + + log.Infof("Web API returning %v for min relay feerate", + w.minRelayFeerate) + + return w.minRelayFeerate.FeePerKWeight() } // randomFeeUpdateTimeout returns a random timeout between minFeeUpdateTimeout @@ -956,14 +999,21 @@ func (w *WebAPIEstimator) getCachedFee(numBlocks uint32) (uint32, error) { func (w *WebAPIEstimator) updateFeeEstimates() { // Once we've obtained the response, we'll instruct the WebAPIFeeSource // to parse out the body to obtain our final result. - feesByBlockTarget, err := w.apiSource.GetFeeMap() + resp, err := w.apiSource.GetFeeInfo() if err != nil { log.Errorf("unable to get fee response: %v", err) return } + log.Debugf("Received response from source: %s", lnutils.NewLogClosure( + func() string { + resp, _ := json.Marshal(resp) + return string(resp) + })) + w.feesMtx.Lock() - w.feeByBlockTarget = feesByBlockTarget + w.feeByBlockTarget = resp.FeeByBlockTarget + w.minRelayFeerate = resp.MinRelayFeerate w.feesMtx.Unlock() } diff --git a/lnwallet/chainfee/estimator_test.go b/lnwallet/chainfee/estimator_test.go index 51ab5bf29..3d355d503 100644 --- a/lnwallet/chainfee/estimator_test.go +++ b/lnwallet/chainfee/estimator_test.go @@ -107,17 +107,20 @@ func TestSparseConfFeeSource(t *testing.T) { 2: 42, 3: 54321, } - testJSON := map[string]map[uint32]uint32{ - "fee_by_block_target": testFees, + testMinRelayFee := SatPerKVByte(1000) + testResp := WebAPIResponse{ + MinRelayFeerate: testMinRelayFee, + FeeByBlockTarget: testFees, } - jsonResp, err := json.Marshal(testJSON) + + jsonResp, err := json.Marshal(testResp) require.NoError(t, err, "unable to marshal JSON API response") reader := bytes.NewReader(jsonResp) // Finally, ensure the expected map is returned without error. - fees, err := feeSource.parseResponse(reader) + resp, err := feeSource.parseResponse(reader) require.NoError(t, err, "unable to parse API response") - require.Equal(t, testFees, fees, "unexpected fee map returned") + require.Equal(t, testResp, resp, "unexpected resp returned") // Test parsing an improperly formatted JSON API response. badFees := map[string]uint32{"hi": 12345, "hello": 42, "satoshi": 54321} @@ -131,6 +134,45 @@ func TestSparseConfFeeSource(t *testing.T) { require.Error(t, err, "expected error when parsing bad JSON") } +// TestFeeSourceCompatibility checks that when a fee source doesn't return a +// `min_relay_feerate` field in its response, the floor feerate is used. +// +// NOTE: Field `min_relay_feerate` was added in v0.18.3. +func TestFeeSourceCompatibility(t *testing.T) { + t.Parallel() + + // Test that GenQueryURL returns the URL as is. + url := "test" + feeSource := SparseConfFeeSource{URL: url} + + // Test parsing a properly formatted JSON API response. + // + // Create the resp without the `min_relay_feerate` field. + testFees := map[uint32]uint32{ + 1: 12345, + } + testResp := struct { + // FeeByBlockTarget is a map of confirmation targets to sat/kvb + // fees. + FeeByBlockTarget map[uint32]uint32 `json:"fee_by_block_target"` + }{ + FeeByBlockTarget: testFees, + } + + jsonResp, err := json.Marshal(testResp) + require.NoError(t, err, "unable to marshal JSON API response") + reader := bytes.NewReader(jsonResp) + + // Ensure the expected map is returned without error. + resp, err := feeSource.parseResponse(reader) + require.NoError(t, err, "unable to parse API response") + require.Equal(t, testResp.FeeByBlockTarget, resp.FeeByBlockTarget, + "unexpected resp returned") + + // Expect the floor feerate to be used. + require.Equal(t, FeePerKwFloor.FeePerKVByte(), resp.MinRelayFeerate) +} + // TestWebAPIFeeEstimator checks that the WebAPIFeeEstimator returns fee rates // as expected. func TestWebAPIFeeEstimator(t *testing.T) { @@ -194,25 +236,28 @@ func TestWebAPIFeeEstimator(t *testing.T) { // This will create a `feeByBlockTarget` map with the following values, // - 2: 4000 sat/kb // - 6: 2000 sat/kb. - feeRateResp := map[uint32]uint32{ + feeRates := map[uint32]uint32{ minTarget: maxFeeRate, maxTarget: minFeeRate, } + resp := WebAPIResponse{ + FeeByBlockTarget: feeRates, + } // Create a mock fee source and mock its returned map. feeSource := &mockFeeSource{} - feeSource.On("GetFeeMap").Return(feeRateResp, nil) + feeSource.On("GetFeeInfo").Return(resp, nil) estimator, _ := NewWebAPIEstimator( feeSource, false, minFeeUpdateTimeout, maxFeeUpdateTimeout, ) - // Test that requesting a fee when no fees have been cached won't fail. + // Test that when the estimator is not started, an error is returned. feeRate, err := estimator.EstimateFeePerKW(5) - require.NoErrorf(t, err, "expected no error") - require.Equalf(t, FeePerKwFloor, feeRate, "expected fee rate floor "+ - "returned when no cached fee rate found") + require.Error(t, err, "expected an error") + require.Zero(t, feeRate, "expected zero fee rate") + // Start the estimator. require.NoError(t, estimator.Start(), "unable to start fee estimator") for _, tc := range testCases { @@ -234,7 +279,7 @@ func TestWebAPIFeeEstimator(t *testing.T) { exp := SatPerKVByte(tc.expectedFeeRate).FeePerKWeight() require.Equalf(t, exp, est, "target %v failed, fee "+ - "map is %v", tc.target, feeRateResp) + "map is %v", tc.target, feeRate) }) } diff --git a/lnwallet/chainfee/mocks.go b/lnwallet/chainfee/mocks.go index e14340d91..3a6025005 100644 --- a/lnwallet/chainfee/mocks.go +++ b/lnwallet/chainfee/mocks.go @@ -12,10 +12,10 @@ type mockFeeSource struct { // WebAPIFeeSource interface. var _ WebAPIFeeSource = (*mockFeeSource)(nil) -func (m *mockFeeSource) GetFeeMap() (map[uint32]uint32, error) { +func (m *mockFeeSource) GetFeeInfo() (WebAPIResponse, error) { args := m.Called() - return args.Get(0).(map[uint32]uint32), args.Error(1) + return args.Get(0).(WebAPIResponse), args.Error(1) } // MockEstimator implements the `Estimator` interface and is used by diff --git a/lnwallet/chainfee/rates.go b/lnwallet/chainfee/rates.go index f5294e4d1..20f4f1e1d 100644 --- a/lnwallet/chainfee/rates.go +++ b/lnwallet/chainfee/rates.go @@ -53,7 +53,7 @@ func (s SatPerKVByte) FeePerKWeight() SatPerKWeight { // String returns a human-readable string of the fee rate. func (s SatPerKVByte) String() string { - return fmt.Sprintf("%v sat/kb", int64(s)) + return fmt.Sprintf("%v sat/kvb", int64(s)) } // SatPerKWeight represents a fee rate in sat/kw. diff --git a/lnwallet/chancloser/chancloser.go b/lnwallet/chancloser/chancloser.go index 47635c3af..3f5e730c0 100644 --- a/lnwallet/chancloser/chancloser.go +++ b/lnwallet/chancloser/chancloser.go @@ -15,6 +15,7 @@ import ( "github.com/lightningnetwork/lnd/htlcswitch" "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/labels" + "github.com/lightningnetwork/lnd/lnutils" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/lnwire" @@ -869,10 +870,7 @@ func (c *ChanCloser) ReceiveClosingSigned( //nolint:funlen // With the closing transaction crafted, we'll now broadcast it // to the network. chancloserLog.Infof("Broadcasting cooperative close tx: %v", - newLogClosure(func() string { - return spew.Sdump(closeTx) - }), - ) + lnutils.SpewLogClosure(closeTx)) // Create a close channel label. chanID := c.cfg.Channel.ShortChanID() diff --git a/lnwallet/chancloser/log.go b/lnwallet/chancloser/log.go index 967a1ec35..7189ed2a3 100644 --- a/lnwallet/chancloser/log.go +++ b/lnwallet/chancloser/log.go @@ -23,19 +23,3 @@ func DisableLog() { func UseLogger(logger btclog.Logger) { chancloserLog = logger } - -// logClosure is used to provide a closure over expensive logging operations -// so they aren't performed when the logging level doesn't warrant it. -type logClosure func() string - -// String invokes the underlying function and returns the result. -func (c logClosure) String() string { - return c() -} - -// newLogClosure returns a new closure over a function that returns a string -// which itself provides a Stringer interface so that it can be used with the -// logging system. -func newLogClosure(c func() string) logClosure { - return logClosure(c) -} diff --git a/lnwallet/channel.go b/lnwallet/channel.go index 0e0d762c1..b4ea2fee0 100644 --- a/lnwallet/channel.go +++ b/lnwallet/channel.go @@ -29,6 +29,7 @@ import ( "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lntypes" + "github.com/lightningnetwork/lnd/lnutils" "github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/shachain" @@ -1869,10 +1870,7 @@ func (lc *LightningChannel) restoreCommitState( lc.localCommitChain.addCommitment(localCommit) lc.log.Tracef("starting local commitment: %v", - newLogClosure(func() string { - return spew.Sdump(lc.localCommitChain.tail()) - }), - ) + lnutils.SpewLogClosure(lc.localCommitChain.tail())) // We'll also do the same for the remote commitment chain. remoteCommit, err := lc.diskCommitToMemCommit( @@ -1885,10 +1883,7 @@ func (lc *LightningChannel) restoreCommitState( lc.remoteCommitChain.addCommitment(remoteCommit) lc.log.Tracef("starting remote commitment: %v", - newLogClosure(func() string { - return spew.Sdump(lc.remoteCommitChain.tail()) - }), - ) + lnutils.SpewLogClosure(lc.remoteCommitChain.tail())) var ( pendingRemoteCommit *commitment @@ -1920,10 +1915,7 @@ func (lc *LightningChannel) restoreCommitState( lc.remoteCommitChain.addCommitment(pendingRemoteCommit) lc.log.Debugf("pending remote commitment: %v", - newLogClosure(func() string { - return spew.Sdump(lc.remoteCommitChain.tip()) - }), - ) + lnutils.SpewLogClosure(lc.remoteCommitChain.tip())) // We'll also re-create the set of commitment keys needed to // fully re-derive the state. @@ -3245,12 +3237,8 @@ func (lc *LightningChannel) fetchParent(entry *PaymentDescriptor, return nil, fmt.Errorf("unable to find parent entry "+ "%d in %v update log: %v\nUpdatelog: %v", entry.ParentIndex, logName, - newLogClosure(func() string { - return spew.Sdump(entry) - }), newLogClosure(func() string { - return spew.Sdump(updateLog) - }), - ) + lnutils.SpewLogClosure(entry), + lnutils.SpewLogClosure(updateLog)) // The parent add height should never be zero at this point. If // that's the case we probably forgot to send a new commitment. @@ -4249,10 +4237,7 @@ func (lc *LightningChannel) SignNextCommitment() (*NewCommitState, error) { "their_balance=%v, commit_tx: %v", newCommitView.ourBalance, newCommitView.theirBalance, - newLogClosure(func() string { - return spew.Sdump(newCommitView.txn) - }), - ) + lnutils.SpewLogClosure(newCommitView.txn)) // With the commitment view constructed, if there are any HTLC's, we'll // need to generate signatures of each of them for the remote party's @@ -5209,10 +5194,7 @@ func (lc *LightningChannel) ReceiveNewCommitment(commitSigs *CommitSigs) error { lc.log.Tracef("local chain: our_balance=%v, "+ "their_balance=%v, commit_tx: %v", localCommitmentView.ourBalance, localCommitmentView.theirBalance, - newLogClosure(func() string { - return spew.Sdump(localCommitmentView.txn) - }), - ) + lnutils.SpewLogClosure(localCommitmentView.txn)) // As an optimization, we'll generate a series of jobs for the worker // pool to verify each of the HTLC signatures presented. Once diff --git a/lnwallet/log.go b/lnwallet/log.go index 341edeca7..7c8ce5198 100644 --- a/lnwallet/log.go +++ b/lnwallet/log.go @@ -36,19 +36,3 @@ func UseLogger(logger btclog.Logger) { chain.UseLogger(logger) chainfee.UseLogger(logger) } - -// logClosure is used to provide a closure over expensive logging operations -// so don't have to be performed when the logging level doesn't warrant it. -type logClosure func() string - -// String invokes the underlying function and returns the result. -func (c logClosure) String() string { - return c() -} - -// newLogClosure returns a new closure over a function that returns a string -// which itself provides a Stringer interface so that it can be used with the -// logging system. -func newLogClosure(c func() string) logClosure { - return logClosure(c) -} diff --git a/log.go b/log.go index 1b170f5ea..9067a4a36 100644 --- a/log.go +++ b/log.go @@ -208,19 +208,3 @@ func SetSubLogger(root *build.RotatingLogWriter, subsystem string, useLogger(logger) } } - -// logClosure is used to provide a closure over expensive logging operations so -// don't have to be performed when the logging level doesn't warrant it. -type logClosure func() string - -// String invokes the underlying function and returns the result. -func (c logClosure) String() string { - return c() -} - -// newLogClosure returns a new closure over a function that returns a string -// which itself provides a Stringer interface so that it can be used with the -// logging system. -func newLogClosure(c func() string) logClosure { - return logClosure(c) -} diff --git a/peer/brontide.go b/peer/brontide.go index 769fe539f..fa2c8fde9 100644 --- a/peer/brontide.go +++ b/peer/brontide.go @@ -2156,7 +2156,7 @@ func (p *Brontide) logWireMessage(msg lnwire.Message, read bool) { summaryPrefix = "Sending" } - p.log.Debugf("%v", newLogClosure(func() string { + p.log.Debugf("%v", lnutils.NewLogClosure(func() string { // Debug summary of message. summary := messageSummary(msg) if len(summary) > 0 { @@ -2184,9 +2184,7 @@ func (p *Brontide) logWireMessage(msg lnwire.Message, read bool) { prefix = "writeMessage to peer" } - p.log.Tracef(prefix+": %v", newLogClosure(func() string { - return spew.Sdump(msg) - })) + p.log.Tracef(prefix+": %v", lnutils.SpewLogClosure(msg)) } // writeMessage writes and flushes the target lnwire.Message to the remote peer. diff --git a/peer/log.go b/peer/log.go index a1f9bda3e..f0d1a6672 100644 --- a/peer/log.go +++ b/peer/log.go @@ -22,19 +22,3 @@ func DisableLog() { func UseLogger(logger btclog.Logger) { peerLog = logger } - -// logClosure is used to provide a closure over expensive logging operations -// so they aren't performed when the logging level doesn't warrant it. -type logClosure func() string - -// String invokes the underlying function and returns the result. -func (c logClosure) String() string { - return c() -} - -// newLogClosure returns a new closure over a function that returns a string -// which itself provides a Stringer interface so that it can be used with the -// logging system. -func newLogClosure(c func() string) logClosure { - return logClosure(c) -} diff --git a/routing/log.go b/routing/log.go index e5c2e7a07..741ec084e 100644 --- a/routing/log.go +++ b/routing/log.go @@ -31,19 +31,3 @@ func UseLogger(logger btclog.Logger) { log = logger chainview.UseLogger(logger) } - -// logClosure is used to provide a closure over expensive logging operations so -// don't have to be performed when the logging level doesn't warrant it. -type logClosure func() string - -// String invokes the underlying function and returns the result. -func (c logClosure) String() string { - return c() -} - -// newLogClosure returns a new closure over a function that returns a string -// which itself provides a Stringer interface so that it can be used with the -// logging system. -func newLogClosure(c func() string) logClosure { - return logClosure(c) -} diff --git a/routing/pathfind.go b/routing/pathfind.go index 083af04db..a80826971 100644 --- a/routing/pathfind.go +++ b/routing/pathfind.go @@ -13,6 +13,7 @@ import ( "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb/models" "github.com/lightningnetwork/lnd/feature" + "github.com/lightningnetwork/lnd/lnutils" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/record" "github.com/lightningnetwork/lnd/routing/route" @@ -728,7 +729,7 @@ func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig, edge.capacity, ) - log.Trace(newLogClosure(func() string { + log.Trace(lnutils.NewLogClosure(func() string { return fmt.Sprintf("path finding probability: fromnode=%v,"+ " tonode=%v, amt=%v, cap=%v, probability=%v", fromVertex, toNodeDist.node, amountToSend, diff --git a/routing/payment_session.go b/routing/payment_session.go index a464bd93e..710318426 100644 --- a/routing/payment_session.go +++ b/routing/payment_session.go @@ -5,11 +5,11 @@ import ( "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btclog" - "github.com/davecgh/go-spew/spew" "github.com/lightningnetwork/lnd/build" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb/models" "github.com/lightningnetwork/lnd/graph" + "github.com/lightningnetwork/lnd/lnutils" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/routing/route" ) @@ -432,7 +432,7 @@ func (p *paymentSession) UpdateAdditionalEdge(msg *lnwire.ChannelUpdate, policy.FeeProportionalMillionths = lnwire.MilliSatoshi(msg.FeeRate) log.Debugf("New private channel update applied: %v", - newLogClosure(func() string { return spew.Sdump(msg) })) + lnutils.SpewLogClosure(msg)) return true } diff --git a/routing/router.go b/routing/router.go index 293f2c9fc..35db5a779 100644 --- a/routing/router.go +++ b/routing/router.go @@ -21,6 +21,7 @@ import ( "github.com/lightningnetwork/lnd/fn" "github.com/lightningnetwork/lnd/htlcswitch" "github.com/lightningnetwork/lnd/lntypes" + "github.com/lightningnetwork/lnd/lnutils" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/record" @@ -669,10 +670,7 @@ func (r *ChannelRouter) FindRoute(req *RouteRequest) (*route.Route, float64, } go log.Tracef("Obtained path to send %v to %x: %v", - req.Amount, req.Target, newLogClosure(func() string { - return spew.Sdump(route) - }), - ) + req.Amount, req.Target, lnutils.SpewLogClosure(route)) return route, probability, nil } @@ -704,7 +702,7 @@ func generateSphinxPacket(rt *route.Route, paymentHash []byte, } log.Tracef("Constructed per-hop payloads for payment_hash=%x: %v", - paymentHash[:], newLogClosure(func() string { + paymentHash, lnutils.NewLogClosure(func() string { path := make( []sphinx.OnionHop, sphinxPath.TrueRouteLength(), ) @@ -734,7 +732,7 @@ func generateSphinxPacket(rt *route.Route, paymentHash []byte, } log.Tracef("Generated sphinx packet: %v", - newLogClosure(func() string { + lnutils.NewLogClosure(func() string { // We make a copy of the ephemeral key and unset the // internal curve here in order to keep the logs from // getting noisy. @@ -945,8 +943,8 @@ func (r *ChannelRouter) SendPaymentAsync(ctx context.Context, // spewPayment returns a log closures that provides a spewed string // representation of the passed payment. -func spewPayment(payment *LightningPayment) logClosure { - return newLogClosure(func() string { +func spewPayment(payment *LightningPayment) lnutils.LogClosure { + return lnutils.NewLogClosure(func() string { // Make a copy of the payment with a nilled Curve // before spewing. var routeHints [][]zpay32.HopHint @@ -1090,11 +1088,8 @@ func (r *ChannelRouter) sendToRoute(htlcHash lntypes.Hash, rt *route.Route, return nil, err } - log.Tracef("Dispatching SendToRoute for HTLC hash %v: %v", - htlcHash, newLogClosure(func() string { - return spew.Sdump(rt) - }), - ) + log.Tracef("Dispatching SendToRoute for HTLC hash %v: %v", htlcHash, + lnutils.SpewLogClosure(rt)) // Since the HTLC hashes and preimages are specified manually over the // RPC for SendToRoute requests, we don't have to worry about creating diff --git a/rpcserver.go b/rpcserver.go index 465035ea5..ac10fc790 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -63,6 +63,7 @@ import ( "github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/walletrpc" "github.com/lightningnetwork/lnd/lntypes" + "github.com/lightningnetwork/lnd/lnutils" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet/btcwallet" "github.com/lightningnetwork/lnd/lnwallet/chainfee" @@ -5845,9 +5846,7 @@ func (r *rpcServer) LookupInvoice(ctx context.Context, } rpcsLog.Tracef("[lookupinvoice] located invoice %v", - newLogClosure(func() string { - return spew.Sdump(invoice) - })) + lnutils.SpewLogClosure(invoice)) rpcInvoice, err := invoicesrpc.CreateRPCInvoice( &invoice, r.cfg.ActiveNetParams.Params, diff --git a/sweep/fee_bumper.go b/sweep/fee_bumper.go index e79280166..452cc0dd8 100644 --- a/sweep/fee_bumper.go +++ b/sweep/fee_bumper.go @@ -12,7 +12,6 @@ import ( "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcwallet/chain" - "github.com/davecgh/go-spew/spew" "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/fn" "github.com/lightningnetwork/lnd/input" @@ -313,10 +312,8 @@ func (t *TxPublisher) isNeutrinoBackend() bool { // // NOTE: part of the Bumper interface. func (t *TxPublisher) Broadcast(req *BumpRequest) (<-chan *BumpResult, error) { - log.Tracef("Received broadcast request: %s", newLogClosure( - func() string { - return spew.Sdump(req) - })()) + log.Tracef("Received broadcast request: %s", lnutils.SpewLogClosure( + req)) // Attempt an initial broadcast which is guaranteed to comply with the // RBF rules. diff --git a/sweep/log.go b/sweep/log.go index 9bf48116d..172502375 100644 --- a/sweep/log.go +++ b/sweep/log.go @@ -27,19 +27,3 @@ func DisableLog() { func UseLogger(logger btclog.Logger) { log = logger } - -// logClosure is used to provide a closure over expensive logging operations so -// don't have to be performed when the logging level doesn't warrant it. -type logClosure func() string - -// String invokes the underlying function and returns the result. -func (c logClosure) String() string { - return c() -} - -// newLogClosure returns a new closure over a function that returns a string -// which itself provides a Stringer interface so that it can be used with the -// logging system. -func newLogClosure(c func() string) logClosure { - return logClosure(c) -} diff --git a/sweep/sweeper.go b/sweep/sweeper.go index 39a03228d..af2f0cec9 100644 --- a/sweep/sweeper.go +++ b/sweep/sweeper.go @@ -13,6 +13,7 @@ import ( "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/fn" "github.com/lightningnetwork/lnd/input" + "github.com/lightningnetwork/lnd/lnutils" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet/chainfee" ) @@ -1376,10 +1377,7 @@ func (s *UtxoSweeper) handleInputSpent(spend *chainntnfs.SpendDetail) { log.Debugf("Detected third party spend related to in flight "+ "inputs (is_ours=%v): %v", isOurTx, - newLogClosure(func() string { - return spew.Sdump(spend.SpendingTx) - }), - ) + lnutils.SpewLogClosure(spend.SpendingTx)) } // We now use the spending tx to update the state of the inputs. diff --git a/watchtower/wtdb/log.go b/watchtower/wtdb/log.go index ed453383f..fa0a64f6a 100644 --- a/watchtower/wtdb/log.go +++ b/watchtower/wtdb/log.go @@ -43,19 +43,3 @@ func UseLogger(logger btclog.Logger) { migration7.UseLogger(logger) migration8.UseLogger(logger) } - -// logClosure is used to provide a closure over expensive logging operations so -// don't have to be performed when the logging level doesn't warrant it. -type logClosure func() string // nolint:unused - -// String invokes the underlying function and returns the result. -func (c logClosure) String() string { - return c() -} - -// newLogClosure returns a new closure over a function that returns a string -// which itself provides a Stringer interface so that it can be used with the -// logging system. -func newLogClosure(c func() string) logClosure { // nolint:unused - return logClosure(c) -}