@@ -1847,6 +1847,12 @@ func (s *UtxoSweeper) handleBumpEvent(r *bumpResp) error {
1847
1847
case TxReplaced :
1848
1848
return s .handleBumpEventTxReplaced (r )
1849
1849
1850
+ // There are inputs being spent in a tx which the fee bumper doesn't
1851
+ // understand. We will remove the tx from the sweeper db and mark the
1852
+ // inputs as swept.
1853
+ case TxUnknownSpend :
1854
+ s .handleBumpEventTxUnknownSpend (r )
1855
+
1850
1856
// There's a fatal error in creating the tx, we will remove the tx from
1851
1857
// the sweeper db and mark the inputs as failed.
1852
1858
case TxFatal :
@@ -1878,3 +1884,141 @@ func (s *UtxoSweeper) IsSweeperOutpoint(op wire.OutPoint) bool {
1878
1884
1879
1885
return found
1880
1886
}
1887
+
1888
+ // markInputSwept marks the given input as swept by the tx. It will also notify
1889
+ // all the subscribers of this input.
1890
+ func (s * UtxoSweeper ) markInputSwept (inp * SweeperInput , tx * wire.MsgTx ) {
1891
+ log .Debugf ("Marking input as swept: %v from state=%v" , inp .OutPoint (),
1892
+ inp .state )
1893
+
1894
+ inp .state = Swept
1895
+
1896
+ // Signal result channels.
1897
+ s .signalResult (inp , Result {
1898
+ Tx : tx ,
1899
+ })
1900
+
1901
+ // Remove all other inputs in this exclusive group.
1902
+ if inp .params .ExclusiveGroup != nil {
1903
+ s .removeExclusiveGroup (* inp .params .ExclusiveGroup )
1904
+ }
1905
+ }
1906
+
1907
+ // handleUnknownSpendTx takes an input and its spending tx. If the spending tx
1908
+ // cannot be found in the sweeper store, the input will be marked as fatal,
1909
+ // otherwise it will be marked as swept.
1910
+ func (s * UtxoSweeper ) handleUnknownSpendTx (inp * SweeperInput , tx * wire.MsgTx ) {
1911
+ op := inp .OutPoint ()
1912
+ txid := tx .TxHash ()
1913
+
1914
+ isOurTx , err := s .cfg .Store .IsOurTx (txid )
1915
+ if err != nil {
1916
+ log .Errorf ("Cannot determine if tx %v is ours: %v" , txid , err )
1917
+ return
1918
+ }
1919
+
1920
+ // If this is our tx, it means it's a previous sweeping tx that got
1921
+ // confirmed, which could happen when a restart happens during the
1922
+ // sweeping process.
1923
+ if isOurTx {
1924
+ log .Debugf ("Found our sweeping tx %v, marking input %v as " +
1925
+ "swept" , txid , op )
1926
+
1927
+ // We now use the spending tx to update the state of the inputs.
1928
+ s .markInputSwept (inp , tx )
1929
+
1930
+ return
1931
+ }
1932
+
1933
+ // Since the input is spent by others, we now mark it as fatal and won't
1934
+ // be retried.
1935
+ s .markInputFatal (inp , ErrRemoteSpend )
1936
+
1937
+ log .Debugf ("Removing descendant txns invalidated by (txid=%v): %v" ,
1938
+ txid , lnutils .SpewLogClosure (tx ))
1939
+
1940
+ // Construct a map of the inputs this transaction spends.
1941
+ spentInputs := make (map [wire.OutPoint ]struct {}, len (tx .TxIn ))
1942
+ for _ , txIn := range tx .TxIn {
1943
+ spentInputs [txIn .PreviousOutPoint ] = struct {}{}
1944
+ }
1945
+
1946
+ err = s .removeConflictSweepDescendants (spentInputs )
1947
+ if err != nil {
1948
+ log .Warnf ("unable to remove descendant transactions " +
1949
+ "due to tx %v: " , txid )
1950
+ }
1951
+ }
1952
+
1953
+ // handleBumpEventTxUnknownSpend handles the case where the confirmed tx is
1954
+ // unknown to the fee bumper. In the case when the sweeping tx has been replaced
1955
+ // by another party with their tx being confirmed. It will retry sweeping the
1956
+ // "good" inputs once the "bad" ones are kicked out.
1957
+ func (s * UtxoSweeper ) handleBumpEventTxUnknownSpend (r * bumpResp ) {
1958
+ // Mark the inputs as publish failed, which means they will be retried
1959
+ // later.
1960
+ s .markInputsPublishFailed (r .set )
1961
+
1962
+ // Get all the inputs that are not spent in the current sweeping tx.
1963
+ spentInputs := r .result .SpentInputs
1964
+
1965
+ // Create a slice to track inputs to be retried.
1966
+ inputsToRetry := make ([]input.Input , 0 , len (r .set .Inputs ()))
1967
+
1968
+ // Iterate all the inputs found in this bump and mark the ones spent by
1969
+ // the third party as failed. The rest of inputs will then be updated
1970
+ // with a new fee rate and be retried immediately.
1971
+ for _ , inp := range r .set .Inputs () {
1972
+ op := inp .OutPoint ()
1973
+ input , ok := s .inputs [op ]
1974
+
1975
+ // Wallet inputs are not tracked so we will not find them from
1976
+ // the inputs map.
1977
+ if ! ok {
1978
+ log .Debugf ("Skipped marking input: %v not found in " +
1979
+ "pending inputs" , op )
1980
+
1981
+ continue
1982
+ }
1983
+
1984
+ // Check whether this input has been spent, if so we mark it as
1985
+ // fatal or swept based on whether this is one of our previous
1986
+ // sweeping txns, then move to the next.
1987
+ tx , spent := spentInputs [op ]
1988
+ if spent {
1989
+ s .handleUnknownSpendTx (input , tx )
1990
+
1991
+ continue
1992
+ }
1993
+
1994
+ log .Debugf ("Input(%v): updating params: starting fee rate " +
1995
+ "[%v -> %v], immediate [%v -> true]" , op ,
1996
+ input .params .StartingFeeRate , r .result .FeeRate ,
1997
+ input .params .Immediate )
1998
+
1999
+ // Update the input using the fee rate specified from the
2000
+ // BumpResult, which should be the starting fee rate to use for
2001
+ // the next sweeping attempt.
2002
+ input .params .StartingFeeRate = fn .Some (r .result .FeeRate )
2003
+ input .params .Immediate = true
2004
+ inputsToRetry = append (inputsToRetry , input )
2005
+ }
2006
+
2007
+ // Exit early if there are no inputs to be retried.
2008
+ if len (inputsToRetry ) == 0 {
2009
+ return
2010
+ }
2011
+
2012
+ log .Debugf ("Retry sweeping inputs with updated params: %v" ,
2013
+ inputTypeSummary (inputsToRetry ))
2014
+
2015
+ // Get the latest inputs, which should put the PublishFailed inputs back
2016
+ // to the sweeping queue.
2017
+ inputs := s .updateSweeperInputs ()
2018
+
2019
+ // Immediately sweep the remaining inputs - the previous inputs should
2020
+ // now be swept with the updated StartingFeeRate immediately. We may
2021
+ // also include more inputs in the new sweeping tx if new ones with the
2022
+ // same deadline are offered.
2023
+ s .sweepPendingInputs (inputs )
2024
+ }
0 commit comments