lnwallet+peer: extract close types to separate pkg
The aux close types will soon be used by a different package that would otherwise cause an import cycle if used directly from lnwallet/chancloser. We now create a new sub-package lnwallet/types that will be improrted from all users of these types.
This commit is contained in:
5 files changed
+106
-91
No files matched your search
@@ -1,78 +1,13 @@
|
|||||||
package chancloser
|
package chancloser
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/btcsuite/btcd/btcec/v2"
|
|
||||||
"github.com/btcsuite/btcd/btcutil"
|
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/lightningnetwork/lnd/fn/v2"
|
"github.com/lightningnetwork/lnd/fn/v2"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/types"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/tlv"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// CloseOutput represents an output that should be included in the close
|
|
||||||
// transaction.
|
|
||||||
type CloseOutput struct {
|
|
||||||
// Amt is the amount of the output.
|
|
||||||
Amt btcutil.Amount
|
|
||||||
|
|
||||||
// DustLimit is the dust limit for the local node.
|
|
||||||
DustLimit btcutil.Amount
|
|
||||||
|
|
||||||
// PkScript is the script that should be used to pay to the output.
|
|
||||||
PkScript []byte
|
|
||||||
|
|
||||||
// ShutdownRecords is the set of custom records that may result in
|
|
||||||
// extra close outputs being added.
|
|
||||||
ShutdownRecords lnwire.CustomRecords
|
|
||||||
}
|
|
||||||
|
|
||||||
// AuxShutdownReq is used to request a set of extra custom records to include
|
|
||||||
// in the shutdown message.
|
|
||||||
type AuxShutdownReq struct {
|
|
||||||
// ChanPoint is the channel point of the channel that is being shut
|
|
||||||
// down.
|
|
||||||
ChanPoint wire.OutPoint
|
|
||||||
|
|
||||||
// ShortChanID is the short channel ID of the channel that is being
|
|
||||||
// closed.
|
|
||||||
ShortChanID lnwire.ShortChannelID
|
|
||||||
|
|
||||||
// Initiator is true if the local node is the initiator of the channel.
|
|
||||||
Initiator bool
|
|
||||||
|
|
||||||
// InternalKey is the internal key for the shutdown addr. This will
|
|
||||||
// only be set for taproot shutdown addrs.
|
|
||||||
InternalKey fn.Option[btcec.PublicKey]
|
|
||||||
|
|
||||||
// CommitBlob is the blob that was included in the last commitment.
|
|
||||||
CommitBlob fn.Option[tlv.Blob]
|
|
||||||
|
|
||||||
// FundingBlob is the blob that was included in the funding state.
|
|
||||||
FundingBlob fn.Option[tlv.Blob]
|
|
||||||
}
|
|
||||||
|
|
||||||
// AuxCloseDesc is used to describe the channel close that is being performed.
|
|
||||||
type AuxCloseDesc struct {
|
|
||||||
AuxShutdownReq
|
|
||||||
|
|
||||||
// CloseFee is the closing fee to be paid for this state.
|
|
||||||
CloseFee btcutil.Amount
|
|
||||||
|
|
||||||
// CommitFee is the fee that was paid for the last commitment.
|
|
||||||
CommitFee btcutil.Amount
|
|
||||||
|
|
||||||
// LocalCloseOutput is the output that the local node should be paid
|
|
||||||
// to. This is None if the local party will not have an output on the
|
|
||||||
// co-op close transaction.
|
|
||||||
LocalCloseOutput fn.Option[CloseOutput]
|
|
||||||
|
|
||||||
// RemoteCloseOutput is the output that the remote node should be paid
|
|
||||||
// to. This will be None if the remote party will not have an output on
|
|
||||||
// the co-op close transaction.
|
|
||||||
RemoteCloseOutput fn.Option[CloseOutput]
|
|
||||||
}
|
|
||||||
|
|
||||||
// AuxCloseOutputs is used to specify extra outputs that should be used when
|
// AuxCloseOutputs is used to specify extra outputs that should be used when
|
||||||
// constructing the co-op close transaction.
|
// constructing the co-op close transaction.
|
||||||
type AuxCloseOutputs struct {
|
type AuxCloseOutputs struct {
|
||||||
@@ -91,14 +26,15 @@ type AuxCloseOutputs struct {
|
|||||||
type AuxChanCloser interface {
|
type AuxChanCloser interface {
|
||||||
// ShutdownBlob returns the set of custom records that should be
|
// ShutdownBlob returns the set of custom records that should be
|
||||||
// included in the shutdown message.
|
// included in the shutdown message.
|
||||||
ShutdownBlob(req AuxShutdownReq) (fn.Option[lnwire.CustomRecords],
|
ShutdownBlob(req types.AuxShutdownReq) (fn.Option[lnwire.CustomRecords],
|
||||||
error)
|
error)
|
||||||
|
|
||||||
// AuxCloseOutputs returns the set of custom outputs that should be used
|
// AuxCloseOutputs returns the set of custom outputs that should be used
|
||||||
// to construct the co-op close transaction.
|
// to construct the co-op close transaction.
|
||||||
AuxCloseOutputs(desc AuxCloseDesc) (fn.Option[AuxCloseOutputs], error)
|
AuxCloseOutputs(desc types.AuxCloseDesc) (fn.Option[AuxCloseOutputs],
|
||||||
|
error)
|
||||||
|
|
||||||
// FinalizeClose is called after the close transaction has been agreed
|
// FinalizeClose is called after the close transaction has been agreed
|
||||||
// upon.
|
// upon.
|
||||||
FinalizeClose(desc AuxCloseDesc, closeTx *wire.MsgTx) error
|
FinalizeClose(desc types.AuxCloseDesc, closeTx *wire.MsgTx) error
|
||||||
}
|
}
|
||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lnutils"
|
"github.com/lightningnetwork/lnd/lnutils"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/types"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -239,12 +240,12 @@ type ChanCloser struct {
|
|||||||
// localCloseOutput is the local output on the closing transaction that
|
// localCloseOutput is the local output on the closing transaction that
|
||||||
// the local party should be paid to. This will only be populated if the
|
// the local party should be paid to. This will only be populated if the
|
||||||
// local balance isn't dust.
|
// local balance isn't dust.
|
||||||
localCloseOutput fn.Option[CloseOutput]
|
localCloseOutput fn.Option[types.CloseOutput]
|
||||||
|
|
||||||
// remoteCloseOutput is the remote output on the closing transaction
|
// remoteCloseOutput is the remote output on the closing transaction
|
||||||
// that the remote party should be paid to. This will only be populated
|
// that the remote party should be paid to. This will only be populated
|
||||||
// if the remote balance isn't dust.
|
// if the remote balance isn't dust.
|
||||||
remoteCloseOutput fn.Option[CloseOutput]
|
remoteCloseOutput fn.Option[types.CloseOutput]
|
||||||
|
|
||||||
// auxOutputs are the optional additional outputs that might be added to
|
// auxOutputs are the optional additional outputs that might be added to
|
||||||
// the closing transaction.
|
// the closing transaction.
|
||||||
@@ -378,14 +379,17 @@ func (c *ChanCloser) initChanShutdown() (*lnwire.Shutdown, error) {
|
|||||||
// At this point, we'll check to see if we have any custom records to
|
// At this point, we'll check to see if we have any custom records to
|
||||||
// add to the shutdown message.
|
// add to the shutdown message.
|
||||||
err := fn.MapOptionZ(c.cfg.AuxCloser, func(a AuxChanCloser) error {
|
err := fn.MapOptionZ(c.cfg.AuxCloser, func(a AuxChanCloser) error {
|
||||||
shutdownCustomRecords, err := a.ShutdownBlob(AuxShutdownReq{
|
channel := c.cfg.Channel
|
||||||
ChanPoint: c.chanPoint,
|
shutdownCustomRecords, err := a.ShutdownBlob(
|
||||||
ShortChanID: c.cfg.Channel.ShortChanID(),
|
types.AuxShutdownReq{
|
||||||
Initiator: c.cfg.Channel.IsInitiator(),
|
ChanPoint: c.chanPoint,
|
||||||
InternalKey: c.localInternalKey,
|
ShortChanID: channel.ShortChanID(),
|
||||||
CommitBlob: c.cfg.Channel.LocalCommitmentBlob(),
|
Initiator: channel.IsInitiator(),
|
||||||
FundingBlob: c.cfg.Channel.FundingBlob(),
|
InternalKey: c.localInternalKey,
|
||||||
})
|
CommitBlob: channel.LocalCommitmentBlob(),
|
||||||
|
FundingBlob: channel.FundingBlob(),
|
||||||
|
},
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -442,7 +446,7 @@ func (c *ChanCloser) initChanShutdown() (*lnwire.Shutdown, error) {
|
|||||||
// it might still carry value in custom channel terms.
|
// it might still carry value in custom channel terms.
|
||||||
_, dustAmt := c.cfg.Channel.LocalBalanceDust()
|
_, dustAmt := c.cfg.Channel.LocalBalanceDust()
|
||||||
localBalance, _ := c.cfg.Channel.CommitBalances()
|
localBalance, _ := c.cfg.Channel.CommitBalances()
|
||||||
c.localCloseOutput = fn.Some(CloseOutput{
|
c.localCloseOutput = fn.Some(types.CloseOutput{
|
||||||
Amt: localBalance,
|
Amt: localBalance,
|
||||||
DustLimit: dustAmt,
|
DustLimit: dustAmt,
|
||||||
PkScript: c.localDeliveryScript,
|
PkScript: c.localDeliveryScript,
|
||||||
@@ -519,12 +523,12 @@ func (c *ChanCloser) NegotiationHeight() uint32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LocalCloseOutput returns the local close output.
|
// LocalCloseOutput returns the local close output.
|
||||||
func (c *ChanCloser) LocalCloseOutput() fn.Option[CloseOutput] {
|
func (c *ChanCloser) LocalCloseOutput() fn.Option[types.CloseOutput] {
|
||||||
return c.localCloseOutput
|
return c.localCloseOutput
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoteCloseOutput returns the remote close output.
|
// RemoteCloseOutput returns the remote close output.
|
||||||
func (c *ChanCloser) RemoteCloseOutput() fn.Option[CloseOutput] {
|
func (c *ChanCloser) RemoteCloseOutput() fn.Option[types.CloseOutput] {
|
||||||
return c.remoteCloseOutput
|
return c.remoteCloseOutput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -590,7 +594,7 @@ func (c *ChanCloser) ReceiveShutdown(msg lnwire.Shutdown) (
|
|||||||
// terms, it might still carry value in custom channel terms.
|
// terms, it might still carry value in custom channel terms.
|
||||||
_, dustAmt := c.cfg.Channel.RemoteBalanceDust()
|
_, dustAmt := c.cfg.Channel.RemoteBalanceDust()
|
||||||
_, remoteBalance := c.cfg.Channel.CommitBalances()
|
_, remoteBalance := c.cfg.Channel.CommitBalances()
|
||||||
c.remoteCloseOutput = fn.Some(CloseOutput{
|
c.remoteCloseOutput = fn.Some(types.CloseOutput{
|
||||||
Amt: remoteBalance,
|
Amt: remoteBalance,
|
||||||
DustLimit: dustAmt,
|
DustLimit: dustAmt,
|
||||||
PkScript: msg.Address,
|
PkScript: msg.Address,
|
||||||
@@ -976,7 +980,7 @@ func (c *ChanCloser) ReceiveClosingSigned( //nolint:funlen
|
|||||||
c.cfg.AuxCloser, func(aux AuxChanCloser) error {
|
c.cfg.AuxCloser, func(aux AuxChanCloser) error {
|
||||||
channel := c.cfg.Channel
|
channel := c.cfg.Channel
|
||||||
//nolint:ll
|
//nolint:ll
|
||||||
req := AuxShutdownReq{
|
req := types.AuxShutdownReq{
|
||||||
ChanPoint: c.chanPoint,
|
ChanPoint: c.chanPoint,
|
||||||
ShortChanID: c.cfg.Channel.ShortChanID(),
|
ShortChanID: c.cfg.Channel.ShortChanID(),
|
||||||
InternalKey: c.localInternalKey,
|
InternalKey: c.localInternalKey,
|
||||||
@@ -984,7 +988,7 @@ func (c *ChanCloser) ReceiveClosingSigned( //nolint:funlen
|
|||||||
CommitBlob: channel.LocalCommitmentBlob(),
|
CommitBlob: channel.LocalCommitmentBlob(),
|
||||||
FundingBlob: channel.FundingBlob(),
|
FundingBlob: channel.FundingBlob(),
|
||||||
}
|
}
|
||||||
desc := AuxCloseDesc{
|
desc := types.AuxCloseDesc{
|
||||||
AuxShutdownReq: req,
|
AuxShutdownReq: req,
|
||||||
LocalCloseOutput: c.localCloseOutput,
|
LocalCloseOutput: c.localCloseOutput,
|
||||||
RemoteCloseOutput: c.remoteCloseOutput,
|
RemoteCloseOutput: c.remoteCloseOutput,
|
||||||
@@ -1053,7 +1057,7 @@ func (c *ChanCloser) auxCloseOutputs(
|
|||||||
|
|
||||||
var closeOuts fn.Option[AuxCloseOutputs]
|
var closeOuts fn.Option[AuxCloseOutputs]
|
||||||
err := fn.MapOptionZ(c.cfg.AuxCloser, func(aux AuxChanCloser) error {
|
err := fn.MapOptionZ(c.cfg.AuxCloser, func(aux AuxChanCloser) error {
|
||||||
req := AuxShutdownReq{
|
req := types.AuxShutdownReq{
|
||||||
ChanPoint: c.chanPoint,
|
ChanPoint: c.chanPoint,
|
||||||
ShortChanID: c.cfg.Channel.ShortChanID(),
|
ShortChanID: c.cfg.Channel.ShortChanID(),
|
||||||
InternalKey: c.localInternalKey,
|
InternalKey: c.localInternalKey,
|
||||||
@@ -1061,7 +1065,7 @@ func (c *ChanCloser) auxCloseOutputs(
|
|||||||
CommitBlob: c.cfg.Channel.LocalCommitmentBlob(),
|
CommitBlob: c.cfg.Channel.LocalCommitmentBlob(),
|
||||||
FundingBlob: c.cfg.Channel.FundingBlob(),
|
FundingBlob: c.cfg.Channel.FundingBlob(),
|
||||||
}
|
}
|
||||||
outs, err := aux.AuxCloseOutputs(AuxCloseDesc{
|
outs, err := aux.AuxCloseOutputs(types.AuxCloseDesc{
|
||||||
AuxShutdownReq: req,
|
AuxShutdownReq: req,
|
||||||
CloseFee: closeFee,
|
CloseFee: closeFee,
|
||||||
CommitFee: c.cfg.Channel.CommitFee(),
|
CommitFee: c.cfg.Channel.CommitFee(),
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/btcsuite/btcd/btcec/v2"
|
||||||
|
"github.com/btcsuite/btcd/btcutil"
|
||||||
|
"github.com/btcsuite/btcd/wire"
|
||||||
|
"github.com/lightningnetwork/lnd/fn/v2"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
|
"github.com/lightningnetwork/lnd/tlv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CloseOutput represents an output that should be included in the close
|
||||||
|
// transaction.
|
||||||
|
type CloseOutput struct {
|
||||||
|
// Amt is the amount of the output.
|
||||||
|
Amt btcutil.Amount
|
||||||
|
|
||||||
|
// DustLimit is the dust limit for the local node.
|
||||||
|
DustLimit btcutil.Amount
|
||||||
|
|
||||||
|
// PkScript is the script that should be used to pay to the output.
|
||||||
|
PkScript []byte
|
||||||
|
|
||||||
|
// ShutdownRecords is the set of custom records that may result in
|
||||||
|
// extra close outputs being added.
|
||||||
|
ShutdownRecords lnwire.CustomRecords
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuxShutdownReq is used to request a set of extra custom records to include
|
||||||
|
// in the shutdown message.
|
||||||
|
type AuxShutdownReq struct {
|
||||||
|
// ChanPoint is the channel point of the channel that is being shut
|
||||||
|
// down.
|
||||||
|
ChanPoint wire.OutPoint
|
||||||
|
|
||||||
|
// ShortChanID is the short channel ID of the channel that is being
|
||||||
|
// closed.
|
||||||
|
ShortChanID lnwire.ShortChannelID
|
||||||
|
|
||||||
|
// Initiator is true if the local node is the initiator of the channel.
|
||||||
|
Initiator bool
|
||||||
|
|
||||||
|
// InternalKey is the internal key for the shutdown addr. This will
|
||||||
|
// only be set for taproot shutdown addrs.
|
||||||
|
InternalKey fn.Option[btcec.PublicKey]
|
||||||
|
|
||||||
|
// CommitBlob is the blob that was included in the last commitment.
|
||||||
|
CommitBlob fn.Option[tlv.Blob]
|
||||||
|
|
||||||
|
// FundingBlob is the blob that was included in the funding state.
|
||||||
|
FundingBlob fn.Option[tlv.Blob]
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuxCloseDesc is used to describe the channel close that is being performed.
|
||||||
|
type AuxCloseDesc struct {
|
||||||
|
AuxShutdownReq
|
||||||
|
|
||||||
|
// CloseFee is the closing fee to be paid for this state.
|
||||||
|
CloseFee btcutil.Amount
|
||||||
|
|
||||||
|
// CommitFee is the fee that was paid for the last commitment.
|
||||||
|
CommitFee btcutil.Amount
|
||||||
|
|
||||||
|
// LocalCloseOutput is the output that the local node should be paid
|
||||||
|
// to. This is None if the local party will not have an output on the
|
||||||
|
// co-op close transaction.
|
||||||
|
LocalCloseOutput fn.Option[CloseOutput]
|
||||||
|
|
||||||
|
// RemoteCloseOutput is the output that the remote node should be paid
|
||||||
|
// to. This will be None if the remote party will not have an output on
|
||||||
|
// the co-op close transaction.
|
||||||
|
RemoteCloseOutput fn.Option[CloseOutput]
|
||||||
|
}
|
||||||
+3
-2
@@ -44,6 +44,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet/chancloser"
|
"github.com/lightningnetwork/lnd/lnwallet/chancloser"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/types"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/msgmux"
|
"github.com/lightningnetwork/lnd/msgmux"
|
||||||
"github.com/lightningnetwork/lnd/netann"
|
"github.com/lightningnetwork/lnd/netann"
|
||||||
@@ -169,12 +170,12 @@ type ChannelCloseUpdate struct {
|
|||||||
// LocalCloseOutput is an optional, additional output on the closing
|
// LocalCloseOutput is an optional, additional output on the closing
|
||||||
// transaction that the local party should be paid to. This will only be
|
// transaction that the local party should be paid to. This will only be
|
||||||
// populated if the local balance isn't dust.
|
// populated if the local balance isn't dust.
|
||||||
LocalCloseOutput fn.Option[chancloser.CloseOutput]
|
LocalCloseOutput fn.Option[types.CloseOutput]
|
||||||
|
|
||||||
// RemoteCloseOutput is an optional, additional output on the closing
|
// RemoteCloseOutput is an optional, additional output on the closing
|
||||||
// transaction that the remote party should be paid to. This will only
|
// transaction that the remote party should be paid to. This will only
|
||||||
// be populated if the remote balance isn't dust.
|
// be populated if the remote balance isn't dust.
|
||||||
RemoteCloseOutput fn.Option[chancloser.CloseOutput]
|
RemoteCloseOutput fn.Option[types.CloseOutput]
|
||||||
|
|
||||||
// AuxOutputs is an optional set of additional outputs that might be
|
// AuxOutputs is an optional set of additional outputs that might be
|
||||||
// included in the closing transaction. These are used for custom
|
// included in the closing transaction. These are used for custom
|
||||||
|
|||||||
+3
-2
@@ -69,6 +69,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet/chancloser"
|
"github.com/lightningnetwork/lnd/lnwallet/chancloser"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet/chanfunding"
|
"github.com/lightningnetwork/lnd/lnwallet/chanfunding"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/types"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/macaroons"
|
"github.com/lightningnetwork/lnd/macaroons"
|
||||||
"github.com/lightningnetwork/lnd/onionmessage"
|
"github.com/lightningnetwork/lnd/onionmessage"
|
||||||
@@ -3060,7 +3061,7 @@ func createRPCCloseUpdate(
|
|||||||
|
|
||||||
err := fn.MapOptionZ(
|
err := fn.MapOptionZ(
|
||||||
u.LocalCloseOutput,
|
u.LocalCloseOutput,
|
||||||
func(closeOut chancloser.CloseOutput) error {
|
func(closeOut types.CloseOutput) error {
|
||||||
cr, err := closeOut.ShutdownRecords.Serialize()
|
cr, err := closeOut.ShutdownRecords.Serialize()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error serializing "+
|
return fmt.Errorf("error serializing "+
|
||||||
@@ -3085,7 +3086,7 @@ func createRPCCloseUpdate(
|
|||||||
|
|
||||||
err = fn.MapOptionZ(
|
err = fn.MapOptionZ(
|
||||||
u.RemoteCloseOutput,
|
u.RemoteCloseOutput,
|
||||||
func(closeOut chancloser.CloseOutput) error {
|
func(closeOut types.CloseOutput) error {
|
||||||
cr, err := closeOut.ShutdownRecords.Serialize()
|
cr, err := closeOut.ShutdownRecords.Serialize()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error serializing "+
|
return fmt.Errorf("error serializing "+
|
||||||
|
|||||||
Reference in new issue
Block a user