From d60a44c73d6cbe0f2d41ee9c239022fc2d9a48d1 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Wed, 26 Aug 2020 16:38:58 -0700 Subject: [PATCH] account: implement fee bump for transactions of accounts in pending states --- account/manager.go | 55 +++++++++++++++++++++++++++++++++ go.mod | 4 +-- go.sum | 22 +++++-------- internal/test/walletkit_mock.go | 6 ++++ 4 files changed, 71 insertions(+), 16 deletions(-) diff --git a/account/manager.go b/account/manager.go index 9e89aad..ca1436e 100644 --- a/account/manager.go +++ b/account/manager.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "math" + "strings" "sync" "github.com/btcsuite/btcd/blockchain" @@ -20,6 +21,7 @@ import ( "github.com/lightninglabs/lndclient" "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/input" + "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/lnwallet/chanfunding" ) @@ -1007,6 +1009,59 @@ func (m *Manager) WithdrawAccount(ctx context.Context, return modifiedAccount, spendPkg.tx, nil } +// BumpAccountFee attempts to bump the fee of an account's most recent +// transaction. This is done by locating an eligible output for lnd to CPFP, +// otherwise the fee bump will not succeed. Further invocations of this call for +// the same account will result in the child being replaced by the higher fee +// transaction (RBF). +func (m *Manager) BumpAccountFee(ctx context.Context, + traderKey *btcec.PublicKey, newFeeRate chainfee.SatPerKWeight) error { + + account, err := m.cfg.Store.Account(traderKey) + if err != nil { + return err + } + + // Only accounts in pending states can have their transaction fees + // bumped. + switch account.State { + case StatePendingOpen, StatePendingUpdate, StatePendingClosed: + default: + return fmt.Errorf("cannot bump fee for account in state %v", + account.State) + } + + // Since we're using lnd's sweeper for fee bumps, we'll need to find an + // output in the transaction under its control to perform the CPFP/RBF. + op := wire.OutPoint{Hash: account.LatestTx.TxHash()} + for i := range account.LatestTx.TxOut { + op.Index = uint32(i) + + log.Debugf("Attempting CPFP with %v for account %x", op, + traderKey.SerializeCompressed()) + + err := m.cfg.Wallet.BumpFee(ctx, op, newFeeRate) + if err != nil { + // Output isn't known to lnd, continue to the next one. + if strings.Contains(err.Error(), lnwallet.ErrNotMine.Error()) { + continue + } + + // A fatal error occurred, return it. + return err + } + + // Once we've found an eligible output, we can return. + log.Infof("Found eligible output %v for CPFP of account %x", + op, traderKey.SerializeCompressed()) + return nil + } + + // If we didn't find an eligible output, report it as an error. + return fmt.Errorf("transaction %v did not contain any eligible "+ + "outputs to CPFP", op.Hash) +} + // CloseAccount attempts to close the account associated with the given trader // key. Closing the account requires a signature of the auctioneer if the // account has not yet expired. The account funds are swept according to the diff --git a/go.mod b/go.mod index b499aaf..dd4fe08 100644 --- a/go.mod +++ b/go.mod @@ -12,8 +12,8 @@ require ( github.com/golang/protobuf v1.3.3 github.com/grpc-ecosystem/grpc-gateway v1.14.6 github.com/jessevdk/go-flags v1.4.0 - github.com/lightninglabs/aperture v0.0.0-20200811173827-537716305eba - github.com/lightninglabs/lndclient v1.0.1-0.20200811080044-d1a60f30cf60 + github.com/lightninglabs/aperture v0.1.1-beta.0.20200901205500-5237b07a6ef5 + github.com/lightninglabs/lndclient v0.11.0-1 github.com/lightninglabs/protobuf-hex-display v1.3.3-0.20191212020323-b444784ce75d github.com/lightningnetwork/lnd v0.11.0-beta.rc2 github.com/stretchr/testify v1.5.1 diff --git a/go.sum b/go.sum index e71c1db..6b264ad 100644 --- a/go.sum +++ b/go.sum @@ -24,8 +24,6 @@ github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcug github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.20.1-beta.0.20200513120220-b470eee47728/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= -github.com/btcsuite/btcd v0.20.1-beta.0.20200515232429-9f0179fd2c46 h1:QyTpiR5nQe94vza2qkvf7Ns8XX2Rjh/vdIhO3RzGj4o= -github.com/btcsuite/btcd v0.20.1-beta.0.20200515232429-9f0179fd2c46/go.mod h1:Yktc19YNjh/Iz2//CX0vfRTS4IJKM/RKO5YZ9Fn+Pgo= github.com/btcsuite/btcd v0.20.1-beta.0.20200730232343-1db1b6f8217f h1:m/GhMTvDQLbID616c4TYdHyt0MZ9lH5B/nf9Lu3okCY= github.com/btcsuite/btcd v0.20.1-beta.0.20200730232343-1db1b6f8217f/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= @@ -37,6 +35,8 @@ github.com/btcsuite/btcutil/psbt v1.0.2 h1:gCVY3KxdoEVU7Q6TjusPO+GANIwVgr9yTLqM+ github.com/btcsuite/btcutil/psbt v1.0.2/go.mod h1:LVveMu4VaNSkIRTZu2+ut0HDBRuYjqGocxDMNS1KuGQ= github.com/btcsuite/btcwallet v0.11.1-0.20200612012534-48addcd5591a h1:AZ1Mf0gd9mgJqrTTIFUc17ep9EKUbQusVAIzJ6X+x3Q= github.com/btcsuite/btcwallet v0.11.1-0.20200612012534-48addcd5591a/go.mod h1:9+AH3V5mcTtNXTKe+fe63fDLKGOwQbZqmvOVUef+JFE= +github.com/btcsuite/btcwallet v0.11.1-0.20200814001439-1d31f4ea6fc5 h1:1We7EuizBnX/17Q6O2dkeToyehxzUHo62Wv1c0ncr7c= +github.com/btcsuite/btcwallet v0.11.1-0.20200814001439-1d31f4ea6fc5/go.mod h1:YkEbJaCyN6yncq5gEp2xG0OKDwus2QxGCEXTNF27w5I= github.com/btcsuite/btcwallet/wallet/txauthor v1.0.0 h1:KGHMW5sd7yDdDMkCZ/JpP0KltolFsQcB973brBnfj4c= github.com/btcsuite/btcwallet/wallet/txauthor v1.0.0/go.mod h1:VufDts7bd/zs3GV13f/lXc/0lXrPnvxD/NvmpG/FEKU= github.com/btcsuite/btcwallet/wallet/txrules v1.0.0 h1:2VsfS0sBedcM5KmDzRMT3+b6xobqWveZGvjb+jFez5w= @@ -138,7 +138,6 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:Iju5GlWwrvL6UBg4zJJt3btmo github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.8.6/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.14.3/go.mod h1:6CwZWGDSPRJidgKAtJVvND6soZe6fT7iteq8wDPdhb0= github.com/grpc-ecosystem/grpc-gateway v1.14.6 h1:8ERzHx8aj1Sc47mu9n/AksaKCSWrMchFtkdrS4BIj5o= github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw= @@ -187,22 +186,21 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lightninglabs/aperture v0.0.0-20200811173827-537716305eba h1:rEI6XdRGvG4myoSzQJ1LikYEHVv1+p60L/5hejCDBjw= -github.com/lightninglabs/aperture v0.0.0-20200811173827-537716305eba/go.mod h1:LbxSjvNlM3RAB7vBhIW8TKkH4Qm2WNIT03iJ+iZqlvk= +github.com/lightninglabs/aperture v0.1.1-beta.0.20200901205500-5237b07a6ef5 h1:VHwj2tb494GDF4Da0CRX4g1NVRv1f72KB3fKhJbDb5M= +github.com/lightninglabs/aperture v0.1.1-beta.0.20200901205500-5237b07a6ef5/go.mod h1:skgCNj3K3bQXgPwrdjCkPSPVYQ3SRJZKoGl49JI+mCA= github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf h1:HZKvJUHlcXI/f/O0Avg7t8sqkPo78HFzjmeYFl6DPnc= github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf/go.mod h1:vxmQPeIQxPf6Jf9rM8R+B4rKBqLA2AjttNxkFBL2Plk= -github.com/lightninglabs/lndclient v1.0.1-0.20200708223031-76709c25d859/go.mod h1:nKEd6j54LxPYuIe3K/BUwQPus24sbvWTdoweoBcHas0= -github.com/lightninglabs/lndclient v1.0.1-0.20200811080044-d1a60f30cf60 h1:V5tXFlWoIqx/ycsQ+dibjuem/cAOboNMbUcroBVwupU= -github.com/lightninglabs/lndclient v1.0.1-0.20200811080044-d1a60f30cf60/go.mod h1:7UNQg6WLBgt+T/KBQjlSXtid7bFlwBRWdOk7ZMLYkrM= +github.com/lightninglabs/lndclient v0.11.0-0/go.mod h1:8/cTKNwgL87NX123gmlv3Xh6p1a7pvzu+40Un3PhHiI= +github.com/lightninglabs/lndclient v0.11.0-1 h1:UHIAu6eRmXpL84War0a1OvdmG7rXW+NkJEdSruo+jWE= +github.com/lightninglabs/lndclient v0.11.0-1/go.mod h1:8/cTKNwgL87NX123gmlv3Xh6p1a7pvzu+40Un3PhHiI= github.com/lightninglabs/neutrino v0.11.0/go.mod h1:CuhF0iuzg9Sp2HO6ZgXgayviFTn1QHdSTJlMncK80wg= github.com/lightninglabs/neutrino v0.11.1-0.20200316235139-bffc52e8f200 h1:j4iZ1XlUAPQmW6oSzMcJGILYsRHNs+4O3Gk+2Ms5Dww= github.com/lightninglabs/neutrino v0.11.1-0.20200316235139-bffc52e8f200/go.mod h1:MlZmoKa7CJP3eR1s5yB7Rm5aSyadpKkxqAwLQmog7N0= github.com/lightninglabs/protobuf-hex-display v1.3.3-0.20191212020323-b444784ce75d h1:QWD/5MPnaZfUVP7P8wLa4M8Td2DI7XXHXt2vhVtUgGI= github.com/lightninglabs/protobuf-hex-display v1.3.3-0.20191212020323-b444784ce75d/go.mod h1:KDb67YMzoh4eudnzClmvs2FbiLG9vxISmLApUkCa4uI= -github.com/lightningnetwork/lightning-onion v1.0.1/go.mod h1:rigfi6Af/KqsF7Za0hOgcyq2PNH4AN70AaMRxcJkff4= github.com/lightningnetwork/lightning-onion v1.0.2-0.20200501022730-3c8c8d0b89ea h1:oCj48NQ8u7Vz+MmzHqt0db6mxcFZo3Ho7M5gCJauY/k= github.com/lightningnetwork/lightning-onion v1.0.2-0.20200501022730-3c8c8d0b89ea/go.mod h1:rigfi6Af/KqsF7Za0hOgcyq2PNH4AN70AaMRxcJkff4= -github.com/lightningnetwork/lnd v0.10.3-beta/go.mod h1:4d02pduRVtZwgTJ+EimKJTsEAY0jDwi0SPE9h5aRneM= +github.com/lightningnetwork/lnd v0.11.0-beta/go.mod h1:CzArvT7NFDLhVyW06+NJWSuWFmE6Ea+AjjA3txUBqTM= github.com/lightningnetwork/lnd v0.11.0-beta.rc2 h1:em+sMbR/RF90RFgig2pWkuzXbpdIDLAUFIoxK68Z6j8= github.com/lightningnetwork/lnd v0.11.0-beta.rc2/go.mod h1:/f/0xJER9MIoFE2LHJljPH6vtHYkrmwYS4KkD1S5wwo= github.com/lightningnetwork/lnd/cert v1.0.2/go.mod h1:fmtemlSMf5t4hsQmcprSoOykypAPp+9c+0d0iqTScMo= @@ -254,7 +252,6 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084 h1:sofwID9zm4tzrgykg80hfFph1mryUeLRsUfoocVVmRY= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -322,7 +319,6 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190206173232-65e2d4e15006/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -402,10 +398,8 @@ gopkg.in/macaroon.v2 v2.1.0 h1:HZcsjBCzq9t0eBPMKqTN/uSN6JOm78ZJ2INbqcBQOUI= gopkg.in/macaroon.v2 v2.1.0/go.mod h1:OUb+TQP/OP0WOerC2Jp/3CwhIKyIa9kQjuc7H24e6/o= gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 h1:VpOs+IwYnYBaFnrNAeB8UUWtL3vEUnzSCL1nVjPhqrw= gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3 h1:fvjTMHxHEw/mxHbtzPi3JCcKXQRAnQTBRo6YCJSVHKI= diff --git a/internal/test/walletkit_mock.go b/internal/test/walletkit_mock.go index 2bec3a3..0674de4 100644 --- a/internal/test/walletkit_mock.go +++ b/internal/test/walletkit_mock.go @@ -154,3 +154,9 @@ func (m *MockWalletKit) AddTx(tx *wire.MsgTx) { m.Transactions = append(m.Transactions, tx.Copy()) m.lock.Unlock() } + +func (m *MockWalletKit) BumpFee(context.Context, wire.OutPoint, + chainfee.SatPerKWeight) error { + + panic("unimplemented") +}