From 908d82acdb06adc871e54dd14843249915f24406 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Wed, 6 Mar 2019 18:22:46 -0800 Subject: [PATCH] loop: extract code from client package into new loop primary package --- client/client.go => client.go | 25 ++++--- client/log.go | 24 ------- client/utils.go | 20 ------ client/client_test.go => client_test.go | 2 +- client/config.go => config.go | 2 +- client/executor.go => executor.go | 6 +- client/interface.go => interface.go | 69 +++--------------- lndclient/chainnotifier_client.go | 6 +- lndclient/lnd_services.go | 4 +- lndclient/signer_client.go | 4 +- lndclient/walletkit_client.go | 6 +- log.go | 70 +++++++++++++++++++ ...server_mock_test.go => server_mock_test.go | 2 +- .../store_mock_test.go => store_mock_test.go | 2 +- client/swap.go => swap.go | 2 +- ..._server_client.go => swap_server_client.go | 2 +- test/lightning_client_mock.go | 4 +- ...testcontext_test.go => testcontext_test.go | 11 +-- client/uncharge.go => uncharge.go | 9 ++- uncharge_state.go | 1 + client/uncharge_test.go => uncharge_test.go | 2 +- 21 files changed, 126 insertions(+), 147 deletions(-) rename client/client.go => client.go (94%) delete mode 100644 client/log.go delete mode 100644 client/utils.go rename client/client_test.go => client_test.go (99%) rename client/config.go => config.go (95%) rename client/executor.go => executor.go (98%) rename client/interface.go => interface.go (77%) create mode 100644 log.go rename client/server_mock_test.go => server_mock_test.go (99%) rename client/store_mock_test.go => store_mock_test.go (99%) rename client/swap.go => swap.go (99%) rename client/swap_server_client.go => swap_server_client.go (99%) rename client/testcontext_test.go => testcontext_test.go (95%) rename client/uncharge.go => uncharge.go (99%) create mode 100644 uncharge_state.go rename client/uncharge_test.go => uncharge_test.go (99%) diff --git a/client/client.go b/client.go similarity index 94% rename from client/client.go rename to client.go index 359650b..dc11b9b 100644 --- a/client/client.go +++ b/client.go @@ -1,4 +1,4 @@ -package client +package loop import ( "context" @@ -46,8 +46,8 @@ var ( republishDelay = 10 * time.Second ) -// Client performs the client side part of swaps. This interface exists to -// be able to implement a stub. +// Client performs the client side part of swaps. This interface exists to be +// able to implement a stub. type Client struct { started uint32 // To be used atomically. errChan chan error @@ -118,9 +118,9 @@ func (s *Client) GetUnchargeSwaps() ([]*PersistentUncharge, error) { } // Run is a blocking call that executes all swaps. Any pending swaps are -// restored from persistent storage and resumed. Subsequent updates -// will be sent through the passed in statusChan. The function can be -// terminated by cancelling the context. +// restored from persistent storage and resumed. Subsequent updates will be +// sent through the passed in statusChan. The function can be terminated by +// cancelling the context. func (s *Client) Run(ctx context.Context, statusChan chan<- SwapInfo) error { @@ -213,11 +213,10 @@ func (s *Client) resumeSwaps(ctx context.Context, } } -// Uncharge initiates a uncharge swap. It blocks until the swap is -// initiation with the swap server is completed (typically this takes -// only a short amount of time). From there on further status -// information can be acquired through the status channel returned from -// the Run call. +// Uncharge initiates a uncharge swap. It blocks until the swap is initiation +// with the swap server is completed (typically this takes only a short amount +// of time). From there on further status information can be acquired through +// the status channel returned from the Run call. // // When the call returns, the swap has been persisted and will be // resumed automatically after restarts. @@ -258,8 +257,8 @@ func (s *Client) Uncharge(globalCtx context.Context, } // UnchargeQuote takes a Uncharge amount and returns a break down of estimated -// costs for the client. Both the swap server and the on-chain fee estimator are -// queried to get to build the quote response. +// costs for the client. Both the swap server and the on-chain fee estimator +// are queried to get to build the quote response. func (s *Client) UnchargeQuote(ctx context.Context, request *UnchargeQuoteRequest) (*UnchargeQuote, error) { diff --git a/client/log.go b/client/log.go deleted file mode 100644 index d510225..0000000 --- a/client/log.go +++ /dev/null @@ -1,24 +0,0 @@ -package client - -import ( - "github.com/btcsuite/btclog" - "os" -) - -// log is a logger that is initialized with no output filters. This -// means the package will not perform any logging by default until the caller -// requests it. -var ( - backendLog = btclog.NewBackend(logWriter{}) - logger = backendLog.Logger("CLIENT") - servicesLogger = backendLog.Logger("SERVICES") -) - -// logWriter implements an io.Writer that outputs to both standard output and -// the write-end pipe of an initialized log rotator. -type logWriter struct{} - -func (logWriter) Write(p []byte) (n int, err error) { - os.Stdout.Write(p) - return len(p), nil -} diff --git a/client/utils.go b/client/utils.go deleted file mode 100644 index 8937bc8..0000000 --- a/client/utils.go +++ /dev/null @@ -1,20 +0,0 @@ -package client - -import ( - "errors" - - "github.com/btcsuite/btcd/wire" -) - -// getTxInputByOutpoint returns a tx input based on a given input outpoint. -func getTxInputByOutpoint(tx *wire.MsgTx, input *wire.OutPoint) ( - *wire.TxIn, error) { - - for _, in := range tx.TxIn { - if in.PreviousOutPoint == *input { - return in, nil - } - } - - return nil, errors.New("input not found") -} diff --git a/client/client_test.go b/client_test.go similarity index 99% rename from client/client_test.go rename to client_test.go index 31d2d04..6600b03 100644 --- a/client/client_test.go +++ b/client_test.go @@ -1,4 +1,4 @@ -package client +package loop import ( "bytes" diff --git a/client/config.go b/config.go similarity index 95% rename from client/config.go rename to config.go index 2d3b017..1f4086a 100644 --- a/client/config.go +++ b/config.go @@ -1,4 +1,4 @@ -package client +package loop import ( "time" diff --git a/client/executor.go b/executor.go similarity index 98% rename from client/executor.go rename to executor.go index c6a4931..6116d10 100644 --- a/client/executor.go +++ b/executor.go @@ -1,4 +1,4 @@ -package client +package loop import ( "context" @@ -21,6 +21,8 @@ type executorConfig struct { } // executor is responsible for executing swaps. +// +// TODO(roasbeef): rename to SubSwapper type executor struct { wg sync.WaitGroup newSwaps chan genericSwap @@ -91,6 +93,7 @@ func (s *executor) run(mainCtx context.Context, nextSwapID := 0 for { select { + case newSwap := <-s.newSwaps: queue := queue.NewConcurrentQueue(10) queue.Start() @@ -115,6 +118,7 @@ func (s *executor) run(mainCtx context.Context, }() nextSwapID++ + case doneID := <-swapDoneChan: queue, ok := blockEpochQueues[doneID] if !ok { diff --git a/client/interface.go b/interface.go similarity index 77% rename from client/interface.go rename to interface.go index f8d15fa..bed2e5c 100644 --- a/client/interface.go +++ b/interface.go @@ -1,4 +1,4 @@ -package client +package loop import ( "time" @@ -29,9 +29,9 @@ type UnchargeRequest struct { MaxPrepayRoutingFee btcutil.Amount // MaxSwapFee is the maximum we are willing to pay the server for the - // swap. This value is not disclosed in the swap initiation call, but if - // the server asks for a higher fee, we abort the swap. Typically this - // value is taken from the response of the UnchargeQuote call. It + // swap. This value is not disclosed in the swap initiation call, but + // if the server asks for a higher fee, we abort the swap. Typically + // this value is taken from the response of the UnchargeQuote call. It // includes the prepay amount. MaxSwapFee btcutil.Amount @@ -66,28 +66,6 @@ type UnchargeRequest struct { UnchargeChannel *uint64 } -// UnchargeContract contains the data that is serialized to persistent storage for -// pending swaps. -type UnchargeContract struct { - SwapContract - - DestAddr btcutil.Address - - SwapInvoice string - - // MaxSwapRoutingFee is the maximum off-chain fee in msat that may be - // paid for the swap payment to the server. - MaxSwapRoutingFee btcutil.Amount - - // SweepConfTarget specifies the targeted confirmation target for the - // client sweep tx. - SweepConfTarget int32 - - // UnchargeChannel is the channel to uncharge. If zero, any channel may - // be used. - UnchargeChannel *uint64 -} - // UnchargeSwapInfo contains status information for a uncharge swap. type UnchargeSwapInfo struct { UnchargeContract @@ -152,7 +130,8 @@ type UnchargeTerms struct { // SwapFeeRate is the variable fee in parts per million. SwapFeeRate int64 - // PrepayAmt is the fixed part of the swap fee that needs to be prepaid. + // PrepayAmt is the fixed part of the swap fee that needs to be + // prepaid. PrepayAmt btcutil.Amount // MinSwapAmount is the minimum amount that the server requires for a @@ -172,42 +151,10 @@ type UnchargeTerms struct { SwapPaymentDest [33]byte } -// SwapContract contains the base data that is serialized to persistent storage -// for pending swaps. -type SwapContract struct { - Preimage lntypes.Preimage - AmountRequested btcutil.Amount - - PrepayInvoice string - - SenderKey [33]byte - ReceiverKey [33]byte - - CltvExpiry int32 - - // MaxPrepayRoutingFee is the maximum off-chain fee in msat that may be - // paid for the prepayment to the server. - MaxPrepayRoutingFee btcutil.Amount - - // MaxSwapFee is the maximum we are willing to pay the server for the - // swap. - MaxSwapFee btcutil.Amount - - // MaxMinerFee is the maximum in on-chain fees that we are willing to - // spend. - MaxMinerFee btcutil.Amount - - // InitiationHeight is the block height at which the swap was initiated. - InitiationHeight int32 - - // InitiationTime is the time at which the swap was initiated. - InitiationTime time.Time -} - // SwapInfoKit contains common swap info fields. type SwapInfoKit struct { - // Hash is the sha256 hash of the preimage that unlocks the htlcs. It is - // used to uniquely identify this swap. + // Hash is the sha256 hash of the preimage that unlocks the htlcs. It + // is used to uniquely identify this swap. Hash lntypes.Hash // LastUpdateTime is the time of the last update of this swap. diff --git a/lndclient/chainnotifier_client.go b/lndclient/chainnotifier_client.go index 7170fba..12e727e 100644 --- a/lndclient/chainnotifier_client.go +++ b/lndclient/chainnotifier_client.go @@ -7,7 +7,7 @@ import ( "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" - "github.com/lightninglabs/loop/utils" + "github.com/lightninglabs/loop/swap" "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/lnrpc/chainrpc" "google.golang.org/grpc" @@ -77,7 +77,7 @@ func (s *chainNotifierClient) RegisterSpendNtfn(ctx context.Context, if err != nil { return err } - tx, err := utils.DecodeTx(d.RawSpendingTx) + tx, err := swap.DecodeTx(d.RawSpendingTx) if err != nil { return err } @@ -165,7 +165,7 @@ func (s *chainNotifierClient) RegisterConfirmationsNtfn(ctx context.Context, // Script confirmed case *chainrpc.ConfEvent_Conf: - tx, err := utils.DecodeTx(c.Conf.RawTx) + tx, err := swap.DecodeTx(c.Conf.RawTx) if err != nil { errChan <- err return diff --git a/lndclient/lnd_services.go b/lndclient/lnd_services.go index f15591e..ab40949 100644 --- a/lndclient/lnd_services.go +++ b/lndclient/lnd_services.go @@ -4,13 +4,13 @@ import ( "context" "errors" "fmt" - "github.com/lightninglabs/loop/utils" "io/ioutil" "path/filepath" "time" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcutil" + "github.com/lightninglabs/loop/swap" "github.com/lightningnetwork/lnd/lncfg" "github.com/lightningnetwork/lnd/macaroons" "google.golang.org/grpc" @@ -53,7 +53,7 @@ func NewLndServices(lndAddress string, application string, logger.Infof("Connected to lnd") - chainParams, err := utils.ChainParamsFromNetwork(network) + chainParams, err := swap.ChainParamsFromNetwork(network) if err != nil { return nil, err } diff --git a/lndclient/signer_client.go b/lndclient/signer_client.go index 5e7b5eb..e9397ba 100644 --- a/lndclient/signer_client.go +++ b/lndclient/signer_client.go @@ -4,7 +4,7 @@ import ( "context" "github.com/btcsuite/btcd/wire" - "github.com/lightninglabs/loop/utils" + "github.com/lightninglabs/loop/swap" "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/lnrpc/signrpc" "google.golang.org/grpc" @@ -29,7 +29,7 @@ func newSignerClient(conn *grpc.ClientConn) *signerClient { func (s *signerClient) SignOutputRaw(ctx context.Context, tx *wire.MsgTx, signDescriptors []*input.SignDescriptor) ([][]byte, error) { - txRaw, err := utils.EncodeTx(tx) + txRaw, err := swap.EncodeTx(tx) if err != nil { return nil, err } diff --git a/lndclient/walletkit_client.go b/lndclient/walletkit_client.go index ba506c8..a477978 100644 --- a/lndclient/walletkit_client.go +++ b/lndclient/walletkit_client.go @@ -6,7 +6,7 @@ import ( "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" - "github.com/lightninglabs/loop/utils" + "github.com/lightninglabs/loop/swap" "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lnrpc/signrpc" "github.com/lightningnetwork/lnd/lnrpc/walletrpc" @@ -117,7 +117,7 @@ func (m *walletKitClient) NextAddr(ctx context.Context) ( func (m *walletKitClient) PublishTransaction(ctx context.Context, tx *wire.MsgTx) error { - txHex, err := utils.EncodeTx(tx) + txHex, err := swap.EncodeTx(tx) if err != nil { return err } @@ -155,7 +155,7 @@ func (m *walletKitClient) SendOutputs(ctx context.Context, return nil, err } - tx, err := utils.DecodeTx(resp.RawTx) + tx, err := swap.DecodeTx(resp.RawTx) if err != nil { return nil, err } diff --git a/log.go b/log.go new file mode 100644 index 0000000..3423dd5 --- /dev/null +++ b/log.go @@ -0,0 +1,70 @@ +package loop + +import ( + "fmt" + "os" + + "github.com/btcsuite/btclog" + "github.com/lightningnetwork/lnd/lntypes" +) + +// log is a logger that is initialized with no output filters. This +// means the package will not perform any logging by default until the caller +// requests it. +var ( + backendLog = btclog.NewBackend(logWriter{}) + logger = backendLog.Logger("CLIENT") + servicesLogger = backendLog.Logger("SERVICES") +) + +// logWriter implements an io.Writer that outputs to both standard output and +// the write-end pipe of an initialized log rotator. +type logWriter struct{} + +func (logWriter) Write(p []byte) (n int, err error) { + os.Stdout.Write(p) + return len(p), nil +} + +// SwapLog logs with a short swap hash prefix. +type SwapLog struct { + // Logger is the underlying based logger. + Logger btclog.Logger + + // Hash is the hash the identifies the target swap. + Hash lntypes.Hash +} + +// Infof formats message according to format specifier and writes to +// log with LevelInfo. +func (s *SwapLog) Infof(format string, params ...interface{}) { + s.Logger.Infof( + fmt.Sprintf("%v %s", ShortHash(&s.Hash), format), + params..., + ) +} + +// Warnf formats message according to format specifier and writes to +// to log with LevelError. +func (s *SwapLog) Warnf(format string, params ...interface{}) { + s.Logger.Warnf( + fmt.Sprintf("%v %s", ShortHash(&s.Hash), format), + params..., + ) +} + +// Errorf formats message according to format specifier and writes to +// to log with LevelError. +func (s *SwapLog) Errorf(format string, params ...interface{}) { + s.Logger.Errorf( + fmt.Sprintf("%v %s", ShortHash(&s.Hash), format), + params..., + ) + +} + +// ShortHash returns a shortened version of the hash suitable for use in +// logging. +func ShortHash(hash *lntypes.Hash) string { + return hash.String()[:6] +} diff --git a/client/server_mock_test.go b/server_mock_test.go similarity index 99% rename from client/server_mock_test.go rename to server_mock_test.go index eab38eb..28494bd 100644 --- a/client/server_mock_test.go +++ b/server_mock_test.go @@ -1,4 +1,4 @@ -package client +package loop import ( "context" diff --git a/client/store_mock_test.go b/store_mock_test.go similarity index 99% rename from client/store_mock_test.go rename to store_mock_test.go index 6c462a0..e492aa4 100644 --- a/client/store_mock_test.go +++ b/store_mock_test.go @@ -1,4 +1,4 @@ -package client +package loop import ( "errors" diff --git a/client/swap.go b/swap.go similarity index 99% rename from client/swap.go rename to swap.go index 63b098b..3b447bd 100644 --- a/client/swap.go +++ b/swap.go @@ -1,4 +1,4 @@ -package client +package loop import ( "context" diff --git a/client/swap_server_client.go b/swap_server_client.go similarity index 99% rename from client/swap_server_client.go rename to swap_server_client.go index 0e695f0..b005231 100644 --- a/client/swap_server_client.go +++ b/swap_server_client.go @@ -1,4 +1,4 @@ -package client +package loop import ( "context" diff --git a/test/lightning_client_mock.go b/test/lightning_client_mock.go index 2d2ea83..e90a0f5 100644 --- a/test/lightning_client_mock.go +++ b/test/lightning_client_mock.go @@ -9,7 +9,7 @@ import ( "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcutil" "github.com/lightninglabs/loop/lndclient" - "github.com/lightninglabs/loop/utils" + "github.com/lightninglabs/loop/swap" "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc" "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lnwire" @@ -34,7 +34,7 @@ func (h *mockLightningClient) PayInvoice(ctx context.Context, invoice string, go func() { defer h.wg.Done() - amt, err := utils.GetInvoiceAmt(&chaincfg.TestNet3Params, invoice) + amt, err := swap.GetInvoiceAmt(&chaincfg.TestNet3Params, invoice) if err != nil { select { case done <- lndclient.PaymentResult{ diff --git a/client/testcontext_test.go b/testcontext_test.go similarity index 95% rename from client/testcontext_test.go rename to testcontext_test.go index d13260a..45e95d2 100644 --- a/client/testcontext_test.go +++ b/testcontext_test.go @@ -1,4 +1,4 @@ -package client +package loop import ( "context" @@ -139,8 +139,9 @@ func (ctx *testContext) finish() { ctx.assertIsDone() } -// notifyHeight notifies swap client of the arrival of a new block and waits for -// the notification to be processed by selecting on a dedicated test channel. +// notifyHeight notifies swap client of the arrival of a new block and +// waits for the notification to be processed by selecting on a dedicated +// test channel. func (ctx *testContext) notifyHeight(height int32) { ctx.T.Helper() @@ -205,7 +206,9 @@ func (ctx *testContext) assertStatus(expectedState SwapState) { } } -func (ctx *testContext) publishHtlc(script []byte, amt btcutil.Amount) wire.OutPoint { +func (ctx *testContext) publishHtlc(script []byte, + amt btcutil.Amount) wire.OutPoint { + // Create the htlc tx. htlcTx := wire.MsgTx{} htlcTx.AddTxIn(&wire.TxIn{ diff --git a/client/uncharge.go b/uncharge.go similarity index 99% rename from client/uncharge.go rename to uncharge.go index c55d7e7..66cabc0 100644 --- a/client/uncharge.go +++ b/uncharge.go @@ -1,4 +1,4 @@ -package client +package loop import ( "context" @@ -305,10 +305,9 @@ func (s *unchargeSwap) executeSwap(globalCtx context.Context) error { return err } - // Inspect witness stack to see if it is a success transaction. We don't - // just try to match with the hash of our sweep tx, because it may be - // swept by a different (fee) sweep tx from a previous run. - + // Inspect witness stack to see if it is a success transaction. We + // don't just try to match with the hash of our sweep tx, because it + // may be swept by a different (fee) sweep tx from a previous run. htlcInput, err := getTxInputByOutpoint( spendDetails.SpendingTx, htlcOutpoint, ) diff --git a/uncharge_state.go b/uncharge_state.go new file mode 100644 index 0000000..2d09be7 --- /dev/null +++ b/uncharge_state.go @@ -0,0 +1 @@ +package loop diff --git a/client/uncharge_test.go b/uncharge_test.go similarity index 99% rename from client/uncharge_test.go rename to uncharge_test.go index 6cd6753..29b8f49 100644 --- a/client/uncharge_test.go +++ b/uncharge_test.go @@ -1,4 +1,4 @@ -package client +package loop import ( "context"