diff --git a/README.md b/README.md index f70abdd..545a09d 100644 --- a/README.md +++ b/README.md @@ -304,6 +304,7 @@ Detailed documentation for each sub command is available in the Quick access: + [chanbackup](doc/chantools_chanbackup.md) ++ [closepoolaccount](doc/chantools_closepoolaccount.md) + [compactdb](doc/chantools_compactdb.md) + [deletepayments](doc/chantools_deletepayments.md) + [derivekey](doc/chantools_derivekey.md) diff --git a/cmd/chantools/closepoolaccount.go b/cmd/chantools/closepoolaccount.go new file mode 100644 index 0000000..23bc48c --- /dev/null +++ b/cmd/chantools/closepoolaccount.go @@ -0,0 +1,414 @@ +package main + +import ( + "bytes" + "encoding/hex" + "fmt" + + "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/txscript" + "github.com/btcsuite/btcd/wire" + "github.com/btcsuite/btcutil/hdkeychain" + "github.com/guggero/chantools/btc" + "github.com/guggero/chantools/lnd" + "github.com/lightninglabs/pool/poolscript" + "github.com/lightningnetwork/lnd/input" + "github.com/lightningnetwork/lnd/keychain" + "github.com/lightningnetwork/lnd/lnwallet/chainfee" + "github.com/spf13/cobra" +) + +const ( + poolMainnetFirstBatchBlock = 648168 + defaultMaxNumBlocks = 200000 + defaultMaxNumAccounts = 20 + defaultMaxNumBatchKeys = 500 +) + +var ( + initialBatchKeyBytes, _ = hex.DecodeString( + "02824d0cbac65e01712124c50ff2cc74ce22851d7b444c1bf2ae66afefb8" + + "eaf27f", + ) + initialBatchKey, _ = btcec.ParsePubKey( + initialBatchKeyBytes, btcec.S256(), + ) + + mainnetAuctioneerKeyHex = "028e87bdd134238f8347f845d9ecc827b843d0d1e2" + + "7cdcb46da704d916613f4fce" +) + +type closePoolAccountCommand struct { + APIURL string + Outpoint string + AuctioneerKey string + Publish bool + SweepAddr string + FeeRate uint16 + + MinExpiry uint32 + MaxNumBlocks uint32 + MaxNumAccounts uint32 + MaxNumBatchKeys uint32 + + rootKey *rootKey + cmd *cobra.Command +} + +func newClosePoolAccountCommand() *cobra.Command { + cc := &closePoolAccountCommand{} + cc.cmd = &cobra.Command{ + Use: "closepoolaccount", + Short: "Tries to close a Pool account that has expired", + Long: `In case a Pool account cannot be closed normally with the +poold daemon it can be closed with this command. The account **MUST** have +expired already, otherwise this command doesn't work since a signature from the +auctioneer is necessary. + +You need to know the account's last unspent outpoint. That can either be +obtained by running 'pool accounts list' `, + Example: `chantools closepoolaccount \ + --outpoint xxxxxxxxx:y \ + --sweepaddr bc1q..... \ + --feerate 10 \ + --publish`, + RunE: cc.Execute, + } + cc.cmd.Flags().StringVar( + &cc.APIURL, "apiurl", defaultAPIURL, "API URL to use (must "+ + "be esplora compatible)", + ) + cc.cmd.Flags().StringVar( + &cc.Outpoint, "outpoint", "", "last account outpoint of the "+ + "account to close (:)", + ) + cc.cmd.Flags().StringVar( + &cc.AuctioneerKey, "auctioneerkey", mainnetAuctioneerKeyHex, + "the auctioneer's static public key", + ) + cc.cmd.Flags().BoolVar( + &cc.Publish, "publish", false, "publish sweep TX to the chain "+ + "API instead of just printing the TX", + ) + cc.cmd.Flags().StringVar( + &cc.SweepAddr, "sweepaddr", "", "address to sweep the funds to", + ) + cc.cmd.Flags().Uint16Var( + &cc.FeeRate, "feerate", defaultFeeSatPerVByte, "fee rate to "+ + "use for the sweep transaction in sat/vByte", + ) + cc.cmd.Flags().Uint32Var( + &cc.MinExpiry, "minexpiry", poolMainnetFirstBatchBlock, + "the block to start brute forcing the expiry from", + ) + cc.cmd.Flags().Uint32Var( + &cc.MaxNumBlocks, "maxnumblocks", defaultMaxNumBlocks, "the "+ + "maximum number of blocks to try when brute forcing "+ + "the expiry", + ) + cc.cmd.Flags().Uint32Var( + &cc.MaxNumAccounts, "maxnumaccounts", defaultMaxNumAccounts, + "the number of account indices to try at most", + ) + cc.cmd.Flags().Uint32Var( + &cc.MaxNumBatchKeys, "maxnumbatchkeys", defaultMaxNumBatchKeys, + "the number of batch keys to try at most", + ) + + cc.rootKey = newRootKey(cc.cmd, "deriving keys") + + return cc.cmd +} + +func (c *closePoolAccountCommand) Execute(_ *cobra.Command, _ []string) error { + extendedKey, err := c.rootKey.read() + if err != nil { + return fmt.Errorf("error reading root key: %v", err) + } + + // Make sure sweep addr is set. + if c.SweepAddr == "" { + return fmt.Errorf("sweep addr is required") + } + + // Parse account outpoint and auctioneer key. + outpoint, err := lnd.ParseOutpoint(c.Outpoint) + if err != nil { + return fmt.Errorf("error parsing account outpoint: %v", err) + } + + auctioneerKeyBytes, err := hex.DecodeString(c.AuctioneerKey) + if err != nil { + return fmt.Errorf("error decoding auctioneer key: %v", err) + } + + auctioneerKey, err := btcec.ParsePubKey( + auctioneerKeyBytes, btcec.S256(), + ) + if err != nil { + return fmt.Errorf("error parsing auctioneer key: %v", err) + } + + // Set default values. + if c.FeeRate == 0 { + c.FeeRate = defaultFeeSatPerVByte + } + return closePoolAccount( + extendedKey, c.APIURL, outpoint, auctioneerKey, c.SweepAddr, + c.Publish, c.FeeRate, c.MinExpiry, c.MinExpiry+c.MaxNumBlocks, + c.MaxNumAccounts, c.MaxNumBatchKeys, + ) +} + +func closePoolAccount(extendedKey *hdkeychain.ExtendedKey, apiURL string, + outpoint *wire.OutPoint, auctioneerKey *btcec.PublicKey, + sweepAddr string, publish bool, feeRate uint16, minExpiry, + maxNumBlocks, maxNumAccounts, maxNumBatchKeys uint32) error { + + signer := &lnd.Signer{ + ExtendedKey: extendedKey, + ChainParams: chainParams, + } + api := &btc.ExplorerAPI{BaseURL: apiURL} + + tx, err := api.Transaction(outpoint.Hash.String()) + if err != nil { + return fmt.Errorf("error looking up TX %s: %v", + outpoint.Hash.String(), err) + } + + txOut := tx.Vout[outpoint.Index] + if txOut.Outspend.Spent { + return fmt.Errorf("outpoint %v is already spent", outpoint) + } + + pkScript, err := hex.DecodeString(txOut.ScriptPubkey) + if err != nil { + return fmt.Errorf("error decoding pk script %s: %v", + txOut.ScriptPubkey, err) + } + log.Debugf("Brute forcing pk script %x for outpoint %v", pkScript, + outpoint) + + // Let's derive the account key family's extended key first. + path := []uint32{ + lnd.HardenedKeyStart + uint32(keychain.BIP0043Purpose), + lnd.HardenedKeyStart + chainParams.HDCoinType, + lnd.HardenedKeyStart + uint32(poolscript.AccountKeyFamily), + 0, + } + accountBaseKey, err := lnd.DeriveChildren(extendedKey, path) + if err != nil { + return fmt.Errorf("error deriving account base key: %v", err) + } + + // Try our luck. + acct, err := bruteForceAccountScript( + accountBaseKey, auctioneerKey, minExpiry, maxNumBlocks, + maxNumAccounts, maxNumBatchKeys, pkScript, + ) + if err != nil { + return fmt.Errorf("error brute forcing account script: %v", err) + } + + log.Debugf("Found pool account with expiry %d!", acct.expiry) + + sweepTx := wire.NewMsgTx(2) + sweepTx.LockTime = acct.expiry + sweepValue := int64(txOut.Value) + + // Create the transaction input. + sweepTx.TxIn = []*wire.TxIn{{ + PreviousOutPoint: *outpoint, + }} + + // Calculate the fee based on the given fee rate and our weight + // estimation. + var estimator input.TxWeightEstimator + estimator.AddWitnessInput(input.ToLocalTimeoutWitnessSize) + estimator.AddP2WKHOutput() + feeRateKWeight := chainfee.SatPerKVByte(1000 * feeRate).FeePerKWeight() + totalFee := feeRateKWeight.FeeForWeight(int64(estimator.Weight())) + + // Add our sweep destination output. + sweepScript, err := lnd.GetP2WPKHScript(sweepAddr, chainParams) + if err != nil { + return err + } + sweepTx.TxOut = []*wire.TxOut{{ + Value: sweepValue - int64(totalFee), + PkScript: sweepScript, + }} + + log.Infof("Fee %d sats of %d total amount (estimated weight %d)", + totalFee, sweepValue, estimator.Weight()) + + // Create the sign descriptor for the input then sign the transaction. + sigHashes := txscript.NewTxSigHashes(sweepTx) + signDesc := &input.SignDescriptor{ + KeyDesc: keychain.KeyDescriptor{ + KeyLocator: keychain.KeyLocator{ + Family: poolscript.AccountKeyFamily, + Index: acct.keyIndex, + }, + }, + SingleTweak: acct.keyTweak, + WitnessScript: acct.witnessScript, + Output: &wire.TxOut{ + PkScript: pkScript, + Value: sweepValue, + }, + InputIndex: 0, + SigHashes: sigHashes, + HashType: txscript.SigHashAll, + } + sig, err := signer.SignOutputRaw(sweepTx, signDesc) + if err != nil { + return fmt.Errorf("error signing sweep tx: %v", err) + } + ourSig := append(sig.Serialize(), byte(signDesc.HashType)) + sweepTx.TxIn[0].Witness = poolscript.SpendExpiry( + acct.witnessScript, ourSig, + ) + + var buf bytes.Buffer + err = sweepTx.Serialize(&buf) + if err != nil { + return err + } + + // Publish TX. + if publish { + response, err := api.PublishTx( + hex.EncodeToString(buf.Bytes()), + ) + if err != nil { + return err + } + log.Infof("Published TX %s, response: %s", + sweepTx.TxHash().String(), response) + } + + log.Infof("Transaction: %x", buf.Bytes()) + return nil +} + +type poolAccount struct { + keyIndex uint32 + expiry uint32 + keyTweak []byte + witnessScript []byte +} + +func bruteForceAccountScript(accountBaseKey *hdkeychain.ExtendedKey, + auctioneerKey *btcec.PublicKey, minExpiry, maxNumBlocks, maxNumAccounts, + maxNumBatchKeys uint32, targetScript []byte) (*poolAccount, error) { + + // The outer-most loop is over the possible accounts. + for i := uint32(0); i < maxNumAccounts; i++ { + accountExtendedKey, err := accountBaseKey.DeriveNonStandard(i) + if err != nil { + return nil, fmt.Errorf("error deriving account key: "+ + "%v", err) + } + + accountPrivKey, err := accountExtendedKey.ECPrivKey() + if err != nil { + return nil, fmt.Errorf("error deriving private key: "+ + "%v", err) + } + log.Debugf("Trying trader key %x...", + accountPrivKey.PubKey().SerializeCompressed()) + + sharedKey, err := lnd.ECDH(accountPrivKey, auctioneerKey) + if err != nil { + return nil, fmt.Errorf("error deriving shared key: "+ + "%v", err) + } + + // The next loop is over the batch keys. + batchKeyIndex := uint32(0) + currentBatchKey := initialBatchKey + for batchKeyIndex < maxNumBatchKeys { + // And then finally the loop over the actual account + // expiry in blocks. + block, err := fastScript( + minExpiry, maxNumBlocks, + accountPrivKey.PubKey(), auctioneerKey, + currentBatchKey, sharedKey, targetScript, + ) + if err == nil { + witnessScript, err := poolscript.AccountWitnessScript( + block, accountPrivKey.PubKey(), + auctioneerKey, currentBatchKey, + sharedKey, + ) + if err != nil { + return nil, fmt.Errorf("error "+ + "deriving script: %v", err) + } + + traderKeyTweak := poolscript.TraderKeyTweak( + currentBatchKey, sharedKey, + accountPrivKey.PubKey(), + ) + + return &poolAccount{ + keyIndex: i, + expiry: block, + keyTweak: traderKeyTweak, + witnessScript: witnessScript, + }, nil + } + + currentBatchKey = poolscript.IncrementKey( + currentBatchKey, + ) + batchKeyIndex++ + } + + log.Debugf("Tried account index %d of %d", i, maxNumAccounts) + } + + return nil, fmt.Errorf("account script not derived") +} + +func fastScript(expiryFrom, expiryTo uint32, traderKey, auctioneerKey, + batchKey *btcec.PublicKey, secret [32]byte, + targetScript []byte) (uint32, error) { + + traderKeyTweak := poolscript.TraderKeyTweak(batchKey, secret, traderKey) + tweakedTraderKey := input.TweakPubKeyWithTweak(traderKey, traderKeyTweak) + tweakedAuctioneerKey := input.TweakPubKey(auctioneerKey, tweakedTraderKey) + + for block := expiryFrom; block <= expiryTo; block++ { + builder := txscript.NewScriptBuilder() + + builder.AddData(tweakedTraderKey.SerializeCompressed()) + builder.AddOp(txscript.OP_CHECKSIGVERIFY) + + builder.AddData(tweakedAuctioneerKey.SerializeCompressed()) + builder.AddOp(txscript.OP_CHECKSIG) + + builder.AddOp(txscript.OP_IFDUP) + builder.AddOp(txscript.OP_NOTIF) + builder.AddInt64(int64(block)) + builder.AddOp(txscript.OP_CHECKLOCKTIMEVERIFY) + builder.AddOp(txscript.OP_ENDIF) + + currentScript, err := builder.Script() + if err != nil { + return 0, fmt.Errorf("error building script: %v", err) + } + + currentPkScript, err := input.WitnessScriptHash(currentScript) + if err != nil { + return 0, fmt.Errorf("error hashing script: %v", err) + } + if bytes.Equal(currentPkScript, targetScript) { + return block, nil + } + } + + return 0, fmt.Errorf("account script not derived") +} diff --git a/cmd/chantools/root.go b/cmd/chantools/root.go index 3f3852a..2b5b5b6 100644 --- a/cmd/chantools/root.go +++ b/cmd/chantools/root.go @@ -26,7 +26,7 @@ import ( const ( defaultAPIURL = "https://blockstream.info/api" - version = "0.10.0" + version = "0.10.1" na = "n/a" Commit = "" @@ -80,6 +80,7 @@ func main() { rootCmd.AddCommand( newChanBackupCommand(), + newClosePoolAccountCommand(), newCompactDBCommand(), newDeletePaymentsCommand(), newDeriveKeyCommand(), diff --git a/doc/chantools.md b/doc/chantools.md index 66d7a32..959d0b4 100644 --- a/doc/chantools.md +++ b/doc/chantools.md @@ -19,6 +19,7 @@ Complete documentation is available at https://github.com/guggero/chantools/. ### SEE ALSO * [chantools chanbackup](chantools_chanbackup.md) - Create a channel.backup file from a channel database +* [chantools closepoolaccount](chantools_closepoolaccount.md) - Tries to close a Pool account that has expired * [chantools compactdb](chantools_compactdb.md) - Create a copy of a channel.db file in safe/read-only mode * [chantools deletepayments](chantools_deletepayments.md) - Remove all (failed) payments from a channel DB * [chantools derivekey](chantools_derivekey.md) - Derive a key with a specific derivation path diff --git a/doc/chantools_closepoolaccount.md b/doc/chantools_closepoolaccount.md new file mode 100644 index 0000000..e5b929b --- /dev/null +++ b/doc/chantools_closepoolaccount.md @@ -0,0 +1,57 @@ +## chantools closepoolaccount + +Tries to close a Pool account that has expired + +### Synopsis + +In case a Pool account cannot be closed normally with the +poold daemon it can be closed with this command. The account **MUST** have +expired already, otherwise this command doesn't work since a signature from the +auctioneer is necessary. + +You need to know the account's last unspent outpoint. That can either be +obtained by running 'pool accounts list' + +``` +chantools closepoolaccount [flags] +``` + +### Examples + +``` +chantools closepoolaccount \ + --outpoint xxxxxxxxx:y \ + --sweepaddr bc1q..... \ + --feerate 10 \ + --publish +``` + +### Options + +``` + --apiurl string API URL to use (must be esplora compatible) (default "https://blockstream.info/api") + --auctioneerkey string the auctioneer's static public key (default "028e87bdd134238f8347f845d9ecc827b843d0d1e27cdcb46da704d916613f4fce") + --bip39 read a classic BIP39 seed and passphrase from the terminal instead of asking for lnd seed format or providing the --rootkey flag + --feerate uint16 fee rate to use for the sweep transaction in sat/vByte (default 30) + -h, --help help for closepoolaccount + --maxnumaccounts uint32 the number of account indices to try at most (default 20) + --maxnumbatchkeys uint32 the number of batch keys to try at most (default 500) + --maxnumblocks uint32 the maximum number of blocks to try when brute forcing the expiry (default 200000) + --minexpiry uint32 the block to start brute forcing the expiry from (default 648168) + --outpoint string last account outpoint of the account to close (:) + --publish publish sweep TX to the chain API instead of just printing the TX + --rootkey string BIP32 HD root key of the wallet to use for deriving keys; leave empty to prompt for lnd 24 word aezeed + --sweepaddr string address to sweep the funds to +``` + +### Options inherited from parent commands + +``` + -r, --regtest Indicates if regtest parameters should be used + -t, --testnet Indicates if testnet parameters should be used +``` + +### SEE ALSO + +* [chantools](chantools.md) - Chantools helps recover funds from lightning channels + diff --git a/go.mod b/go.mod index 1b98888..359b014 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ require ( github.com/davecgh/go-spew v1.1.1 github.com/frankban/quicktest v1.11.2 // indirect github.com/gogo/protobuf v1.3.2 + github.com/lightninglabs/pool v0.5.3-alpha github.com/lightningnetwork/lnd v0.14.1-beta github.com/lightningnetwork/lnd/kvdb v1.2.1 github.com/ltcsuite/ltcd v0.0.0-20191228044241-92166e412499 // indirect diff --git a/go.sum b/go.sum index b412c91..d351723 100644 --- a/go.sum +++ b/go.sum @@ -75,6 +75,7 @@ github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJm github.com/btcsuite/btcd v0.0.0-20190629003639-c26ffa870fd8/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btcd v0.20.1-beta.0.20200730232343-1db1b6f8217f/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94= github.com/btcsuite/btcd v0.21.0-beta.0.20201208033208-6bd4c64a54fa/go.mod h1:Sv4JPQ3/M+teHz9Bo5jBpkNcP0x6r7rdihlNL/7tTAs= github.com/btcsuite/btcd v0.22.0-beta.0.20210803133449-f5a1fb9965e4/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA= github.com/btcsuite/btcd v0.22.0-beta.0.20211005184431-e3449998be39 h1:o6qacOzpKubr16y0RrE2fBauRZN1rDZ1YsE26ixCgQ0= @@ -100,10 +101,12 @@ github.com/btcsuite/btcwallet/wallet/txrules v1.1.0/go.mod h1:Zn9UTqpiTH+HOd5BLz github.com/btcsuite/btcwallet/wallet/txsizes v1.0.0/go.mod h1:pauEU8UuMFiThe5PB3EO+gO5kx87Me5NvdQDsTuq6cs= github.com/btcsuite/btcwallet/wallet/txsizes v1.1.0 h1:wZnOolEAeNOHzHTnznw/wQv+j35ftCIokNrnOTOU5o8= github.com/btcsuite/btcwallet/wallet/txsizes v1.1.0/go.mod h1:pauEU8UuMFiThe5PB3EO+gO5kx87Me5NvdQDsTuq6cs= +github.com/btcsuite/btcwallet/walletdb v1.3.2/go.mod h1:GZCMPNpUu5KE3ASoVd+k06p/1OW8OwNGCCaNWRto2cQ= github.com/btcsuite/btcwallet/walletdb v1.3.4/go.mod h1:oJDxAEUHVtnmIIBaa22wSBPTVcs6hUp5NKWmI8xDwwU= github.com/btcsuite/btcwallet/walletdb v1.3.5/go.mod h1:oJDxAEUHVtnmIIBaa22wSBPTVcs6hUp5NKWmI8xDwwU= github.com/btcsuite/btcwallet/walletdb v1.3.6-0.20210803004036-eebed51155ec h1:zcAU3Ij8SmqaE+ITtS76fua2Niq7DRNp46sJRhi8PiI= github.com/btcsuite/btcwallet/walletdb v1.3.6-0.20210803004036-eebed51155ec/go.mod h1:oJDxAEUHVtnmIIBaa22wSBPTVcs6hUp5NKWmI8xDwwU= +github.com/btcsuite/btcwallet/wtxmgr v1.2.0/go.mod h1:h8hkcKUE3X7lMPzTUoGnNiw5g7VhGrKEW3KpR2r0VnY= github.com/btcsuite/btcwallet/wtxmgr v1.3.0/go.mod h1:awQsh1n/0ZrEQ+JZgWvHeo153ubzEisf/FyNtwI0dDk= github.com/btcsuite/btcwallet/wtxmgr v1.3.1-0.20210822222949-9b5a201c344c h1:owWPexGfK4eSK4/Zy+XK2lET5qsnW7FRAc8OCOdD0Fg= github.com/btcsuite/btcwallet/wtxmgr v1.3.1-0.20210822222949-9b5a201c344c/go.mod h1:UM38ixX8VwJ9qey4umf//0H3ndn5kSImFZ46V54Nd5Q= @@ -145,6 +148,7 @@ github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkE github.com/coreos/bbolt v1.3.3 h1:n6AiVyVRKQFNb6mJlwESEvvLoDyiTzXX7ORAUlkeBdY= github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.22+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= @@ -181,10 +185,13 @@ github.com/fergusstrange/embedded-postgres v1.10.0 h1:YnwF6xAQYmKLAXXrrRx4rHDLih github.com/fergusstrange/embedded-postgres v1.10.0/go.mod h1:a008U8/Rws5FtIOTGYDYa7beVWsT3qVKyqExqYYjL+c= github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/frankban/quicktest v1.0.0/go.mod h1:R98jIehRai+d1/3Hv2//jOVCTJhW1VBavT6B6CuGq2k= github.com/frankban/quicktest v1.2.2/go.mod h1:Qh/WofXFeiAFII1aEBu529AtJo6Zg2VHscnEsbBnJ20= github.com/frankban/quicktest v1.11.2 h1:mjwHjStlXWibxOohM7HYieIViKyh56mmt3+6viyhDDI= github.com/frankban/quicktest v1.11.2/go.mod h1:K+q6oSqb0W0Ininfk863uOk1lMy69l/P6txr3mVT54s= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -227,6 +234,7 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -372,6 +380,7 @@ github.com/jedib0t/go-pretty v4.3.0+incompatible/go.mod h1:XemHduiw8R651AF9Pt4Fw github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.2.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= @@ -435,14 +444,21 @@ github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.3 h1:v9QZf2Sn6AmjXtQeFpdoq/eaNtYP6IN+7lcrygsIAtg= github.com/lib/pq v1.10.3/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lightninglabs/aperture v0.1.6-beta/go.mod h1:9xl4mx778ZAzrB87nLHMqk+XQcSz8Dx/DypjWzGN1xo= 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 v0.11.0-4/go.mod h1:8/cTKNwgL87NX123gmlv3Xh6p1a7pvzu+40Un3PhHiI= +github.com/lightninglabs/lndclient v0.14.0-5/go.mod h1:2kH9vNoc29ghIkfMjxwSeK8yCxsYfR80XAJ9PU/QWWk= github.com/lightninglabs/neutrino v0.12.1/go.mod h1:GlKninWpRBbL7b8G0oQ36/8downfnFwKsr0hbRA6E/E= github.com/lightninglabs/neutrino v0.13.0 h1:j3PKWEJCwqwMn/qLASz2j0IuCF6AumS9DaM0i0pM/nY= github.com/lightninglabs/neutrino v0.13.0/go.mod h1:GlKninWpRBbL7b8G0oQ36/8downfnFwKsr0hbRA6E/E= +github.com/lightninglabs/pool v0.5.3-alpha h1:Ylyi5evjYM/NRS++qkNPFk4AIY2gIZx72fSiUXOx0Hs= +github.com/lightninglabs/pool v0.5.3-alpha/go.mod h1:U2Q4RpDb7Lj0vP+GD3oF1teLO/mxIOGaAbtBm77EyRQ= +github.com/lightninglabs/pool/auctioneerrpc v1.0.5/go.mod h1:F9uND5Kpj2eYeYe0RLi8IWQHsRjQ88FUp8itkYmX1Mo= github.com/lightninglabs/protobuf-hex-display v1.4.3-hex-display/go.mod h1:2oKOBU042GKFHrdbgGiKax4xVrFiZu51lhacUZQ9MnE= github.com/lightningnetwork/lightning-onion v1.0.2-0.20210520211913-522b799e65b1 h1:h1BsjPzWea790mAXISoiT/qr0JRcixTCDNLmjsDThSw= github.com/lightningnetwork/lightning-onion v1.0.2-0.20210520211913-522b799e65b1/go.mod h1:rigfi6Af/KqsF7Za0hOgcyq2PNH4AN70AaMRxcJkff4= +github.com/lightningnetwork/lnd/cert v1.0.2/go.mod h1:fmtemlSMf5t4hsQmcprSoOykypAPp+9c+0d0iqTScMo= github.com/lightningnetwork/lnd/cert v1.1.0/go.mod h1:3MWXVLLPI0Mg0XETm9fT4N9Vyy/8qQLmaM5589bEggM= github.com/lightningnetwork/lnd/clock v1.0.1/go.mod h1:KnQudQ6w0IAMZi1SgvecLZQZ43ra2vpDNj7H/aasemg= github.com/lightningnetwork/lnd/clock v1.1.0 h1:/yfVAwtPmdx45aQBoXQImeY7sOIEr7IXlImRMBOZ7GQ= @@ -592,6 +608,7 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20200122045848-3419fae592fc/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 h1:uruHq4dN7GR16kFc5fp3d1RIYzJW5onx8Ybykw2YQFA= github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/zbase32 v0.0.0-20160707012821-501572607d02/go.mod h1:tHlrkM198S068ZqfrO6S8HsoJq2bF3ETfTL+kt4tInY= @@ -673,9 +690,11 @@ go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9E go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180723164146-c126467f60eb/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -689,6 +708,7 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= @@ -751,6 +771,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -813,6 +834,7 @@ golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -917,6 +939,7 @@ golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3 h1:L69ShwSZEyCsLKoAxDKeMvLDZkumEe8gXUZAjab0tX8= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= @@ -991,6 +1014,7 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= @@ -1030,8 +1054,9 @@ gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:a gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/macaroon-bakery.v2 v2.0.1 h1:0N1TlEdfLP4HXNCg7MQUMp5XwvOoxk+oe9Owr2cpvsc= gopkg.in/macaroon-bakery.v2 v2.0.1/go.mod h1:B4/T17l+ZWGwxFSZQmlBwp25x+og7OkhETfr3S9MbIA= -gopkg.in/macaroon.v2 v2.0.0 h1:LVWycAfeJBUjCIqfR9gqlo7I8vmiXRr51YEOZ1suop8= gopkg.in/macaroon.v2 v2.0.0/go.mod h1:+I6LnTMkm/uV5ew/0nsulNjL16SK4+C8yDmRUzHR17I= +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/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=