From eea02b30adacee55791caba0cae9568bac5085de Mon Sep 17 00:00:00 2001 From: bruwbird Date: Sun, 11 Feb 2024 18:00:37 +0900 Subject: [PATCH 1/3] lnd: label the tx to make it easier to audit Ensure that all lnd transactions related to peerswaps are identifiable by the label `peerswap`. This makes it easier to audit the transactions from faraday. This is performed by LND's LabelTransaction RPC. Since CLN has no such function, no label is assigned. Since label recording is not an essential requirement for swap, if it fails, it is logged and subsequent processing is continued. --- clightning/clightning_wallet.go | 8 ++++++++ lnd/lnd_wallet.go | 17 +++++++++++++++++ onchain/bitcoin.go | 8 ++++++++ onchain/liquid.go | 8 ++++++++ swap/actions.go | 21 +++++++++++++++++++-- swap/services.go | 1 + swap/swap_out_sender_test.go | 4 ++++ 7 files changed, 65 insertions(+), 2 deletions(-) diff --git a/clightning/clightning_wallet.go b/clightning/clightning_wallet.go index 91893cb5..bbdb8ad1 100644 --- a/clightning/clightning_wallet.go +++ b/clightning/clightning_wallet.go @@ -199,6 +199,14 @@ func (cl *ClightningClient) CreateCoopSpendingTransaction(swapParams *swap.Openi return spendingTx.TxHash().String(), txHex, nil } +func (cl *ClightningClient) LabelTransaction(txId, label string) error { + // todo implement + // This function assigns an identifiable label to the target transaction based on the txid. + // Currently no such functionality is available, so it has not been implemented. + // Supported by lnd only. + return nil +} + func (cl *ClightningClient) NewAddress() (string, error) { newAddr, err := cl.glightning.NewAddr() if err != nil { diff --git a/lnd/lnd_wallet.go b/lnd/lnd_wallet.go index 039ecfa7..adc36684 100644 --- a/lnd/lnd_wallet.go +++ b/lnd/lnd_wallet.go @@ -7,6 +7,7 @@ import ( "encoding/hex" "github.com/btcsuite/btcd/btcutil/psbt" + "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" "github.com/elementsproject/peerswap/lightning" "github.com/elementsproject/peerswap/onchain" @@ -207,6 +208,22 @@ func (l *Client) CreateCoopSpendingTransaction(swapParams *swap.OpeningParams, c return spendingTx.TxHash().String(), txHex, nil } +// LabelTransaction labels a transaction with a given label. +// This makes it easier to audit the transactions from faraday. +// This is performed by LND's LabelTransaction RPC. +func (l *Client) LabelTransaction(txID, label string) error { + txIDHash, err := chainhash.NewHashFromStr(txID) + if err != nil { + return err + } + _, err = l.walletClient.LabelTransaction(l.ctx, + &walletrpc.LabelTransactionRequest{ + Txid: txIDHash.CloneBytes(), + Label: label, + Overwrite: true}) + return err +} + func (l *Client) GetOnchainBalance() (uint64, error) { res, err := l.lndClient.WalletBalance(l.ctx, &lnrpc.WalletBalanceRequest{}) if err != nil { diff --git a/onchain/bitcoin.go b/onchain/bitcoin.go index d6fc0101..02ef14c7 100644 --- a/onchain/bitcoin.go +++ b/onchain/bitcoin.go @@ -254,6 +254,14 @@ func (b *BitcoinOnChain) PrepareSpendingTransaction(swapParams *swap.OpeningPara return spendingTx, sigHash, redeemScript, nil } +func (b *BitcoinOnChain) LabelTransaction(txID, label string) error { + // TODO: implement + // This function assigns an identifiable label to the target transaction based on the txid. + // Currently no such functionality is available, so it has not been implemented. + // Supported by lnd only. + return nil +} + func (b *BitcoinOnChain) CreateOpeningAddress(params *swap.OpeningParams, csv uint32) (string, error) { redeemScript, err := ParamsToTxScript(params, csv) if err != nil { diff --git a/onchain/liquid.go b/onchain/liquid.go index 3a854a9e..27e26a61 100644 --- a/onchain/liquid.go +++ b/onchain/liquid.go @@ -220,6 +220,14 @@ func (l *LiquidOnChain) CreateCoopSpendingTransaction(swapParams *swap.OpeningPa return txId, txHex, nil } +func (l *LiquidOnChain) LabelTransaction(txID, label string) error { + // TODO: implement + // This function assigns an identifiable label to the target transaction based on the txid. + // Currently no such functionality is available, so it has not been implemented. + // Supported by lnd only. + return nil +} + func (l *LiquidOnChain) AddBlindingRandomFactors(claimParams *swap.ClaimParams) (err error) { claimParams.OutputAssetBlindingFactor = generateRandom32Bytes() claimParams.BlindingSeed = generateRandom32Bytes() diff --git a/swap/actions.go b/swap/actions.go index a8f158a1..046888c3 100644 --- a/swap/actions.go +++ b/swap/actions.go @@ -18,8 +18,9 @@ import ( ) const ( - BitcoinCsv = 1008 - LiquidCsv = 60 + BitcoinCsv = 1008 + LiquidCsv = 60 + peerswapLabel = "peerswap" ) type CheckRequestWrapperAction struct { @@ -194,6 +195,10 @@ func (s *ClaimSwapTransactionWithPreimageAction) Execute(services *SwapServices, return Event_OnRetry } swap.ClaimTxId = txId + err = wallet.LabelTransaction(txId, peerswapLabel) + if err != nil { + log.Infof("Error labeling trnasaction %v", err) + } } return Event_ActionSucceeded @@ -249,6 +254,10 @@ func (c *CreateAndBroadcastOpeningTransaction) Execute(services *SwapServices, s // todo: idempotent states return swap.HandleError(err) } + err = wallet.LabelTransaction(txId, peerswapLabel) + if err != nil { + log.Infof("Error labeling trnasaction %v", err) + } startingHeight, err := txWatcher.GetBlockHeight() if err != nil { return swap.HandleError(err) @@ -437,6 +446,10 @@ func (c *ClaimSwapTransactionWithCsv) Execute(services *SwapServices, swap *Swap return Event_OnRetry } swap.ClaimTxId = txId + err = wallet.LabelTransaction(txId, peerswapLabel) + if err != nil { + log.Infof("Error labeling trnasaction %v", err) + } } return Event_ActionSucceeded @@ -463,6 +476,10 @@ func (c *ClaimSwapTransactionCoop) Execute(services *SwapServices, swap *SwapDat return swap.HandleError(err) } swap.ClaimTxId = txId + err = wallet.LabelTransaction(txId, peerswapLabel) + if err != nil { + log.Infof("Error labeling trnasaction %v", err) + } } return Event_ActionSucceeded diff --git a/swap/services.go b/swap/services.go index 6a843c09..8bf11e53 100644 --- a/swap/services.go +++ b/swap/services.go @@ -74,6 +74,7 @@ type Wallet interface { CreatePreimageSpendingTransaction(swapParams *OpeningParams, claimParams *ClaimParams) (string, string, error) CreateCsvSpendingTransaction(swapParams *OpeningParams, claimParams *ClaimParams) (txId, txHex string, error error) CreateCoopSpendingTransaction(swapParams *OpeningParams, claimParams *ClaimParams, takerSigner Signer) (txId, txHex string, error error) + LabelTransaction(txId, label string) error GetOutputScript(params *OpeningParams) ([]byte, error) NewAddress() (string, error) GetRefundFee() (uint64, error) diff --git a/swap/swap_out_sender_test.go b/swap/swap_out_sender_test.go index b4267736..57ca0a70 100644 --- a/swap/swap_out_sender_test.go +++ b/swap/swap_out_sender_test.go @@ -458,6 +458,10 @@ func (d *dummyChain) AddWaitForConfirmationTx(swapId, txId string, vout, startin } +func (d *dummyChain) LabelTransaction(txId, label string) error { + return nil +} + func (d *dummyChain) AddWaitForCsvTx(swapId, txId string, vout uint32, startingHeight uint32, wantscript []byte) { } From 22c7144dd201c5ca9b012d4dc7c3f0afe00cf460 Mon Sep 17 00:00:00 2001 From: bruwbird Date: Thu, 15 Feb 2024 09:36:54 +0900 Subject: [PATCH 2/3] labels: add labels package Add labels package to handle labeling on-chain transactions. * Opening label * claim by CSV label * claim by cooperative close label --- labels/labels.go | 36 ++++++++++++++++++++++++++++++++++++ swap/actions.go | 37 +++++++++++++++++++++++++------------ swap/swap.go | 5 +++++ 3 files changed, 66 insertions(+), 12 deletions(-) create mode 100644 labels/labels.go diff --git a/labels/labels.go b/labels/labels.go new file mode 100644 index 00000000..ad795ca4 --- /dev/null +++ b/labels/labels.go @@ -0,0 +1,36 @@ +package labels + +import "fmt" + +const ( + // peerswapLabelPattern is the pattern that peerswap uses to label on-chain transactions. + peerswapLabelPattern = "peerswap -- %s(swap id=%s)" + // opening is the label used for the opening transaction. + opening = "Opening" + // claimByInvoice is the label used for the claim by invoice transaction. + claimByInvoice = "ClaimByInvoice" + // claimByCoop is the label used for the claim by cooperative close transaction. + claimByCoop = "ClaimByCoop" + // ClaimByCsv is the label used for the claim by CSV transaction. + claimByCsv = "ClaimByCsv" +) + +// Opening returns the label used for the opening transaction. +func Opening(swapID string) string { + return fmt.Sprintf(peerswapLabelPattern, opening, swapID) +} + +// ClaimByInvoice returns the label used for the claim by invoice transaction. +func ClaimByInvoice(swapID string) string { + return fmt.Sprintf(peerswapLabelPattern, claimByInvoice, swapID) +} + +// ClaimByCoop returns the label used for the claim by cooperative close transaction. +func ClaimByCoop(swapID string) string { + return fmt.Sprintf(peerswapLabelPattern, claimByCoop, swapID) +} + +// ClaimByCsv returns the label used for the claim by CSV transaction. +func ClaimByCsv(swapID string) string { + return fmt.Sprintf(peerswapLabelPattern, claimByCsv, swapID) +} diff --git a/swap/actions.go b/swap/actions.go index 046888c3..ce193fd0 100644 --- a/swap/actions.go +++ b/swap/actions.go @@ -13,14 +13,14 @@ import ( "github.com/btcsuite/btcd/btcec/v2" "github.com/elementsproject/peerswap/isdev" + "github.com/elementsproject/peerswap/labels" "github.com/elementsproject/peerswap/lightning" "github.com/elementsproject/peerswap/messages" ) const ( - BitcoinCsv = 1008 - LiquidCsv = 60 - peerswapLabel = "peerswap" + BitcoinCsv = 1008 + LiquidCsv = 60 ) type CheckRequestWrapperAction struct { @@ -195,9 +195,10 @@ func (s *ClaimSwapTransactionWithPreimageAction) Execute(services *SwapServices, return Event_OnRetry } swap.ClaimTxId = txId - err = wallet.LabelTransaction(txId, peerswapLabel) + err = wallet.LabelTransaction(txId, labels.ClaimByInvoice(swap.GetId().Short())) if err != nil { - log.Infof("Error labeling trnasaction %v", err) + log.Infof("Error labeling transaction. txid: %s, label: %s, error: %v", + txId, labels.ClaimByInvoice(swap.GetId().Short()), err) } } @@ -254,9 +255,10 @@ func (c *CreateAndBroadcastOpeningTransaction) Execute(services *SwapServices, s // todo: idempotent states return swap.HandleError(err) } - err = wallet.LabelTransaction(txId, peerswapLabel) + err = wallet.LabelTransaction(txId, labels.Opening(swap.GetId().Short())) if err != nil { - log.Infof("Error labeling trnasaction %v", err) + log.Infof("Error labeling transaction. txid: %s, label: %s, error: %v", + txId, labels.Opening(swap.GetId().Short()), err) } startingHeight, err := txWatcher.GetBlockHeight() if err != nil { @@ -446,9 +448,10 @@ func (c *ClaimSwapTransactionWithCsv) Execute(services *SwapServices, swap *Swap return Event_OnRetry } swap.ClaimTxId = txId - err = wallet.LabelTransaction(txId, peerswapLabel) + err = wallet.LabelTransaction(txId, labels.ClaimByCsv(swap.GetId().Short())) if err != nil { - log.Infof("Error labeling trnasaction %v", err) + log.Infof("Error labeling transaction. txid: %s, label: %s, error: %v", + txId, labels.ClaimByCsv(swap.GetId().Short()), err) } } @@ -476,9 +479,10 @@ func (c *ClaimSwapTransactionCoop) Execute(services *SwapServices, swap *SwapDat return swap.HandleError(err) } swap.ClaimTxId = txId - err = wallet.LabelTransaction(txId, peerswapLabel) + err = wallet.LabelTransaction(txId, labels.ClaimByCoop(swap.GetId().Short())) if err != nil { - log.Infof("Error labeling trnasaction %v", err) + log.Infof("Error labeling transaction. txid: %s, label: %s, error: %v", + txId, labels.ClaimByCoop(swap.GetId().Short()), err) } } @@ -717,7 +721,7 @@ type ValidateTxAndPayClaimInvoiceAction struct{} func (p *ValidateTxAndPayClaimInvoiceAction) Execute(services *SwapServices, swap *SwapData) EventType { lc := services.lightning - onchain, _, validator, err := services.getOnChainServices(swap.GetChain()) + onchain, wallet, validator, err := services.getOnChainServices(swap.GetChain()) if err != nil { return swap.HandleError(err) } @@ -730,6 +734,15 @@ func (p *ValidateTxAndPayClaimInvoiceAction) Execute(services *SwapServices, swa if !ok { return swap.HandleError(errors.New("tx is not valid")) } + txId, err := validator.TxIdFromHex(swap.OpeningTxHex) + if err != nil { + return swap.HandleError(err) + } + err = wallet.LabelTransaction(txId, labels.Opening(swap.GetId().Short())) + if err != nil { + log.Infof("Error labeling transaction. txid: %s, label: %s, error: %v", + txId, labels.Opening(swap.GetId().Short()), err) + } var retryTime time.Duration = 120 * time.Second var interval time.Duration = 10 * time.Second diff --git a/swap/swap.go b/swap/swap.go index c054a58d..26051f08 100644 --- a/swap/swap.go +++ b/swap/swap.go @@ -455,6 +455,11 @@ func (s *SwapId) FromString(str string) error { return nil } +// Short returns a shortened version of the id suitable for use in observing. +func (s *SwapId) Short() string { + return s.String()[:6] +} + func ParseSwapIdFromString(str string) (*SwapId, error) { data, err := hex.DecodeString(str) if err != nil { From 2ce98c1c3d9c41a404c03a5999368e8d4fb50c8d Mon Sep 17 00:00:00 2001 From: bruwbird Date: Fri, 16 Feb 2024 06:46:50 +0900 Subject: [PATCH 3/3] swap: remove Receiving nodes label attempts Receiving nodes should not attempt to apply a label to this transaction that is not being tracked by the receiving node --- swap/actions.go | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/swap/actions.go b/swap/actions.go index ce193fd0..1744d174 100644 --- a/swap/actions.go +++ b/swap/actions.go @@ -721,7 +721,7 @@ type ValidateTxAndPayClaimInvoiceAction struct{} func (p *ValidateTxAndPayClaimInvoiceAction) Execute(services *SwapServices, swap *SwapData) EventType { lc := services.lightning - onchain, wallet, validator, err := services.getOnChainServices(swap.GetChain()) + onchain, _, validator, err := services.getOnChainServices(swap.GetChain()) if err != nil { return swap.HandleError(err) } @@ -734,15 +734,6 @@ func (p *ValidateTxAndPayClaimInvoiceAction) Execute(services *SwapServices, swa if !ok { return swap.HandleError(errors.New("tx is not valid")) } - txId, err := validator.TxIdFromHex(swap.OpeningTxHex) - if err != nil { - return swap.HandleError(err) - } - err = wallet.LabelTransaction(txId, labels.Opening(swap.GetId().Short())) - if err != nil { - log.Infof("Error labeling transaction. txid: %s, label: %s, error: %v", - txId, labels.Opening(swap.GetId().Short()), err) - } var retryTime time.Duration = 120 * time.Second var interval time.Duration = 10 * time.Second