diff --git a/client/asset/bch/bch.go b/client/asset/bch/bch.go index e2a20dcd27..7a4455820c 100644 --- a/client/asset/bch/bch.go +++ b/client/asset/bch/bch.go @@ -6,12 +6,15 @@ package bch import ( "bytes" "encoding/json" + "errors" "fmt" "math" + "path/filepath" "decred.org/dcrdex/client/asset" "decred.org/dcrdex/client/asset/btc" "decred.org/dcrdex/dex" + "decred.org/dcrdex/dex/config" dexbch "decred.org/dcrdex/dex/networks/bch" dexbtc "decred.org/dcrdex/dex/networks/btc" "github.com/btcsuite/btcd/btcec/v2" @@ -19,8 +22,10 @@ import ( "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" "github.com/gcash/bchd/bchec" - bchscript "github.com/gcash/bchd/txscript" + bchchaincfg "github.com/gcash/bchd/chaincfg" + bchtxscript "github.com/gcash/bchd/txscript" bchwire "github.com/gcash/bchd/wire" + "github.com/gcash/bchwallet/wallet" ) const ( @@ -33,6 +38,7 @@ const ( defaultFee = 100 minNetworkVersion = 221100 walletTypeRPC = "bitcoindRPC" + walletTypeSPV = "SPV" walletTypeLegacy = "" walletTypeElectrum = "electrumRPC" ) @@ -43,66 +49,30 @@ var ( Testnet: "28332", Simnet: "18443", } - fallbackFeeKey = "fallbackfee" - walletNameOpt = []*asset.ConfigOption{ // slice for easy appends - { - Key: "walletname", - DisplayName: "Wallet Name", - Description: "The wallet name", - }, - } - commonOpts = []*asset.ConfigOption{ - { - Key: "rpcuser", - DisplayName: "JSON-RPC Username", - Description: "Bitcoin Cash 'rpcuser' setting", - }, - { - Key: "rpcpassword", - DisplayName: "JSON-RPC Password", - Description: "Bitcoin Cash 'rpcpassword' setting", - NoEcho: true, - }, - { - Key: "rpcbind", - DisplayName: "JSON-RPC Address", - Description: " or : (default 'localhost')", - }, - { - Key: "rpcport", - DisplayName: "JSON-RPC Port", - Description: "Port for RPC connections (if not set in Address)", - }, - { - Key: fallbackFeeKey, - DisplayName: "Fallback fee rate", - Description: "Bitcoin Cash 'fallbackfee' rate. Units: BCH/kB", - DefaultValue: defaultFee * 1000 / 1e8, - }, - { - Key: "txsplit", - DisplayName: "Pre-split funding inputs", - Description: "When placing an order, create a \"split\" transaction to fund the order without locking more of the wallet balance than " + - "necessary. Otherwise, excess funds may be reserved to fund the order until the first swap contract is broadcast " + - "during match settlement, or the order is canceled. This an extra transaction for which network mining fees are paid. " + - "Used only for standing-type orders, e.g. limit orders without immediate time-in-force.", - IsBoolean: true, - }, - } + rpcWalletDefinition = &asset.WalletDefinition{ Type: walletTypeRPC, - Tab: "Bitcoin Cash Node (external)", - Description: "Connect to bitcoind (the BCH fork)", + Tab: "External", + Description: "Connect to bitcoind", DefaultConfigPath: dexbtc.SystemConfigPath("bitcoin"), // Same as bitcoin. That's dumb. - ConfigOpts: append(walletNameOpt, commonOpts...), + ConfigOpts: append(btc.RPCConfigOpts("Bitcoin Cash", ""), btc.CommonConfigOpts("BCH")...), } + spvWalletDefinition = &asset.WalletDefinition{ + Type: walletTypeSPV, + Tab: "Native", + Description: "Use the built-in SPV wallet", + ConfigOpts: append(btc.SPVConfigOpts("BCH"), btc.CommonConfigOpts("BCH")...), + Seeded: true, + } + electrumWalletDefinition = &asset.WalletDefinition{ Type: walletTypeElectrum, Tab: "Electron Cash (external)", Description: "Use an external Electron Cash (BCH Electrum fork) Wallet", // json: DefaultConfigPath: filepath.Join(btcutil.AppDataDir("electrom-cash", false), "config"), // maybe? - ConfigOpts: commonOpts, + ConfigOpts: btc.CommonConfigOpts("BCH"), } + // WalletInfo defines some general information about a Bitcoin Cash wallet. WalletInfo = &asset.WalletInfo{ Name: "Bitcoin Cash", @@ -110,6 +80,7 @@ var ( // Same as bitcoin. That's dumb. UnitInfo: dexbch.UnitInfo, AvailableWallets: []*asset.WalletDefinition{ + spvWalletDefinition, rpcWalletDefinition, // electrumWalletDefinition, // getinfo RPC needs backport: https://github.com/Electron-Cash/Electron-Cash/pull/2399 }, @@ -143,17 +114,66 @@ func (d *Driver) Info() *asset.WalletInfo { return WalletInfo } +// Exists checks the existence of the wallet. Part of the Creator interface, so +// only used for wallets with WalletDefinition.Seeded = true. +func (d *Driver) Exists(walletType, dataDir string, settings map[string]string, net dex.Network) (bool, error) { + if walletType != walletTypeSPV { + return false, fmt.Errorf("no Bitcoin Cash wallet of type %q available", walletType) + } + + chainParams, err := parseChainParams(net) + if err != nil { + return false, err + } + netDir := filepath.Join(dataDir, chainParams.Name, "spv") + // recoverWindow argument borrowed from bchwallet directly. + loader := wallet.NewLoader(chainParams, netDir, true, 250) + return loader.WalletExists() +} + +// Create creates a new SPV wallet. +func (d *Driver) Create(params *asset.CreateWalletParams) error { + if params.Type != walletTypeSPV { + return fmt.Errorf("SPV is the only seeded wallet type. required = %q, requested = %q", walletTypeSPV, params.Type) + } + if len(params.Seed) == 0 { + return errors.New("wallet seed cannot be empty") + } + if len(params.DataDir) == 0 { + return errors.New("must specify wallet data directory") + } + chainParams, err := parseChainParams(params.Net) + if err != nil { + return fmt.Errorf("error parsing chain: %w", err) + } + + walletCfg := new(btc.WalletConfig) + err = config.Unmapify(params.Settings, walletCfg) + if err != nil { + return err + } + + recoveryCfg := new(btc.RecoveryCfg) + err = config.Unmapify(params.Settings, recoveryCfg) + if err != nil { + return err + } + + return createSPVWallet(params.Pass, params.Seed, walletCfg.AdjustedBirthday(), params.DataDir, + params.Logger, recoveryCfg.NumExternalAddresses, recoveryCfg.NumInternalAddresses, chainParams) +} + // NewWallet is the exported constructor by which the DEX will import the // exchange wallet. func NewWallet(cfg *asset.WalletConfig, logger dex.Logger, network dex.Network) (asset.Wallet, error) { - var params *chaincfg.Params + var cloneParams *chaincfg.Params switch network { case dex.Mainnet: - params = dexbch.MainNetParams + cloneParams = dexbch.MainNetParams case dex.Testnet: - params = dexbch.TestNet4Params + cloneParams = dexbch.TestNet4Params case dex.Regtest: - params = dexbch.RegressionNetParams + cloneParams = dexbch.RegressionNetParams default: return nil, fmt.Errorf("unknown network ID %v", network) } @@ -168,11 +188,11 @@ func NewWallet(cfg *asset.WalletConfig, logger dex.Logger, network dex.Network) Symbol: "bch", Logger: logger, Network: network, - ChainParams: params, + ChainParams: cloneParams, Ports: netPorts, DefaultFallbackFee: defaultFee, Segwit: false, - LegacyBalance: true, + LegacyBalance: cfg.Type != walletTypeSPV, LegacySendToAddr: true, // Bitcoin Cash uses the Cash Address encoding, which is Bech32, but not // indicative of segwit. We provide a custom encoder and decode to go @@ -203,9 +223,10 @@ func NewWallet(cfg *asset.WalletConfig, logger dex.Logger, network dex.Network) // cloneCFG.LegacyBalance = false // cloneCFG.Ports = dexbtc.NetPorts{} // no default ports for Electrum wallet // return btc.ElectrumWallet(cloneCFG) - default: - return nil, fmt.Errorf("unknown wallet type %q", cfg.Type) + case walletTypeSPV: + return btc.OpenSPVWallet(cloneCFG, openSPVWallet) } + return nil, fmt.Errorf("wallet type %q not known", cfg.Type) } // rawTxSigner signs the transaction using Bitcoin Cash's custom signature @@ -220,7 +241,7 @@ func rawTxInSigner(btcTx *wire.MsgTx, idx int, subScript []byte, hashType txscri bchKey, _ := bchec.PrivKeyFromBytes(bchec.S256(), btcKey.Serialize()) - return bchscript.RawTxInECDSASignature(bchTx, idx, subScript, bchscript.SigHashType(uint32(hashType)), bchKey, vals[idx]) + return bchtxscript.RawTxInECDSASignature(bchTx, idx, subScript, bchtxscript.SigHashType(uint32(hashType)), bchKey, vals[idx]) } // serializeBtcTx serializes the wire.MsgTx. @@ -266,3 +287,15 @@ func translateTx(btcTx *wire.MsgTx) (*bchwire.MsgTx, error) { return bchTx, nil } + +func parseChainParams(net dex.Network) (*bchchaincfg.Params, error) { + switch net { + case dex.Mainnet: + return &bchchaincfg.MainNetParams, nil + case dex.Testnet: + return &bchchaincfg.TestNet4Params, nil + case dex.Regtest: + return &bchchaincfg.RegressionNetParams, nil + } + return nil, fmt.Errorf("unknown network ID %v", net) +} diff --git a/client/asset/bch/spv.go b/client/asset/bch/spv.go new file mode 100644 index 0000000000..667c77885a --- /dev/null +++ b/client/asset/bch/spv.go @@ -0,0 +1,1037 @@ +// This code is available on the terms of the project LICENSE.md file, +// also available online at https://blueoakcouncil.org/license/1.0.0. + +package bch + +import ( + "bytes" + "context" + "errors" + "fmt" + "os" + "path/filepath" + "sync/atomic" + "time" + + "decred.org/dcrdex/client/asset" + "decred.org/dcrdex/client/asset/btc" + "decred.org/dcrdex/dex" + "decred.org/dcrdex/dex/config" + dexbch "decred.org/dcrdex/dex/networks/bch" + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcjson" + "github.com/btcsuite/btcd/btcutil" + "github.com/btcsuite/btcd/btcutil/gcs" + "github.com/btcsuite/btcd/btcutil/psbt" + "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/wire" + "github.com/btcsuite/btcwallet/waddrmgr" + btcwallet "github.com/btcsuite/btcwallet/wallet" + "github.com/btcsuite/btcwallet/wtxmgr" + neutrino "github.com/dcrlabs/neutrino-bch" + labschain "github.com/dcrlabs/neutrino-bch/chain" + "github.com/decred/slog" + "github.com/gcash/bchd/bchec" + bchchaincfg "github.com/gcash/bchd/chaincfg" + bchchainhash "github.com/gcash/bchd/chaincfg/chainhash" + bchtxscript "github.com/gcash/bchd/txscript" + bchwire "github.com/gcash/bchd/wire" + "github.com/gcash/bchlog" + "github.com/gcash/bchutil" + "github.com/gcash/bchwallet/chain" + bchwaddrmgr "github.com/gcash/bchwallet/waddrmgr" + "github.com/gcash/bchwallet/wallet" + "github.com/gcash/bchwallet/wallet/txauthor" + "github.com/gcash/bchwallet/walletdb" + _ "github.com/gcash/bchwallet/walletdb/bdb" + bchwtxmgr "github.com/gcash/bchwallet/wtxmgr" + "github.com/jrick/logrotate/rotator" + btcneutrino "github.com/lightninglabs/neutrino" + "github.com/lightninglabs/neutrino/headerfs" +) + +const ( + DefaultM uint64 = 784931 // From bchutil. Used for gcs filters. + logDirName = "logs" + neutrinoDBName = "neutrino.db" + defaultAcctNum = 0 +) + +var ( + waddrmgrNamespace = []byte("waddrmgr") + wtxmgrNamespace = []byte("wtxmgr") +) + +// bchSPVWallet is an implementation of btc.BTCWallet that runs a native Bitcoin +// Cash SPV Wallet. bchSPVWallet mostly just translates types from the btcsuite +// types to gcash and vice-versa. Startup and shutdown are notable exceptions, +// and have some critical code that needed to be duplicated (in order to avoid +// interface hell). +type bchSPVWallet struct { + // This section is populated in openSPVWallet. + dir string + chainParams *bchchaincfg.Params + btcParams *chaincfg.Params + log dex.Logger + birthdayV atomic.Value // time.Time + allowAutomaticRescan bool + + // This section is populated in Start. + *wallet.Wallet + chainClient *labschain.NeutrinoClient + cl *neutrino.ChainService + loader *wallet.Loader + neutrinoDB walletdb.DB +} + +var _ btc.BTCWallet = (*bchSPVWallet)(nil) + +// openSPVWallet creates a bchSPVWallet, but does not Start. +// Satisfies btc.BTCWalletConstructor. +func openSPVWallet(dir string, cfg *btc.WalletConfig, btcParams *chaincfg.Params, log dex.Logger) btc.BTCWallet { + var bchParams *bchchaincfg.Params + switch btcParams.Name { + case dexbch.MainNetParams.Name: + bchParams = &bchchaincfg.MainNetParams + case dexbch.TestNet4Params.Name: + bchParams = &bchchaincfg.TestNet4Params + case dexbch.RegressionNetParams.Name: + bchParams = &bchchaincfg.RegressionNetParams + } + + w := &bchSPVWallet{ + dir: dir, + chainParams: bchParams, + btcParams: btcParams, + log: log, + allowAutomaticRescan: !cfg.ActivelyUsed, + } + w.birthdayV.Store(cfg.AdjustedBirthday()) + return w +} + +// createSPVWallet creates a new SPV wallet. +func createSPVWallet(privPass []byte, seed []byte, bday time.Time, dbDir string, log dex.Logger, extIdx, intIdx uint32, net *bchchaincfg.Params) error { + netDir := filepath.Join(dbDir, net.Name, "spv") + + if err := logNeutrino(netDir, log); err != nil { + return fmt.Errorf("error initializing bchwallet+neutrino logging: %w", err) + } + + logDir := filepath.Join(netDir, logDirName) + err := os.MkdirAll(logDir, 0744) + if err != nil { + return fmt.Errorf("error creating wallet directories: %w", err) + } + + loader := wallet.NewLoader(net, netDir, true, 250) + + pubPass := []byte(wallet.InsecurePubPassphrase) + + btcw, err := loader.CreateNewWallet(pubPass, privPass, seed, bday) + if err != nil { + return fmt.Errorf("CreateNewWallet error: %w", err) + } + + errCloser := dex.NewErrorCloser(log) + defer errCloser.Done() + errCloser.Add(loader.UnloadWallet) + + if extIdx > 0 || intIdx > 0 { + err = extendAddresses(extIdx, intIdx, btcw) + if err != nil { + return fmt.Errorf("failed to set starting address indexes: %w", err) + } + } + + // The chain service DB + neutrinoDBPath := filepath.Join(netDir, neutrinoDBName) + db, err := walletdb.Create("bdb", neutrinoDBPath, true) + if err != nil { + return fmt.Errorf("unable to create neutrino db at %q: %w", neutrinoDBPath, err) + } + if err = db.Close(); err != nil { + return fmt.Errorf("error closing newly created wallet database: %w", err) + } + + if err := loader.UnloadWallet(); err != nil { + return fmt.Errorf("error unloading wallet: %w", err) + } + + errCloser.Success() + return nil +} + +// Start initializes the *bchwallet.Wallet and its supporting players and starts +// syncing. +func (w *bchSPVWallet) Start() (btc.SPVService, error) { + if err := logNeutrino(w.dir, w.log); err != nil { + return nil, fmt.Errorf("error initializing bchwallet+neutrino logging: %v", err) + } + // recoverWindow arguments borrowed from bchwallet directly. + w.loader = wallet.NewLoader(w.chainParams, w.dir, true, 250) + + exists, err := w.loader.WalletExists() + if err != nil { + return nil, fmt.Errorf("error verifying wallet existence: %v", err) + } + if !exists { + return nil, errors.New("wallet not found") + } + + w.log.Debug("Starting native BCH wallet...") + w.Wallet, err = w.loader.OpenExistingWallet([]byte(wallet.InsecurePubPassphrase), false) + if err != nil { + return nil, fmt.Errorf("couldn't load wallet: %w", err) + } + + errCloser := dex.NewErrorCloser(w.log) + defer errCloser.Done() + errCloser.Add(w.loader.UnloadWallet) + + neutrinoDBPath := filepath.Join(w.dir, neutrinoDBName) + w.neutrinoDB, err = walletdb.Create("bdb", neutrinoDBPath, true) + if err != nil { + return nil, fmt.Errorf("unable to create wallet db at %q: %v", neutrinoDBPath, err) + } + errCloser.Add(w.neutrinoDB.Close) + + // Depending on the network, we add some addpeers or a connect peer. On + // regtest, if the peers haven't been explicitly set, add the simnet harness + // alpha node as an additional peer so we don't have to type it in. On + // mainet and testnet4, add a known reliable persistent peer to be used in + // addition to normal DNS seed-based peer discovery. + var addPeers []string + var connectPeers []string + switch w.chainParams.Net { + // case bchwire.MainNet: + // addPeers = []string{"cfilters.ssgen.io"} + case bchwire.TestNet4: + // Add the address for a local bchd testnet4 node. + addPeers = []string{"localhost:28333"} + case bchwire.TestNet, bchwire.SimNet: // plain "wire.TestNet" is regnet! + connectPeers = []string{"localhost:21577"} + } + + w.log.Debug("Starting neutrino chain service...") + w.cl, err = neutrino.NewChainService(neutrino.Config{ + DataDir: w.dir, + Database: w.neutrinoDB, + ChainParams: *w.chainParams, + // https://github.com/gcash/neutrino/pull/36 + PersistToDisk: true, // keep cfilter headers on disk for efficient rescanning + AddPeers: addPeers, + ConnectPeers: connectPeers, + // WARNING: PublishTransaction currently uses the entire duration + // because if an external bug, but even if the bug is resolved, a + // typical inv/getdata round trip is ~4 seconds, so we set this so + // neutrino does not cancel queries too readily. + BroadcastTimeout: 6 * time.Second, + }) + if err != nil { + return nil, fmt.Errorf("couldn't create Neutrino ChainService: %v", err) + } + errCloser.Add(w.cl.Stop) + + w.chainClient = labschain.NewNeutrinoClient(w.chainParams, w.cl, &logAdapter{w.log}) + + oldBday := w.Manager.Birthday() + + performRescan := w.Birthday().Before(oldBday) + if performRescan && !w.allowAutomaticRescan { + return nil, errors.New("cannot set earlier birthday while there are active deals") + } + + if !oldBday.Equal(w.Birthday()) { + if err := w.updateDBBirthday(w.Birthday()); err != nil { + w.log.Errorf("Failed to reset wallet manager birthday: %v", err) + performRescan = false + } + } + + if performRescan { + w.ForceRescan() + } + + if err = w.chainClient.Start(); err != nil { // lazily starts connmgr + return nil, fmt.Errorf("couldn't start Neutrino client: %v", err) + } + + w.log.Info("Synchronizing wallet with network...") + w.SynchronizeRPC(w.chainClient) + + errCloser.Success() + + return &spvService{w.cl}, nil +} + +func (w *bchSPVWallet) txDetails(txHash *bchchainhash.Hash) (*bchwtxmgr.TxDetails, error) { + details, err := wallet.UnstableAPI(w.Wallet).TxDetails(txHash) + if err != nil { + return nil, err + } + if details == nil { + return nil, btc.WalletTransactionNotFound + } + + return details, nil +} + +var _ btc.BTCWallet = (*bchSPVWallet)(nil) + +func (w *bchSPVWallet) PublishTransaction(btcTx *wire.MsgTx, label string) error { + bchTx, err := convertMsgTxToBCH(btcTx) + if err != nil { + return err + } + return w.Wallet.PublishTransaction(bchTx) +} + +func (w *bchSPVWallet) CalculateAccountBalances(account uint32, confirms int32) (btcwallet.Balances, error) { + bals, err := w.Wallet.CalculateAccountBalances(account, confirms) + if err != nil { + return btcwallet.Balances{}, err + } + return btcwallet.Balances{ + Total: btcutil.Amount(bals.Total), + Spendable: btcutil.Amount(bals.Spendable), + ImmatureReward: btcutil.Amount(bals.ImmatureReward), + }, nil +} + +func (w *bchSPVWallet) ListUnspent(minconf, maxconf int32, acctName string) ([]*btcjson.ListUnspentResult, error) { + // bchwallet's ListUnspent takes either a list of addresses, or else returns + // all non-locked unspent outputs for all accounts. We need to iterate the + // results anyway to convert type. + uns, err := w.Wallet.ListUnspent(minconf, maxconf, nil) + if err != nil { + return nil, err + } + + outs := make([]*btcjson.ListUnspentResult, len(uns)) + for i, u := range uns { + if u.Account != acctName { + continue + } + outs[i] = &btcjson.ListUnspentResult{ + TxID: u.TxID, + Vout: u.Vout, + Address: u.Address, + Account: u.Account, + ScriptPubKey: u.ScriptPubKey, + RedeemScript: u.RedeemScript, + Amount: u.Amount, + Confirmations: u.Confirmations, + Spendable: u.Spendable, + } + } + + return outs, nil +} + +// FetchInputInfo is not actually implemented in bchwallet. This is based on the +// btcwallet implementation. As this is used by btc.spvWallet, we really only +// need the TxOut, and to show ownership. +func (w *bchSPVWallet) FetchInputInfo(prevOut *wire.OutPoint) (*wire.MsgTx, *wire.TxOut, *psbt.Bip32Derivation, int64, error) { + + td, err := w.txDetails((*bchchainhash.Hash)(&prevOut.Hash)) + if err != nil { + return nil, nil, nil, 0, err + } + + if prevOut.Index >= uint32(len(td.TxRecord.MsgTx.TxOut)) { + return nil, nil, nil, 0, fmt.Errorf("not enough outputs") + } + + bchTxOut := td.TxRecord.MsgTx.TxOut[prevOut.Index] + + // Verify we own at least one parsed address. + _, addrs, _, err := bchtxscript.ExtractPkScriptAddrs(bchTxOut.PkScript, w.chainParams) + if err != nil { + return nil, nil, nil, 0, err + } + notOurs := true + for i := 0; notOurs && i < len(addrs); i++ { + _, err := w.Wallet.AddressInfo(addrs[i]) + notOurs = err != nil + } + if notOurs { + return nil, nil, nil, 0, btcwallet.ErrNotMine + } + + btcTxOut := &wire.TxOut{ + Value: bchTxOut.Value, + PkScript: bchTxOut.PkScript, + } + + return nil, btcTxOut, nil, 0, nil +} + +func (w *bchSPVWallet) LockOutpoint(op wire.OutPoint) { + w.Wallet.LockOutpoint(bchwire.OutPoint{ + Hash: bchchainhash.Hash(op.Hash), + Index: op.Index, + }) +} + +func (w *bchSPVWallet) UnlockOutpoint(op wire.OutPoint) { + w.Wallet.UnlockOutpoint(bchwire.OutPoint{ + Hash: bchchainhash.Hash(op.Hash), + Index: op.Index, + }) +} + +func (w *bchSPVWallet) LockedOutpoints() []btcjson.TransactionInput { + locks := w.Wallet.LockedOutpoints() + locked := make([]btcjson.TransactionInput, len(locks)) + for i, lock := range locks { + locked[i] = btcjson.TransactionInput{ + Txid: lock.Txid, + Vout: lock.Vout, + } + } + return locked +} + +func (w *bchSPVWallet) NewChangeAddress(account uint32, _ waddrmgr.KeyScope) (btcutil.Address, error) { + bchAddr, err := w.Wallet.NewChangeAddress(account, bchwaddrmgr.KeyScopeBIP0044) + if err != nil { + return nil, err + } + return dexbch.DecodeCashAddress(bchAddr.String(), w.btcParams) +} + +func (w *bchSPVWallet) NewAddress(account uint32, _ waddrmgr.KeyScope) (btcutil.Address, error) { + bchAddr, err := w.Wallet.NewAddress(account, bchwaddrmgr.KeyScopeBIP0044) + if err != nil { + return nil, err + } + return dexbch.DecodeCashAddress(bchAddr.String(), w.btcParams) +} + +func (w *bchSPVWallet) PrivKeyForAddress(a btcutil.Address) (*btcec.PrivateKey, error) { + bchAddr, err := dexbch.BTCAddrToBCHAddr(a, w.btcParams) + if err != nil { + return nil, err + } + bchKey, err := w.Wallet.PrivKeyForAddress(bchAddr) + if err != nil { + return nil, err + } + + priv, _ /* pub */ := btcec.PrivKeyFromBytes(bchKey.Serialize()) + return priv, nil +} + +func (w *bchSPVWallet) SendOutputs(outputs []*wire.TxOut, _ *waddrmgr.KeyScope, account uint32, minconf int32, + satPerKb btcutil.Amount, _ btcwallet.CoinSelectionStrategy, label string) (*wire.MsgTx, error) { + + bchOuts := make([]*bchwire.TxOut, len(outputs)) + for i, op := range outputs { + bchOuts[i] = &bchwire.TxOut{ + Value: op.Value, + PkScript: op.PkScript, + } + } + + bchTx, err := w.Wallet.SendOutputs(bchOuts, account, minconf, bchutil.Amount(satPerKb)) + if err != nil { + return nil, err + } + + btcTx, err := convertMsgTxToBTC(bchTx) + if err != nil { + return nil, err + } + + return btcTx, nil +} + +func (w *bchSPVWallet) HaveAddress(a btcutil.Address) (bool, error) { + bchAddr, err := dexbch.BTCAddrToBCHAddr(a, w.btcParams) + if err != nil { + return false, err + } + + return w.Wallet.HaveAddress(bchAddr) +} + +func (w *bchSPVWallet) Stop() { + w.log.Info("Unloading wallet") + if err := w.loader.UnloadWallet(); err != nil { + w.log.Errorf("UnloadWallet error: %v", err) + } + if w.chainClient != nil { + w.log.Trace("Stopping neutrino client chain interface") + w.chainClient.Stop() + w.chainClient.WaitForShutdown() + } + w.log.Trace("Stopping neutrino chain sync service") + if err := w.cl.Stop(); err != nil { + w.log.Errorf("error stopping neutrino chain service: %v", err) + } + w.log.Trace("Stopping neutrino DB.") + if err := w.neutrinoDB.Close(); err != nil { + w.log.Errorf("wallet db close error: %v", err) + } + + w.log.Info("SPV wallet closed") +} + +func (w *bchSPVWallet) AccountProperties(_ waddrmgr.KeyScope, acct uint32) (*waddrmgr.AccountProperties, error) { + props, err := w.Wallet.AccountProperties(bchwaddrmgr.KeyScopeBIP0044, acct) + if err != nil { + return nil, err + } + return &waddrmgr.AccountProperties{ + // bch only has a subset of the btc AccountProperties. We'll give + // everything we have. The only two that are actually used are these + // first to fields. + ExternalKeyCount: props.ExternalKeyCount, + InternalKeyCount: props.InternalKeyCount, + AccountNumber: props.AccountNumber, + AccountName: props.AccountName, + ImportedKeyCount: props.ImportedKeyCount, + }, nil +} + +func (w *bchSPVWallet) RescanAsync() error { + w.log.Info("Stopping wallet and chain client...") + w.Wallet.Stop() // stops Wallet and chainClient (not chainService) + w.Wallet.WaitForShutdown() + w.chainClient.WaitForShutdown() + + w.ForceRescan() + + w.log.Info("Starting wallet...") + w.Wallet.Start() + + if err := w.chainClient.Start(); err != nil { + return fmt.Errorf("couldn't start Neutrino client: %v", err) + } + + w.log.Info("Synchronizing wallet with network...") + w.Wallet.SynchronizeRPC(w.chainClient) + return nil +} + +// ForceRescan forces a full rescan with active address discovery on wallet +// restart by dropping the complete transaction history and setting the +// "synced to" field to nil. See the btcwallet/cmd/dropwtxmgr app for more +// information. +func (w *bchSPVWallet) ForceRescan() { + w.log.Info("Dropping transaction history to perform full rescan...") + err := w.dropTransactionHistory() + if err != nil { + w.log.Errorf("Failed to drop wallet transaction history: %v", err) + // Continue to attempt restarting the wallet anyway. + } + + err = walletdb.Update(w.Database(), func(dbtx walletdb.ReadWriteTx) error { + ns := dbtx.ReadWriteBucket(waddrmgrNamespace) // it'll be fine + return w.Manager.SetSyncedTo(ns, nil) // never synced, forcing recover from birthday + }) + if err != nil { + w.log.Errorf("Failed to reset wallet manager sync height: %v", err) + } +} + +// dropTransactionHistory drops the transaction history. It is based off of the +// dropwtxmgr utility in the bchwallet repo. +func (w *bchSPVWallet) dropTransactionHistory() error { + w.log.Info("Dropping wallet transaction history") + + return walletdb.Update(w.Database(), func(tx walletdb.ReadWriteTx) error { + err := tx.DeleteTopLevelBucket(wtxmgrNamespace) + if err != nil && err != walletdb.ErrBucketNotFound { + return err + } + ns, err := tx.CreateTopLevelBucket(wtxmgrNamespace) + if err != nil { + return err + } + err = bchwtxmgr.Create(ns) + if err != nil { + return err + } + + ns = tx.ReadWriteBucket(waddrmgrNamespace) + birthdayBlock, err := bchwaddrmgr.FetchBirthdayBlock(ns) + if err != nil { + fmt.Println("Wallet does not have a birthday block " + + "set, falling back to rescan from genesis") + + startBlock, err := bchwaddrmgr.FetchStartBlock(ns) + if err != nil { + return err + } + return bchwaddrmgr.PutSyncedTo(ns, startBlock) + } + + // We'll need to remove our birthday block first because it + // serves as a barrier when updating our state to detect reorgs + // due to the wallet not storing all block hashes of the chain. + if err := bchwaddrmgr.DeleteBirthdayBlock(ns); err != nil { + return err + } + + if err := bchwaddrmgr.PutSyncedTo(ns, &birthdayBlock); err != nil { + return err + } + return bchwaddrmgr.PutBirthdayBlock(ns, birthdayBlock) + }) +} + +func (w *bchSPVWallet) WalletTransaction(txHash *chainhash.Hash) (*wtxmgr.TxDetails, error) { + txDetails, err := w.txDetails((*bchchainhash.Hash)(txHash)) + if err != nil { + return nil, err + } + + btcTx, err := convertMsgTxToBTC(&txDetails.MsgTx) + if err != nil { + return nil, err + } + + credits := make([]wtxmgr.CreditRecord, len(txDetails.Credits)) + for i, c := range txDetails.Credits { + credits[i] = wtxmgr.CreditRecord{ + Amount: btcutil.Amount(c.Amount), + Index: c.Index, + Spent: c.Spent, + Change: c.Change, + } + } + + debits := make([]wtxmgr.DebitRecord, len(txDetails.Debits)) + for i, d := range txDetails.Debits { + debits[i] = wtxmgr.DebitRecord{ + Amount: btcutil.Amount(d.Amount), + Index: d.Index, + } + } + + return &wtxmgr.TxDetails{ + TxRecord: wtxmgr.TxRecord{ + MsgTx: *btcTx, + Hash: chainhash.Hash(txDetails.TxRecord.Hash), + Received: txDetails.TxRecord.Received, + SerializedTx: txDetails.TxRecord.SerializedTx, + }, + Block: wtxmgr.BlockMeta{ + Block: wtxmgr.Block{ + Hash: chainhash.Hash(txDetails.Block.Hash), + Height: txDetails.Block.Height, + }, + Time: txDetails.Block.Time, + }, + Credits: credits, + Debits: debits, + }, nil +} + +func (w *bchSPVWallet) SyncedTo() waddrmgr.BlockStamp { + bs := w.Manager.SyncedTo() + return waddrmgr.BlockStamp{ + Height: bs.Height, + Hash: chainhash.Hash(bs.Hash), + Timestamp: bs.Timestamp, + } + +} + +func (w *bchSPVWallet) SignTx(btcTx *wire.MsgTx) error { + bchTx, err := convertMsgTxToBCH(btcTx) + if err != nil { + return err + } + + var prevPkScripts [][]byte + var inputValues []bchutil.Amount + for _, txIn := range btcTx.TxIn { + _, txOut, _, _, err := w.FetchInputInfo(&txIn.PreviousOutPoint) + if err != nil { + return err + } + inputValues = append(inputValues, bchutil.Amount(txOut.Value)) + prevPkScripts = append(prevPkScripts, txOut.PkScript) + // Zero the previous witness and signature script or else + // AddAllInputScripts does some weird stuff. + txIn.SignatureScript = nil + txIn.Witness = nil + } + + err = txauthor.AddAllInputScripts(bchTx, prevPkScripts, inputValues, &secretSource{w.Wallet, w.chainParams}) + if err != nil { + return err + } + + if len(bchTx.TxIn) != len(btcTx.TxIn) { + return fmt.Errorf("txin count mismatch") + } + for i, txIn := range btcTx.TxIn { + txIn.SignatureScript = bchTx.TxIn[i].SignatureScript + } + return nil +} + +// BlockNotifications returns a channel on which to receive notifications of +// newly processed blocks. The caller should only call BlockNotificaitons once. +func (w *bchSPVWallet) BlockNotifications(ctx context.Context) <-chan *btc.BlockNotification { + cl := w.NtfnServer.TransactionNotifications() + ch := make(chan *btc.BlockNotification, 1) + go func() { + defer cl.Done() + for { + select { + case note := <-cl.C: + if len(note.AttachedBlocks) > 0 { + lastBlock := note.AttachedBlocks[len(note.AttachedBlocks)-1] + select { + case ch <- &btc.BlockNotification{ + Hash: chainhash.Hash(*lastBlock.Hash), + Height: lastBlock.Height, + }: + default: + } + } + case <-ctx.Done(): + return + } + } + }() + return ch +} + +func (w *bchSPVWallet) Birthday() time.Time { + return w.birthdayV.Load().(time.Time) +} + +func (w *bchSPVWallet) Reconfigure(cfg *asset.WalletConfig, _ /* oldAddress */ string) (restart bool, err error) { + parsedCfg := new(btc.WalletConfig) + if err = config.Unmapify(cfg.Settings, parsedCfg); err != nil { + return + } + + newBday := parsedCfg.AdjustedBirthday() + if newBday.Equal(w.Birthday()) { + // It's the only setting we care about. + return + } + rescanRequired := newBday.Before(w.Birthday()) + if rescanRequired && parsedCfg.ActivelyUsed { + return false, errors.New("cannot decrease the birthday with active orders") + } + if err := w.updateDBBirthday(newBday); err != nil { + return false, fmt.Errorf("error storing new birthday: %w", err) + } + w.birthdayV.Store(newBday) + if rescanRequired { + if err = w.RescanAsync(); err != nil { + return false, fmt.Errorf("error initiating rescan after birthday adjustment: %w", err) + } + } + return +} + +func (w *bchSPVWallet) updateDBBirthday(bday time.Time) error { + btcw, isLoaded := w.loader.LoadedWallet() + if !isLoaded { + return fmt.Errorf("wallet not loaded") + } + return walletdb.Update(btcw.Database(), func(dbtx walletdb.ReadWriteTx) error { + ns := dbtx.ReadWriteBucket(waddrmgrNamespace) + return btcw.Manager.SetBirthday(ns, bday) + }) +} + +// secretSource is used to locate keys and redemption scripts while signing a +// transaction. secretSource satisfies the txauthor.SecretsSource interface. +type secretSource struct { + w *wallet.Wallet + chainParams *bchchaincfg.Params +} + +// ChainParams returns the chain parameters. +func (s *secretSource) ChainParams() *bchchaincfg.Params { + return s.chainParams +} + +// GetKey fetches a private key for the specified address. +func (s *secretSource) GetKey(addr bchutil.Address) (*bchec.PrivateKey, bool, error) { + ma, err := s.w.AddressInfo(addr) + if err != nil { + return nil, false, err + } + + mpka, ok := ma.(bchwaddrmgr.ManagedPubKeyAddress) + if !ok { + e := fmt.Errorf("managed address type for %v is `%T` but "+ + "want waddrmgr.ManagedPubKeyAddress", addr, ma) + return nil, false, e + } + + privKey, err := mpka.PrivKey() + if err != nil { + return nil, false, err + } + + k, _ /* pub */ := bchec.PrivKeyFromBytes(bchec.S256(), privKey.Serialize()) + + return k, ma.Compressed(), nil +} + +// GetScript fetches the redemption script for the specified p2sh/p2wsh address. +func (s *secretSource) GetScript(addr bchutil.Address) ([]byte, error) { + ma, err := s.w.AddressInfo(addr) + if err != nil { + return nil, err + } + + msa, ok := ma.(bchwaddrmgr.ManagedScriptAddress) + if !ok { + e := fmt.Errorf("managed address type for %v is `%T` but "+ + "want waddrmgr.ManagedScriptAddress", addr, ma) + return nil, e + } + return msa.Script() +} + +// spvService embeds gcash neutrino.ChainService and translates types. +type spvService struct { + *neutrino.ChainService +} + +var _ btc.SPVService = (*spvService)(nil) + +func (s *spvService) GetBlockHash(height int64) (*chainhash.Hash, error) { + bchHash, err := s.ChainService.GetBlockHash(height) + if err != nil { + return nil, err + } + return (*chainhash.Hash)(bchHash), nil +} + +func (s *spvService) BestBlock() (*headerfs.BlockStamp, error) { + bs, err := s.ChainService.BestBlock() + if err != nil { + return nil, err + } + return &headerfs.BlockStamp{ + Height: bs.Height, + Hash: chainhash.Hash(bs.Hash), + Timestamp: bs.Timestamp, + }, nil +} + +func (s *spvService) Peers() []btc.SPVPeer { + rawPeers := s.ChainService.Peers() + peers := make([]btc.SPVPeer, len(rawPeers)) + for i, p := range rawPeers { + peers[i] = p + } + return peers +} + +func (s *spvService) GetBlockHeight(h *chainhash.Hash) (int32, error) { + return s.ChainService.GetBlockHeight((*bchchainhash.Hash)(h)) +} + +func (s *spvService) GetBlockHeader(h *chainhash.Hash) (*wire.BlockHeader, error) { + hdr, err := s.ChainService.GetBlockHeader((*bchchainhash.Hash)(h)) + if err != nil { + return nil, err + } + return &wire.BlockHeader{ + Version: hdr.Version, + PrevBlock: chainhash.Hash(hdr.PrevBlock), + MerkleRoot: chainhash.Hash(hdr.MerkleRoot), + Timestamp: hdr.Timestamp, + Bits: hdr.Bits, + Nonce: hdr.Nonce, + }, nil +} + +func (s *spvService) GetCFilter(blockHash chainhash.Hash, filterType wire.FilterType, _ ...btcneutrino.QueryOption) (*gcs.Filter, error) { + f, err := s.ChainService.GetCFilter(bchchainhash.Hash(blockHash), bchwire.GCSFilterRegular) + if err != nil { + return nil, err + } + + b, err := f.Bytes() + if err != nil { + return nil, err + } + + return gcs.FromBytes(f.N(), f.P(), DefaultM, b) +} + +func (s *spvService) GetBlock(blockHash chainhash.Hash, _ ...btcneutrino.QueryOption) (*btcutil.Block, error) { + blk, err := s.ChainService.GetBlock(bchchainhash.Hash(blockHash)) + if err != nil { + return nil, err + } + + b, err := blk.Bytes() + if err != nil { + return nil, err + } + + return btcutil.NewBlockFromBytes(b) +} + +func convertMsgTxToBTC(tx *bchwire.MsgTx) (*wire.MsgTx, error) { + buf := new(bytes.Buffer) + if err := tx.Serialize(buf); err != nil { + return nil, err + } + + btcTx := new(wire.MsgTx) + if err := btcTx.Deserialize(buf); err != nil { + return nil, err + } + return btcTx, nil +} + +func convertMsgTxToBCH(tx *wire.MsgTx) (*bchwire.MsgTx, error) { + buf := new(bytes.Buffer) + if err := tx.Serialize(buf); err != nil { + return nil, err + } + bchTx := new(bchwire.MsgTx) + if err := bchTx.Deserialize(buf); err != nil { + return nil, err + } + return bchTx, nil +} + +func extendAddresses(extIdx, intIdx uint32, bchw *wallet.Wallet) error { + scopedKeyManager, err := bchw.Manager.FetchScopedKeyManager(bchwaddrmgr.KeyScopeBIP0044) + if err != nil { + return err + } + + return walletdb.Update(bchw.Database(), func(dbtx walletdb.ReadWriteTx) error { + ns := dbtx.ReadWriteBucket(waddrmgrNamespace) + if extIdx > 0 { + scopedKeyManager.ExtendExternalAddresses(ns, defaultAcctNum, extIdx) + } + if intIdx > 0 { + scopedKeyManager.ExtendInternalAddresses(ns, defaultAcctNum, intIdx) + } + return nil + }) +} + +var ( + loggingInited uint32 + logFileName = "neutrino.log" +) + +// logWriter implements an io.Writer that outputs to a rotating log file. +type logWriter struct { + *rotator.Rotator +} + +// Write writes the data in p to the log file. +func (w logWriter) Write(p []byte) (n int, err error) { + return w.Rotator.Write(p) +} + +// logRotator initializes a rotating file logger. +func logRotator(netDir string) (*rotator.Rotator, error) { + const maxLogRolls = 8 + logDir := filepath.Join(netDir, logDirName) + if err := os.MkdirAll(logDir, 0744); err != nil { + return nil, fmt.Errorf("error creating log directory: %w", err) + } + + logFilename := filepath.Join(logDir, logFileName) + return rotator.New(logFilename, 32*1024, false, maxLogRolls) +} + +// logNeutrino initializes logging in the neutrino + wallet packages. Logging +// only has to be initialized once, so an atomic flag is used internally to +// return early on subsequent invocations. +// +// In theory, the the rotating file logger must be Close'd at some point, but +// there are concurrency issues with that since btcd and btcwallet have +// unsupervised goroutines still running after shutdown. So we leave the rotator +// running at the risk of losing some logs. +func logNeutrino(netDir string, errorLogger dex.Logger) error { + if !atomic.CompareAndSwapUint32(&loggingInited, 0, 1) { + return nil + } + + logSpinner, err := logRotator(netDir) + if err != nil { + return fmt.Errorf("error initializing log rotator: %w", err) + } + + backendLog := bchlog.NewBackend(logWriter{logSpinner}) + + logger := func(name string, lvl bchlog.Level) bchlog.Logger { + l := backendLog.Logger(name) + l.SetLevel(lvl) + return &fileLoggerPlus{Logger: l, log: errorLogger.SubLogger(name)} + } + + neutrino.UseLogger(logger("NTRNO", bchlog.LevelDebug)) + wallet.UseLogger(logger("BTCW", bchlog.LevelInfo)) + bchwtxmgr.UseLogger(logger("TXMGR", bchlog.LevelInfo)) + chain.UseLogger(logger("CHAIN", bchlog.LevelInfo)) + + return nil +} + +// fileLoggerPlus logs everything to a file, and everything with level >= warn +// to both file and a specified dex.Logger. +type fileLoggerPlus struct { + bchlog.Logger + log dex.Logger +} + +func (f *fileLoggerPlus) Warnf(format string, params ...interface{}) { + f.log.Warnf(format, params...) + f.Logger.Warnf(format, params...) +} + +func (f *fileLoggerPlus) Errorf(format string, params ...interface{}) { + f.log.Errorf(format, params...) + f.Logger.Errorf(format, params...) +} + +func (f *fileLoggerPlus) Criticalf(format string, params ...interface{}) { + f.log.Criticalf(format, params...) + f.Logger.Criticalf(format, params...) +} + +func (f *fileLoggerPlus) Warn(v ...interface{}) { + f.log.Warn(v...) + f.Logger.Warn(v...) +} + +func (f *fileLoggerPlus) Error(v ...interface{}) { + f.log.Error(v...) + f.Logger.Error(v...) +} + +func (f *fileLoggerPlus) Critical(v ...interface{}) { + f.log.Critical(v...) + f.Logger.Critical(v...) +} + +type logAdapter struct { + dex.Logger +} + +var _ bchlog.Logger = (*logAdapter)(nil) + +func (a *logAdapter) Level() bchlog.Level { + return bchlog.Level(a.Logger.Level()) +} + +func (a *logAdapter) SetLevel(lvl bchlog.Level) { + a.Logger.SetLevel(slog.Level(lvl)) +} diff --git a/client/asset/btc/btc.go b/client/asset/btc/btc.go index f3e695358e..4998a79bc7 100644 --- a/client/asset/btc/btc.go +++ b/client/asset/btc/btc.go @@ -98,36 +98,6 @@ var ( peerCountTicker = 5 * time.Second walletBlockAllowance = time.Second * 10 conventionalConversionFactor = float64(dexbtc.UnitInfo.Conventional.ConversionFactor) - rpcOpts = []*asset.ConfigOption{ - { - Key: "walletname", - DisplayName: "Wallet Name", - Description: "The wallet name", - }, - { - Key: "rpcuser", - DisplayName: "JSON-RPC Username", - Description: "Bitcoin's 'rpcuser' setting", - }, - { - Key: "rpcpassword", - DisplayName: "JSON-RPC Password", - Description: "Bitcoin's 'rpcpassword' setting", - NoEcho: true, - }, - { - Key: "rpcbind", - DisplayName: "JSON-RPC Address", - Description: " or : (default 'localhost')", - DefaultValue: "127.0.0.1", - }, - { - Key: "rpcport", - DisplayName: "JSON-RPC Port", - Description: "Port for RPC connections (if not set in rpcbind)", - DefaultValue: "8332", - }, - } electrumOpts = []*asset.ConfigOption{ { @@ -159,37 +129,60 @@ var ( defaultWalletBirthdayUnix = 1622668320 defaultWalletBirthday = time.Unix(int64(defaultWalletBirthdayUnix), 0) - spvOpts = []*asset.ConfigOption{{ - Key: "walletbirthday", - DisplayName: "Wallet Birthday", - Description: "This is the date the wallet starts scanning the blockchain " + - "for transactions related to this wallet. If reconfiguring an existing " + - "wallet, this may start a rescan if the new birthday is older. This " + - "option is disabled if there are currently active BTC trades.", - DefaultValue: defaultWalletBirthdayUnix, - MaxValue: "now", - // This MinValue must be removed if we start supporting importing private keys - MinValue: defaultWalletBirthdayUnix, - IsDate: true, - DisableWhenActive: true, - IsBirthdayConfig: true, - }} + rpcWalletDefinition = &asset.WalletDefinition{ + Type: walletTypeRPC, + Tab: "External", + Description: "Connect to bitcoind", + DefaultConfigPath: dexbtc.SystemConfigPath("bitcoin"), + ConfigOpts: append(RPCConfigOpts("Bitcoin", "8332"), CommonConfigOpts("BTC")...), + } + spvWalletDefinition = &asset.WalletDefinition{ + Type: walletTypeSPV, + Tab: "Native", + Description: "Use the built-in SPV wallet", + ConfigOpts: append(SPVConfigOpts("BTC"), CommonConfigOpts("BTC")...), + Seeded: true, + } - commonOpts = []*asset.ConfigOption{ + electrumWalletDefinition = &asset.WalletDefinition{ + Type: walletTypeElectrum, + Tab: "Electrum (external)", + Description: "Use an external Electrum Wallet", + // json: DefaultConfigPath: filepath.Join(btcutil.AppDataDir("electrum", false), "config"), // e.g. ~/.electrum/config + ConfigOpts: append(electrumOpts, CommonConfigOpts("BTC")...), + } + + // WalletInfo defines some general information about a Bitcoin wallet. + WalletInfo = &asset.WalletInfo{ + Name: "Bitcoin", + Version: version, + UnitInfo: dexbtc.UnitInfo, + AvailableWallets: []*asset.WalletDefinition{ + spvWalletDefinition, + rpcWalletDefinition, + electrumWalletDefinition, + }, + LegacyWalletIndex: 1, + } +) + +// CommonConfigOpts are the common options that the Wallets recognize. +func CommonConfigOpts(symbol string /* upper-case */) []*asset.ConfigOption { + return []*asset.ConfigOption{ { Key: "fallbackfee", DisplayName: "Fallback fee rate", - Description: "The fee rate to use for sending or withdrawing funds and fee payment when" + - " estimatesmartfee is not available. Units: BTC/kB", + Description: fmt.Sprintf("The fee rate to use for sending or withdrawing funds and fee payment when"+ + " estimatesmartfee is not available. Units: %s/kB", symbol), DefaultValue: defaultFee * 1000 / 1e8, }, { Key: "feeratelimit", DisplayName: "Highest acceptable fee rate", - Description: "This is the highest network fee rate you are willing to " + - "pay on swap transactions. If feeratelimit is lower than a market's " + - "maxfeerate, you will not be able to trade on that market with this " + - "wallet. Units: BTC/kB", + Description: fmt.Sprintf("This is the highest network fee rate you are willing to "+ + "pay on swap transactions. If feeratelimit is lower than a market's "+ + "maxfeerate, you will not be able to trade on that market with this "+ + "wallet. Units: %s/kB", symbol), DefaultValue: defaultFeeRateLimit * 1000 / 1e8, }, { @@ -222,43 +215,61 @@ var ( IsBoolean: true, }, } - rpcWalletDefinition = &asset.WalletDefinition{ - Type: walletTypeRPC, - Tab: "Bitcoin Core (external)", - Description: "Connect to bitcoind", - DefaultConfigPath: dexbtc.SystemConfigPath("bitcoin"), - ConfigOpts: append(rpcOpts, commonOpts...), - } - spvWalletDefinition = &asset.WalletDefinition{ - Type: walletTypeSPV, - Tab: "Native", - Description: "Use the built-in SPV wallet", - ConfigOpts: append(spvOpts, commonOpts...), - Seeded: true, - } - electrumWalletDefinition = &asset.WalletDefinition{ - Type: walletTypeElectrum, - Tab: "Electrum (external)", - Description: "Use an external Electrum Wallet", - // json: DefaultConfigPath: filepath.Join(btcutil.AppDataDir("electrum", false), "config"), // e.g. ~/.electrum/config - ConfigOpts: append(electrumOpts, commonOpts...), - } +} - // WalletInfo defines some general information about a Bitcoin wallet. - WalletInfo = &asset.WalletInfo{ - Name: "Bitcoin", - Version: version, - UnitInfo: dexbtc.UnitInfo, - AvailableWallets: []*asset.WalletDefinition{ - spvWalletDefinition, - rpcWalletDefinition, // LegacyWalletIndex - electrumWalletDefinition, +// SPVConfigOpts are the options common to built-in SPV wallets. +func SPVConfigOpts(symbol string) []*asset.ConfigOption { + return []*asset.ConfigOption{{ + Key: "walletbirthday", + DisplayName: "Wallet Birthday", + Description: fmt.Sprintf("This is the date the wallet starts scanning the blockchain "+ + "for transactions related to this wallet. If reconfiguring an existing "+ + "wallet, this may start a rescan if the new birthday is older. This "+ + "option is disabled if there are currently active %s trades.", symbol), + DefaultValue: defaultWalletBirthdayUnix, + MaxValue: "now", + // This MinValue must be removed if we start supporting importing private keys + MinValue: defaultWalletBirthdayUnix, + IsDate: true, + DisableWhenActive: true, + IsBirthdayConfig: true, + }} +} + +// RPCConfigOpts are the settings that are used to connect to and external RPC +// wallet. +func RPCConfigOpts(name, rpcPort string) []*asset.ConfigOption { + return []*asset.ConfigOption{ + { + Key: "walletname", + DisplayName: "Wallet Name", + Description: "The wallet name", + }, + { + Key: "rpcuser", + DisplayName: "JSON-RPC Username", + Description: fmt.Sprintf("%s's 'rpcuser' setting", name), + }, + { + Key: "rpcpassword", + DisplayName: "JSON-RPC Password", + Description: fmt.Sprintf("%s's 'rpcpassword' setting", name), + NoEcho: true, + }, + { + Key: "rpcbind", + DisplayName: "JSON-RPC Address", + Description: " or : (default 'localhost')", + DefaultValue: "127.0.0.1", + }, + { + Key: "rpcport", + DisplayName: "JSON-RPC Port", + Description: "Port for RPC connections (if not set in rpcbind)", + DefaultValue: rpcPort, }, - LegacyWalletIndex: 1, } - - client http.Client -) +} // TxInSigner is a transaction input signer. In addition to the standard Bitcoin // arguments, TxInSigner receives all values and pubkey scripts for previous @@ -513,9 +524,9 @@ type WalletConfig struct { ApiFeeFallback bool `ini:"apifeefallback"` } -// adjustedBirthday converts WalletConfig.Birthday to a time.Time, and adjusts +// AdjustedBirthday converts WalletConfig.Birthday to a time.Time, and adjusts // it so that defaultWalletBirthday <= WalletConfig.Bithday <= now. -func (cfg *WalletConfig) adjustedBirthday() time.Time { +func (cfg *WalletConfig) AdjustedBirthday() time.Time { bday := time.Unix(int64(cfg.Birthday), 0) now := time.Now() if defaultWalletBirthday.After(bday) { @@ -624,9 +635,9 @@ func (d *Driver) Exists(walletType, dataDir string, settings map[string]string, if err != nil { return false, err } - netDir := filepath.Join(dataDir, chainParams.Name) + dir := filepath.Join(dataDir, chainParams.Name, "spv") // timeout and recoverWindow arguments borrowed from btcwallet directly. - loader := wallet.NewLoader(chainParams, netDir, true, 60*time.Second, 250) + loader := wallet.NewLoader(chainParams, dir, true, 60*time.Second, 250) return loader.WalletExists() } @@ -663,7 +674,7 @@ func (d *Driver) Create(params *asset.CreateWalletParams) error { return err } - return createSPVWallet(params.Pass, params.Seed, cfg.adjustedBirthday(), params.DataDir, + return createSPVWallet(params.Pass, params.Seed, cfg.AdjustedBirthday(), params.DataDir, params.Logger, cfg.NumExternalAddresses, cfg.NumInternalAddresses, chainParams) } @@ -867,7 +878,7 @@ func (btc *ExchangeWalletSPV) Rescan(_ context.Context) error { w := btc.node.(*spvWallet) atomic.StoreInt64(&btc.tipAtConnect, 0) // for progress // Caller should start calling SyncStatus on a ticker. - return w.rescanWalletAsync() + return w.wallet.RescanAsync() } // FeeRate satisfies asset.FeeRater. @@ -959,7 +970,7 @@ func NewWallet(cfg *asset.WalletConfig, logger dex.Logger, net dex.Network) (ass switch cfg.Type { case walletTypeSPV: - return openSPVWallet(cloneCFG) + return OpenSPVWallet(cloneCFG, newExtendedWallet) case walletTypeRPC, walletTypeLegacy: rpcWallet, err := BTCCloneWallet(cloneCFG) if err != nil { @@ -1122,8 +1133,8 @@ func newUnconnectedWallet(cfg *BTCCloneCFG, walletCfg *WalletConfig) (*baseWalle return w, nil } -// openSPVWallet opens the previously created native SPV wallet. -func openSPVWallet(cfg *BTCCloneCFG) (*ExchangeWalletSPV, error) { +// OpenSPVWallet opens the previously created native SPV wallet. +func OpenSPVWallet(cfg *BTCCloneCFG, walletConstructor BTCWalletConstructor) (*ExchangeWalletSPV, error) { walletCfg := new(WalletConfig) err := config.Unmapify(cfg.WalletCFG.Settings, walletCfg) if err != nil { @@ -1135,15 +1146,27 @@ func openSPVWallet(cfg *BTCCloneCFG) (*ExchangeWalletSPV, error) { return nil, err } - allowAutomaticRescan := !walletCfg.ActivelyUsed - node := loadSPVWallet(cfg.WalletCFG.DataDir, cfg.Logger.SubLogger("SPV"), cfg.ChainParams, walletCfg.adjustedBirthday(), allowAutomaticRescan) - btc.node = node + spvw := &spvWallet{ + chainParams: cfg.ChainParams, + cfg: walletCfg, + acctNum: defaultAcctNum, + acctName: defaultAcctName, + dir: filepath.Join(cfg.WalletCFG.DataDir, cfg.ChainParams.Name, "spv"), + txBlocks: make(map[chainhash.Hash]*hashEntry), + checkpoints: make(map[outPoint]*scanCheckpoint), + log: cfg.Logger.SubLogger("SPV"), + tipChan: make(chan *block, 8), + newBTCWallet: walletConstructor, + decodeAddr: btc.decodeAddr, + } + + btc.node = spvw return &ExchangeWalletSPV{ intermediaryWallet: &intermediaryWallet{ baseWallet: btc, - txFeeEstimator: node, - tipRedeemer: node, + txFeeEstimator: spvw, + tipRedeemer: spvw, }, }, nil } @@ -1433,7 +1456,7 @@ func externalFeeEstimator(ctx context.Context, net dex.Network) (uint64, error) if err != nil { return 0, err } - httpResponse, err := client.Do(r) + httpResponse, err := http.DefaultClient.Do(r) if err != nil { return 0, err } @@ -4571,7 +4594,6 @@ func convertUnspent(confs uint32, unspents []*ListUnspentResult, chainParams *ch // arbitrary txns. continue } - utxo := &compositeUTXO{ utxo: &utxo{ txHash: txHash, diff --git a/client/asset/btc/btc_test.go b/client/asset/btc/btc_test.go index 8d04317663..42c6ae58d8 100644 --- a/client/asset/btc/btc_test.go +++ b/client/asset/btc/btc_test.go @@ -656,17 +656,16 @@ func tNewWallet(segwit bool, walletType string) (*ExchangeWalletFullNode, *testD neutrinoClient := &tNeutrinoClient{data} spvw := &spvWallet{ chainParams: &chaincfg.MainNetParams, + cfg: &WalletConfig{}, wallet: &tBtcWallet{data}, cl: neutrinoClient, tipChan: make(chan *block, 1), - chainClient: nil, acctNum: 0, txBlocks: data.dbBlockForTx, checkpoints: data.checkpoints, log: cfg.Logger.SubLogger("SPV"), - loader: nil, + decodeAddr: btcutil.DecodeAddress, } - spvw.birthdayV.Store(time.Time{}) w.node = spvw wallet = &ExchangeWalletFullNode{ intermediaryWallet: &intermediaryWallet{ diff --git a/client/asset/btc/spv.go b/client/asset/btc/spv.go index f07637b8ac..fbf99a5371 100644 --- a/client/asset/btc/spv.go +++ b/client/asset/btc/spv.go @@ -83,8 +83,8 @@ const ( var wAddrMgrBkt = []byte("waddrmgr") -// btcWallet is satisfied by *btcwallet.Wallet -> *walletExtender. -type btcWallet interface { +// BTCWallet is satisfied by *btcwallet.Wallet -> *walletExtender. +type BTCWallet interface { PublishTransaction(tx *wire.MsgTx, label string) error CalculateAccountBalances(account uint32, confirms int32) (wallet.Balances, error) ListUnspent(minconf, maxconf int32, acctName string) ([]*btcjson.ListUnspentResult, error) @@ -95,34 +95,43 @@ type btcWallet interface { LockedOutpoints() []btcjson.TransactionInput NewChangeAddress(account uint32, scope waddrmgr.KeyScope) (btcutil.Address, error) NewAddress(account uint32, scope waddrmgr.KeyScope) (btcutil.Address, error) - SignTransaction(tx *wire.MsgTx, hashType txscript.SigHashType, additionalPrevScriptsadditionalPrevScripts map[wire.OutPoint][]byte, - additionalKeysByAddress map[string]*btcutil.WIF, p2shRedeemScriptsByAddress map[string][]byte) ([]wallet.SignatureError, error) PrivKeyForAddress(a btcutil.Address) (*btcec.PrivateKey, error) - Database() walletdb.DB Unlock(passphrase []byte, lock <-chan time.Time) error Lock() Locked() bool SendOutputs(outputs []*wire.TxOut, keyScope *waddrmgr.KeyScope, account uint32, minconf int32, satPerKb btcutil.Amount, coinSelectionStrategy wallet.CoinSelectionStrategy, label string) (*wire.MsgTx, error) HaveAddress(a btcutil.Address) (bool, error) - Stop() WaitForShutdown() ChainSynced() bool // currently unused - SynchronizeRPC(chainClient chain.Interface) - // walletExtender methods - walletTransaction(txHash *chainhash.Hash) (*wtxmgr.TxDetails, error) - syncedTo() waddrmgr.BlockStamp - signTransaction(*wire.MsgTx) error - txNotifications() wallet.TransactionNotificationsClient + AccountProperties(scope waddrmgr.KeyScope, acct uint32) (*waddrmgr.AccountProperties, error) + // The below methods are not implemented by *wallet.Wallet, so must be + // implemented by the BTCWallet implementation. + WalletTransaction(txHash *chainhash.Hash) (*wtxmgr.TxDetails, error) + SyncedTo() waddrmgr.BlockStamp + SignTx(*wire.MsgTx) error + BlockNotifications(context.Context) <-chan *BlockNotification + RescanAsync() error + ForceRescan() + Start() (SPVService, error) + Stop() + Reconfigure(*asset.WalletConfig, string) (bool, error) + Birthday() time.Time } -var _ btcWallet = (*walletExtender)(nil) +// BlockNotification is block hash and height delivered by a BTCWallet when it +// is finished processing a block. +type BlockNotification struct { + Hash chainhash.Hash + Height int32 +} -// neutrinoService is satisfied by *neutrino.ChainService. -type neutrinoService interface { +// SPVService is satisfied by *neutrino.ChainService, with the exception of the +// Peers method, which has a generic interface in place of neutrino.ServerPeer. +type SPVService interface { GetBlockHash(int64) (*chainhash.Hash, error) BestBlock() (*headerfs.BlockStamp, error) - Peers() []*neutrino.ServerPeer + Peers() []SPVPeer GetBlockHeight(hash *chainhash.Hash) (int32, error) GetBlockHeader(*chainhash.Hash) (*wire.BlockHeader, error) GetCFilter(blockHash chainhash.Hash, filterType wire.FilterType, options ...neutrino.QueryOption) (*gcs.Filter, error) @@ -130,7 +139,32 @@ type neutrinoService interface { Stop() error } -var _ neutrinoService = (*neutrino.ChainService)(nil) +// SPVPeer is satisfied by *neutrino.ServerPeer, but is generalized to +// accommodate underlying implementations other than lightninglabs/neutrino. +type SPVPeer interface { + StartingHeight() int32 + LastBlock() int32 +} + +// btcChainService wraps *neutrino.ChainService in order to translate the +// neutrino.ServerPeer to the SPVPeer interface type. +type btcChainService struct { + *neutrino.ChainService +} + +func (s *btcChainService) Peers() []SPVPeer { + rawPeers := s.ChainService.Peers() + peers := make([]SPVPeer, 0, len(rawPeers)) + for _, p := range rawPeers { + peers = append(peers, p) + } + return peers +} + +var _ SPVService = (*btcChainService)(nil) + +// BTCWalletConstructor is a function to construct a BTCWallet. +type BTCWalletConstructor func(dir string, cfg *WalletConfig, chainParams *chaincfg.Params, log dex.Logger) BTCWallet func extendAddresses(extIdx, intIdx uint32, btcw *wallet.Wallet) error { scopedKeyManager, err := btcw.Manager.FetchScopedKeyManager(waddrmgr.KeyScopeBIP0084) @@ -141,30 +175,30 @@ func extendAddresses(extIdx, intIdx uint32, btcw *wallet.Wallet) error { return walletdb.Update(btcw.Database(), func(dbtx walletdb.ReadWriteTx) error { ns := dbtx.ReadWriteBucket(wAddrMgrBkt) if extIdx > 0 { - scopedKeyManager.ExtendExternalAddresses(ns, defaultAcctNum, extIdx) - } - if intIdx > 0 { - scopedKeyManager.ExtendInternalAddresses(ns, defaultAcctNum, intIdx) + if err := scopedKeyManager.ExtendExternalAddresses(ns, defaultAcctNum, extIdx); err != nil { + return err + } } - return nil + return scopedKeyManager.ExtendInternalAddresses(ns, defaultAcctNum, intIdx) }) } // createSPVWallet creates a new SPV wallet. -func createSPVWallet(privPass []byte, seed []byte, bday time.Time, dbDir string, log dex.Logger, extIdx, intIdx uint32, net *chaincfg.Params) error { - netDir := filepath.Join(dbDir, net.Name) +func createSPVWallet(privPass []byte, seed []byte, bday time.Time, dataDir string, log dex.Logger, extIdx, intIdx uint32, net *chaincfg.Params) error { - if err := logNeutrino(netDir); err != nil { + dir := filepath.Join(dataDir, net.Name, "spv") + + if err := logNeutrino(dir); err != nil { return fmt.Errorf("error initializing btcwallet+neutrino logging: %w", err) } - logDir := filepath.Join(netDir, logDirName) + logDir := filepath.Join(dir, logDirName) err := os.MkdirAll(logDir, 0744) if err != nil { return fmt.Errorf("error creating wallet directories: %w", err) } - loader := wallet.NewLoader(net, netDir, true, 60*time.Second, 250) + loader := wallet.NewLoader(net, dir, true, 60*time.Second, 250) pubPass := []byte(wallet.InsecurePubPassphrase) @@ -188,7 +222,7 @@ func createSPVWallet(privPass []byte, seed []byte, bday time.Time, dbDir string, } // The chain service DB - neutrinoDBPath := filepath.Join(netDir, neutrinoDBName) + neutrinoDBPath := filepath.Join(dir, neutrinoDBName) db, err := walletdb.Create("bdb", neutrinoDBPath, true, 5*time.Second) if err != nil { bailOnWallet() @@ -212,9 +246,9 @@ var ( ) // logRotator initializes a rotating file logger. -func logRotator(netDir string) (*rotator.Rotator, error) { +func logRotator(dir string) (*rotator.Rotator, error) { const maxLogRolls = 8 - logDir := filepath.Join(netDir, logDirName) + logDir := filepath.Join(dir, logDirName) if err := os.MkdirAll(logDir, 0744); err != nil { return nil, fmt.Errorf("error creating log directory: %w", err) } @@ -231,17 +265,17 @@ func logRotator(netDir string) (*rotator.Rotator, error) { // there are concurrency issues with that since btcd and btcwallet have // unsupervised goroutines still running after shutdown. So we leave the rotator // running at the risk of losing some logs. -func logNeutrino(netDir string) error { +func logNeutrino(dir string) error { if !atomic.CompareAndSwapUint32(&loggingInited, 0, 1) { return nil } - logSpinner, err := logRotator(netDir) + logSpinner, err := logRotator(dir) if err != nil { return fmt.Errorf("error initializing log rotator: %w", err) } - backendLog := btclog.NewBackend(logWriter{logSpinner}) + backendLog := btclog.NewBackend(logSpinner) logger := func(name string, lvl btclog.Level) btclog.Logger { l := backendLog.Logger(name) @@ -295,33 +329,19 @@ type scanCheckpoint struct { lastAccess time.Time } -// logWriter implements an io.Writer that outputs to a rotating log file. -type logWriter struct { - *rotator.Rotator -} - -// Write writes the data in p to the log file. -func (w logWriter) Write(p []byte) (n int, err error) { - return w.Rotator.Write(p) -} - // spvWallet is an in-process btcwallet.Wallet + neutrino light-filter-based // Bitcoin wallet. spvWallet controls an instance of btcwallet.Wallet directly // and does not run or connect to the RPC server. type spvWallet struct { - chainParams *chaincfg.Params - wallet btcWallet - cl neutrinoService - chainClient *chain.NeutrinoClient - birthdayV atomic.Value // time.Time - // if allowAutomaticRescan is true, if when connect is called, spvWallet.birthday - // is earlier than the birthday stored in the btcwallet database, the transaction - // history will be wiped and a rescan will start. - allowAutomaticRescan bool - acctNum uint32 - acctName string - netDir string - neutrinoDB walletdb.DB + chainParams *chaincfg.Params + cfg *WalletConfig + wallet BTCWallet + cl SPVService + acctNum uint32 + acctName string + dir string + newBTCWallet BTCWalletConstructor + decodeAddr dexbtc.AddressDecoder txBlocksMtx sync.Mutex txBlocks map[chainhash.Hash]*hashEntry @@ -329,63 +349,41 @@ type spvWallet struct { checkpointMtx sync.Mutex checkpoints map[outPoint]*scanCheckpoint - log dex.Logger - loader *wallet.Loader + log dex.Logger tipChan chan *block syncTarget int32 lastPrenatalHeight int32 - - // rescanStarting is set while reloading the wallet and dropping - // transactions from the wallet db. - rescanStarting uint32 // atomic } var _ Wallet = (*spvWallet)(nil) var _ tipNotifier = (*spvWallet)(nil) -// loadSPVWallet loads an existing wallet. -func loadSPVWallet(dbDir string, logger dex.Logger, chainParams *chaincfg.Params, birthday time.Time, allowAutomaticRescan bool) *spvWallet { - spvw := &spvWallet{ - chainParams: chainParams, - acctNum: defaultAcctNum, - acctName: defaultAcctName, - netDir: filepath.Join(dbDir, chainParams.Name), - txBlocks: make(map[chainhash.Hash]*hashEntry), - checkpoints: make(map[outPoint]*scanCheckpoint), - log: logger, - tipChan: make(chan *block, 8), - allowAutomaticRescan: allowAutomaticRescan, - } - spvw.birthdayV.Store(birthday) - return spvw -} - -func (w *spvWallet) birthday() time.Time { - return w.birthdayV.Load().(time.Time) -} - // reconfigure attempts to reconfigure the rpcClient for the new settings. Live // reconfiguration is only attempted if the new wallet type is walletTypeSPV. An // error is generated if the birthday is reduced and the special_activelyUsed // flag is set. -func (w *spvWallet) reconfigure(cfg *asset.WalletConfig, _ /* currentAddress */ string) (restartRequired bool, err error) { +func (w *spvWallet) reconfigure(cfg *asset.WalletConfig, currentAddress string) (restartRequired bool, err error) { if cfg.Type != walletTypeSPV { restartRequired = true return } + return w.wallet.Reconfigure(cfg, currentAddress) +} + +func (w *walletExtender) Reconfigure(cfg *asset.WalletConfig, _ /* currentAddress */ string) (restartRequired bool, err error) { parsedCfg := new(WalletConfig) if err = config.Unmapify(cfg.Settings, parsedCfg); err != nil { return } - newBday := parsedCfg.adjustedBirthday() - if newBday.Equal(w.birthday()) { + newBday := parsedCfg.AdjustedBirthday() + if newBday.Equal(w.Birthday()) { // It's the only setting we care about. return } - rescanRequired := newBday.Before(w.birthday()) + rescanRequired := newBday.Before(w.Birthday()) if rescanRequired && parsedCfg.ActivelyUsed { return false, errors.New("cannot decrease the birthday with active orders") } @@ -394,7 +392,7 @@ func (w *spvWallet) reconfigure(cfg *asset.WalletConfig, _ /* currentAddress */ } w.birthdayV.Store(newBday) if rescanRequired { - if err = w.rescanWalletAsync(); err != nil { + if err = w.RescanAsync(); err != nil { return false, fmt.Errorf("error initiating rescan after birthday adjustment: %w", err) } } @@ -551,7 +549,7 @@ func (w *spvWallet) getBlockHeight(h *chainhash.Hash) (int32, error) { } func (w *spvWallet) getBestBlockHash() (*chainhash.Hash, error) { - blk := w.wallet.syncedTo() + blk := w.wallet.SyncedTo() return &blk.Hash, nil } @@ -561,7 +559,7 @@ func (w *spvWallet) getBestBlockHash() (*chainhash.Hash, error) { // getChainHeight, which indicates the height that the chain service has reached // in its retrieval of block headers and compact filter headers. func (w *spvWallet) getBestBlockHeight() (int32, error) { - return w.wallet.syncedTo().Height, nil + return w.wallet.SyncedTo().Height, nil } // getChainStamp satisfies chainStamper for manual median time calculations. @@ -575,7 +573,7 @@ func (w *spvWallet) getChainStamp(blockHash *chainhash.Hash) (stamp time.Time, p // medianTime is the median time for the current best block. func (w *spvWallet) medianTime() (time.Time, error) { - blk := w.wallet.syncedTo() + blk := w.wallet.SyncedTo() return calcMedianTime(w, &blk.Hash) } @@ -631,12 +629,12 @@ func (w *spvWallet) syncStatus() (*syncStatus, error) { var synced bool var blk *block // Wallet address manager sync height. - if chainBlk.Timestamp.After(w.birthday()) { + if chainBlk.Timestamp.After(w.wallet.Birthday()) { // After the wallet's birthday, the wallet address manager should begin // syncing. Although block time stamps are not necessarily monotonically // increasing, this is a reasonable condition at which the wallet's sync // height should be consulted instead of the chain service's height. - walletBlock := w.wallet.syncedTo() + walletBlock := w.wallet.SyncedTo() if walletBlock.Height == 0 { // The wallet is about to start its sync, so just return the last // chain service height prior to wallet birthday until it begins. @@ -679,7 +677,7 @@ func (w *spvWallet) ownsInputs(txid string) bool { w.log.Warnf("Error decoding txid %q: %v", txid, err) return false } - txDetails, err := w.wallet.walletTransaction(txHash) + txDetails, err := w.wallet.WalletTransaction(txHash) if err != nil { w.log.Warnf("walletTransaction(%v) error: %v", txid, err) return false @@ -833,13 +831,13 @@ func (w *spvWallet) refundAddress() (btcutil.Address, error) { func (w *spvWallet) signTx(tx *wire.MsgTx) (*wire.MsgTx, error) { // Can't use btcwallet.Wallet.SignTransaction, because it doesn't work for // segwit transactions (for real?). - return tx, w.wallet.signTransaction(tx) + return tx, w.wallet.SignTx(tx) } // privKeyForAddress retrieves the private key associated with the specified // address. func (w *spvWallet) privKeyForAddress(addr string) (*btcec.PrivateKey, error) { - a, err := btcutil.DecodeAddress(addr, w.chainParams) + a, err := w.decodeAddr(addr, w.chainParams) if err != nil { return nil, err } @@ -860,7 +858,7 @@ func (w *spvWallet) Lock() error { // sendToAddress sends the amount to the address. feeRate is in units of // sats/byte. func (w *spvWallet) sendToAddress(address string, value, feeRate uint64, subtract bool) (*chainhash.Hash, error) { - addr, err := btcutil.DecodeAddress(address, w.chainParams) + addr, err := w.decodeAddr(address, w.chainParams) if err != nil { return nil, err } @@ -965,7 +963,7 @@ func (w *spvWallet) sendWithSubtract(pkScript []byte, value, feeRate uint64) (*c } tx.AddTxOut(wireOP) - if err := w.wallet.signTransaction(tx); err != nil { + if err := w.wallet.SignTx(tx); err != nil { return nil, fmt.Errorf("signing error: %w", err) } @@ -1173,28 +1171,24 @@ func (w *spvWallet) getBestBlockHeader() (*blockHeader, error) { } func (w *spvWallet) logFilePath() string { - return filepath.Join(w.netDir, logDirName, logFileName) + return filepath.Join(w.dir, logDirName, logFileName) } // connect will start the wallet and begin syncing. -func (w *spvWallet) connect(ctx context.Context, wg *sync.WaitGroup) error { - if err := logNeutrino(w.netDir); err != nil { - return fmt.Errorf("error initializing btcwallet+neutrino logging: %v", err) - } - - err := w.startWallet() +func (w *spvWallet) connect(ctx context.Context, wg *sync.WaitGroup) (err error) { + w.wallet = w.newBTCWallet(w.dir, w.cfg, w.chainParams, w.log) + w.cl, err = w.wallet.Start() if err != nil { return err } - txNotes := w.wallet.txNotifications() + blockNotes := w.wallet.BlockNotifications(ctx) // Nanny for the caches checkpoints and txBlocks caches. wg.Add(1) go func() { defer wg.Done() - defer w.stop() - defer txNotes.Done() + defer w.wallet.Stop() ticker := time.NewTicker(time.Minute * 20) defer ticker.Stop() @@ -1218,29 +1212,19 @@ func (w *spvWallet) connect(ctx context.Context, wg *sync.WaitGroup) error { } w.checkpointMtx.Unlock() - case note := <-txNotes.C: - if len(note.AttachedBlocks) > 0 { - lastBlock := note.AttachedBlocks[len(note.AttachedBlocks)-1] - syncTarget := atomic.LoadInt32(&w.syncTarget) - - for ib := range note.AttachedBlocks { - for _, nt := range note.AttachedBlocks[ib].Transactions { - w.log.Debugf("Block %d contains wallet transaction %v", note.AttachedBlocks[ib].Height, nt.Hash) - } - } - - if syncTarget == 0 || (lastBlock.Height < syncTarget && lastBlock.Height%10_000 != 0) { - continue - } + case blk := <-blockNotes: + syncTarget := atomic.LoadInt32(&w.syncTarget) + if syncTarget == 0 || (blk.Height < syncTarget && blk.Height%10_000 != 0) { + continue + } - select { - case w.tipChan <- &block{ - hash: *lastBlock.Hash, - height: int64(lastBlock.Height), - }: - default: - w.log.Warnf("tip report channel was blocking") - } + select { + case w.tipChan <- &block{ + hash: blk.Hash, + height: int64(blk.Height), + }: + default: + w.log.Warnf("tip report channel was blocking") } case <-ctx.Done(): @@ -1252,45 +1236,39 @@ func (w *spvWallet) connect(ctx context.Context, wg *sync.WaitGroup) error { return nil } -// startWallet initializes the *btcwallet.Wallet and its supporting players and -// starts syncing. -func (w *spvWallet) startWallet() error { +// Start initializes the *btcwallet.Wallet and its supporting players and starts +// syncing. +func (w *walletExtender) Start() (SPVService, error) { + if err := logNeutrino(w.dir); err != nil { + return nil, fmt.Errorf("error initializing btcwallet+neutrino logging: %v", err) + } // timeout and recoverWindow arguments borrowed from btcwallet directly. - w.loader = wallet.NewLoader(w.chainParams, w.netDir, true, 60*time.Second, 250) + w.loader = wallet.NewLoader(w.chainParams, w.dir, true, 60*time.Second, 250) exists, err := w.loader.WalletExists() if err != nil { - return fmt.Errorf("error verifying wallet existence: %v", err) + return nil, fmt.Errorf("error verifying wallet existence: %v", err) } if !exists { - return errors.New("wallet not found") + return nil, errors.New("wallet not found") } w.log.Debug("Starting native BTC wallet...") btcw, err := w.loader.OpenExistingWallet([]byte(wallet.InsecurePubPassphrase), false) if err != nil { - return fmt.Errorf("couldn't load wallet: %w", err) + return nil, fmt.Errorf("couldn't load wallet: %w", err) } - bailOnWallet := func() { - if err := w.loader.UnloadWallet(); err != nil { - w.log.Errorf("Error unloading wallet: %v", err) - } - } + errCloser := dex.NewErrorCloser(w.log) + defer errCloser.Done() + errCloser.Add(w.loader.UnloadWallet) - neutrinoDBPath := filepath.Join(w.netDir, neutrinoDBName) + neutrinoDBPath := filepath.Join(w.dir, neutrinoDBName) w.neutrinoDB, err = walletdb.Create("bdb", neutrinoDBPath, true, wallet.DefaultDBTimeout) if err != nil { - bailOnWallet() - return fmt.Errorf("unable to create wallet db at %q: %v", neutrinoDBPath, err) - } - - bailOnWalletAndDB := func() { - if err := w.neutrinoDB.Close(); err != nil { - w.log.Errorf("Error closing neutrino database: %v", err) - } - bailOnWallet() + return nil, fmt.Errorf("unable to create wallet db at %q: %v", neutrinoDBPath, err) } + errCloser.Add(w.neutrinoDB.Close) // Depending on the network, we add some addpeers or a connect peer. On // regtest, if the peers haven't been explicitly set, add the simnet harness @@ -1308,66 +1286,58 @@ func (w *spvWallet) startWallet() error { connectPeers = []string{"localhost:20575"} } w.log.Debug("Starting neutrino chain service...") - chainService, err := neutrino.NewChainService(neutrino.Config{ - DataDir: w.netDir, + w.cl, err = neutrino.NewChainService(neutrino.Config{ + DataDir: w.dir, Database: w.neutrinoDB, ChainParams: *w.chainParams, PersistToDisk: true, // keep cfilter headers on disk for efficient rescanning AddPeers: addPeers, ConnectPeers: connectPeers, // WARNING: PublishTransaction currently uses the entire duration - // because if an external bug, but even if the resolved, a typical - // inv/getdata round trip is ~4 seconds, so we set this so neutrino does - // not cancel queries too readily. + // because if an external bug, but even if the bug is resolved, a + // typical inv/getdata round trip is ~4 seconds, so we set this so + // neutrino does not cancel queries too readily. BroadcastTimeout: 6 * time.Second, }) if err != nil { - bailOnWalletAndDB() - return fmt.Errorf("couldn't create Neutrino ChainService: %v", err) - } - - bailOnEverything := func() { - if err := chainService.Stop(); err != nil { - w.log.Errorf("Error closing neutrino chain service: %v", err) - } - bailOnWalletAndDB() + return nil, fmt.Errorf("couldn't create Neutrino ChainService: %v", err) } + errCloser.Add(w.cl.Stop) - w.cl = chainService - w.chainClient = chain.NewNeutrinoClient(w.chainParams, chainService) - w.wallet = &walletExtender{btcw, w.chainParams} + w.chainClient = chain.NewNeutrinoClient(w.chainParams, w.cl) + w.Wallet = btcw oldBday := btcw.Manager.Birthday() - performRescan := w.birthday().Before(oldBday) + performRescan := w.Birthday().Before(oldBday) if performRescan && !w.allowAutomaticRescan { - bailOnWalletAndDB() - return errors.New("cannot set earlier birthday while there are active deals") + return nil, errors.New("cannot set earlier birthday while there are active deals") } - if !oldBday.Equal(w.birthday()) { - if err := w.updateDBBirthday(w.birthday()); err != nil { + if !oldBday.Equal(w.Birthday()) { + if err := w.updateDBBirthday(w.Birthday()); err != nil { w.log.Errorf("Failed to reset wallet manager birthday: %v", err) performRescan = false } } if performRescan { - w.forceRescan() + w.ForceRescan() } if err = w.chainClient.Start(); err != nil { // lazily starts connmgr - bailOnEverything() - return fmt.Errorf("couldn't start Neutrino client: %v", err) + return nil, fmt.Errorf("couldn't start Neutrino client: %v", err) } w.log.Info("Synchronizing wallet with network...") btcw.SynchronizeRPC(w.chainClient) - return nil + errCloser.Success() + + return &btcChainService{w.cl}, nil } -func (w *spvWallet) updateDBBirthday(bday time.Time) error { +func (w *walletExtender) updateDBBirthday(bday time.Time) error { btcw, isLoaded := w.loader.LoadedWallet() if !isLoaded { return fmt.Errorf("wallet not loaded") @@ -1386,18 +1356,13 @@ func (w *spvWallet) moveWalletData(backupDir string) error { return err } backupFolder := filepath.Join(backupDir, timeString) - return os.Rename(w.netDir, backupFolder) + return os.Rename(w.dir, backupFolder) } // numDerivedAddresses returns the number of internal and external addresses // that the wallet has derived. func (w *spvWallet) numDerivedAddresses() (internal, external uint32, err error) { - btcw, ok := w.loader.LoadedWallet() - if !ok { - return 0, 0, err - } - - props, err := btcw.AccountProperties(waddrmgr.KeyScopeBIP0084, w.acctNum) + props, err := w.wallet.AccountProperties(waddrmgr.KeyScopeBIP0084, w.acctNum) if err != nil { return 0, 0, err } @@ -1405,59 +1370,46 @@ func (w *spvWallet) numDerivedAddresses() (internal, external uint32, err error) return props.InternalKeyCount, props.ExternalKeyCount, nil } -// rescanWalletAsync initiates a full wallet recovery (used address discovery +// RescanAsync initiates a full wallet recovery (used address discovery // and transaction scanning) by stopping the btcwallet, dropping the transaction // history from the wallet db, resetting the synced-to height of the wallet // manager, restarting the wallet and its chain client, and finally commanding // the wallet to resynchronize, which starts asynchronous wallet recovery. // Progress of the rescan should be monitored with syncStatus. During the rescan // wallet balances and known transactions may not be reported accurately or -// located. The neutrinoService is not stopped, so most spvWallet methods will +// located. The SPVService is not stopped, so most spvWallet methods will // continue to work without error, but methods using the btcWallet will likely // return incorrect results or errors. -func (w *spvWallet) rescanWalletAsync() error { +func (w *walletExtender) RescanAsync() error { if !atomic.CompareAndSwapUint32(&w.rescanStarting, 0, 1) { - return errors.New("rescan already in progress") + w.log.Error("rescan already in progress") } defer atomic.StoreUint32(&w.rescanStarting, 0) - - // Stop the wallet, but do not use w.loader.UnloadWallet because it also - // closes the database. - btcw, ok := w.loader.LoadedWallet() - if !ok { - return errors.New("wallet not loaded") - } - w.log.Info("Stopping wallet and chain client...") - btcw.Stop() // stops Wallet and chainClient (not chainService) - btcw.WaitForShutdown() + w.Wallet.Stop() // stops Wallet and chainClient (not chainService) + w.Wallet.WaitForShutdown() w.chainClient.WaitForShutdown() - w.forceRescan() + w.ForceRescan() w.log.Info("Starting wallet...") - btcw.Start() + w.Wallet.Start() if err := w.chainClient.Start(); err != nil { return fmt.Errorf("couldn't start Neutrino client: %v", err) } w.log.Info("Synchronizing wallet with network...") - btcw.SynchronizeRPC(w.chainClient) + w.Wallet.SynchronizeRPC(w.chainClient) return nil } -// forceRescan forces a full rescan with active address discovery on wallet +// ForceRescan forces a full rescan with active address discovery on wallet // restart by dropping the complete transaction history and setting the // "synced to" field to nil. See the btcwallet/cmd/dropwtxmgr app for more // information. -func (w *spvWallet) forceRescan() { - btcw, ok := w.loader.LoadedWallet() - if !ok { - w.log.Errorf("wallet not loaded") - return - } - wdb := btcw.Database() +func (w *walletExtender) ForceRescan() { + wdb := w.Wallet.Database() w.log.Info("Dropping transaction history to perform full rescan...") err := wallet.DropTransactionHistory(wdb, false) @@ -1467,8 +1419,8 @@ func (w *spvWallet) forceRescan() { } err = walletdb.Update(wdb, func(dbtx walletdb.ReadWriteTx) error { - ns := dbtx.ReadWriteBucket(wAddrMgrBkt) // it'll be fine - return btcw.Manager.SetSyncedTo(ns, nil) // never synced, forcing recover from birthday + ns := dbtx.ReadWriteBucket(wAddrMgrBkt) // it'll be fine + return w.Wallet.Manager.SetSyncedTo(ns, nil) // never synced, forcing recover from birthday }) if err != nil { w.log.Errorf("Failed to reset wallet manager sync height: %v", err) @@ -1476,7 +1428,7 @@ func (w *spvWallet) forceRescan() { } // stop stops the wallet and database threads. -func (w *spvWallet) stop() { +func (w *walletExtender) Stop() { w.log.Info("Unloading wallet") if err := w.loader.UnloadWallet(); err != nil { w.log.Errorf("UnloadWallet error: %v", err) @@ -1495,6 +1447,8 @@ func (w *spvWallet) stop() { w.log.Errorf("wallet db close error: %v", err) } + // NOTE: Do we need w.Wallet.Stop() + w.log.Info("SPV wallet closed") } @@ -1688,7 +1642,7 @@ func (w *spvWallet) scanFilters(txHash *chainhash.Hash, vout uint32, pkScript [] // known to be spent, no *wire.TxOut and no error will be returned. func (w *spvWallet) getTxOut(txHash *chainhash.Hash, vout uint32, pkScript []byte, startTime time.Time) (*wire.TxOut, uint32, error) { // Check for a wallet transaction first - txDetails, err := w.wallet.walletTransaction(txHash) + txDetails, err := w.wallet.WalletTransaction(txHash) var blockHash *chainhash.Hash if err != nil && !errors.Is(err, WalletTransactionNotFound) { return nil, 0, fmt.Errorf("walletTransaction error: %w", err) @@ -1748,7 +1702,7 @@ func (w *spvWallet) getTxOut(txHash *chainhash.Hash, vout uint32, pkScript []byt // filterScanFromHeight scans BIP158 filters beginning at the specified block // height until the tip, or until a spending transaction is found. func (w *spvWallet) filterScanFromHeight(txHash chainhash.Hash, vout uint32, pkScript []byte, startBlockHeight int32, checkPt *filterScanResult) (*filterScanResult, error) { - walletBlock := w.wallet.syncedTo() // where cfilters are received and processed + walletBlock := w.wallet.SyncedTo() // where cfilters are received and processed tip := walletBlock.Height res := checkPt @@ -1904,7 +1858,7 @@ func (w *spvWallet) findRedemptionsInMempool(ctx context.Context, reqs map[outPo // confirmations looks for the confirmation count and spend status on a // transaction output that pays to this wallet. func (w *spvWallet) confirmations(txHash *chainhash.Hash, vout uint32) (blockHash *chainhash.Hash, confs uint32, spent bool, err error) { - details, err := w.wallet.walletTransaction(txHash) + details, err := w.wallet.WalletTransaction(txHash) if err != nil { return nil, 0, false, err } @@ -1946,7 +1900,7 @@ func (w *spvWallet) getWalletTransaction(txHash *chainhash.Hash) (*GetTransactio // Option #2 // This is what the JSON-RPC does (and has since at least May 2018). - details, err := w.wallet.walletTransaction(txHash) + details, err := w.wallet.WalletTransaction(txHash) if err != nil { if errors.Is(err, WalletTransactionNotFound) { return nil, asset.CoinNotFoundError // for the asset.Wallet interface @@ -1954,7 +1908,7 @@ func (w *spvWallet) getWalletTransaction(txHash *chainhash.Hash) (*GetTransactio return nil, err } - syncBlock := w.wallet.syncedTo() + syncBlock := w.wallet.SyncedTo() // TODO: The serialized transaction is already in the DB, so reserializing // might be avoided here. According to btcwallet, details.SerializedTx is @@ -2010,10 +1964,47 @@ func (w *spvWallet) getWalletTransaction(txHash *chainhash.Hash) (*GetTransactio type walletExtender struct { *wallet.Wallet chainParams *chaincfg.Params + log dex.Logger + dir string + birthdayV atomic.Value // time.Time + // if allowAutomaticRescan is true, if when connect is called, + // spvWallet.birthday is earlier than the birthday stored in the btcwallet + // database, the transaction history will be wiped and a rescan will start. + allowAutomaticRescan bool + + // Below fields are populated in Start. + loader *wallet.Loader + chainClient *chain.NeutrinoClient + cl *neutrino.ChainService + neutrinoDB walletdb.DB + + // rescanStarting is set while reloading the wallet and dropping + // transactions from the wallet db. + rescanStarting uint32 // atomic +} + +var _ BTCWallet = (*walletExtender)(nil) + +// newExtendedWallet is the BTCWalletConstructor for Bitcoin. +func newExtendedWallet(dir string, cfg *WalletConfig, + chainParams *chaincfg.Params, log dex.Logger) BTCWallet { + + w := &walletExtender{ + dir: dir, + chainParams: chainParams, + log: log, + allowAutomaticRescan: !cfg.ActivelyUsed, + } + w.birthdayV.Store(cfg.AdjustedBirthday()) + return w +} + +func (w *walletExtender) Birthday() time.Time { + return w.birthdayV.Load().(time.Time) } // walletTransaction pulls the transaction from the database. -func (w *walletExtender) walletTransaction(txHash *chainhash.Hash) (*wtxmgr.TxDetails, error) { +func (w *walletExtender) WalletTransaction(txHash *chainhash.Hash) (*wtxmgr.TxDetails, error) { details, err := wallet.UnstableAPI(w.Wallet).TxDetails(txHash) if err != nil { return nil, err @@ -2025,8 +2016,8 @@ func (w *walletExtender) walletTransaction(txHash *chainhash.Hash) (*wtxmgr.TxDe return details, nil } -func (w *walletExtender) syncedTo() waddrmgr.BlockStamp { - return w.Manager.SyncedTo() +func (w *walletExtender) SyncedTo() waddrmgr.BlockStamp { + return w.Wallet.Manager.SyncedTo() } // getWalletBirthdayBlock retrieves the wallet's birthday block. @@ -2050,11 +2041,13 @@ func (w *walletExtender) syncedTo() waddrmgr.BlockStamp { // } // signTransaction signs the transaction inputs. -func (w *walletExtender) signTransaction(tx *wire.MsgTx) error { +func (w *walletExtender) SignTx(tx *wire.MsgTx) error { var prevPkScripts [][]byte var inputValues []btcutil.Amount for _, txIn := range tx.TxIn { - _, txOut, _, _, err := w.FetchInputInfo(&txIn.PreviousOutPoint) + // NOTE: The BitcoinCash implementation of BTCWallet ONLY produces the + // *wire.TxOut. + _, txOut, _, _, err := w.Wallet.FetchInputInfo(&txIn.PreviousOutPoint) if err != nil { return err } @@ -2068,9 +2061,30 @@ func (w *walletExtender) signTransaction(tx *wire.MsgTx) error { return txauthor.AddAllInputScripts(tx, prevPkScripts, inputValues, &secretSource{w, w.chainParams}) } -// txNotifications gives access to the NotificationServer's tx notifications. -func (w *walletExtender) txNotifications() wallet.TransactionNotificationsClient { - return w.NtfnServer.TransactionNotifications() +func (w *walletExtender) BlockNotifications(ctx context.Context) <-chan *BlockNotification { + cl := w.Wallet.NtfnServer.TransactionNotifications() + ch := make(chan *BlockNotification, 1) + go func() { + defer cl.Done() + for { + select { + case note := <-cl.C: + if len(note.AttachedBlocks) > 0 { + lastBlock := note.AttachedBlocks[len(note.AttachedBlocks)-1] + select { + case ch <- &BlockNotification{ + Hash: *lastBlock.Hash, + Height: lastBlock.Height, + }: + default: + } + } + case <-ctx.Done(): + return + } + } + }() + return ch } // secretSource is used to locate keys and redemption scripts while signing a @@ -2087,7 +2101,7 @@ func (s *secretSource) ChainParams() *chaincfg.Params { // GetKey fetches a private key for the specified address. func (s *secretSource) GetKey(addr btcutil.Address) (*btcec.PrivateKey, bool, error) { - ma, err := s.w.AddressInfo(addr) + ma, err := s.w.Wallet.AddressInfo(addr) if err != nil { return nil, false, err } @@ -2108,7 +2122,7 @@ func (s *secretSource) GetKey(addr btcutil.Address) (*btcec.PrivateKey, bool, er // GetScript fetches the redemption script for the specified p2sh/p2wsh address. func (s *secretSource) GetScript(addr btcutil.Address) ([]byte, error) { - ma, err := s.w.AddressInfo(addr) + ma, err := s.w.Wallet.AddressInfo(addr) if err != nil { return nil, err } diff --git a/client/asset/btc/spv_test.go b/client/asset/btc/spv_test.go index 3df8d1984a..479208e9be 100644 --- a/client/asset/btc/spv_test.go +++ b/client/asset/btc/spv_test.go @@ -6,12 +6,14 @@ package btc import ( + "context" "errors" "fmt" "sync/atomic" "testing" "time" + "decred.org/dcrdex/client/asset" "decred.org/dcrdex/dex" "decred.org/dcrdex/dex/encode" dexbtc "decred.org/dcrdex/dex/networks/btc" @@ -189,6 +191,10 @@ func (c *tBtcWallet) HaveAddress(a btcutil.Address) (bool, error) { func (c *tBtcWallet) Stop() {} +func (c *tBtcWallet) Start() (SPVService, error) { + return nil, nil +} + func (c *tBtcWallet) WaitForShutdown() {} func (c *tBtcWallet) ChainSynced() bool { @@ -202,7 +208,7 @@ func (c *tBtcWallet) ChainSynced() bool { func (c *tBtcWallet) SynchronizeRPC(chainClient chain.Interface) {} -func (c *tBtcWallet) walletTransaction(txHash *chainhash.Hash) (*wtxmgr.TxDetails, error) { +func (c *tBtcWallet) WalletTransaction(txHash *chainhash.Hash) (*wtxmgr.TxDetails, error) { if c.getTransactionErr != nil { return nil, c.getTransactionErr } @@ -283,7 +289,7 @@ func (c *tBtcWallet) getTransaction(txHash *chainhash.Hash) (*GetTransactionResu return txData, nil } -func (c *tBtcWallet) syncedTo() waddrmgr.BlockStamp { +func (c *tBtcWallet) SyncedTo() waddrmgr.BlockStamp { bestHash, bestHeight := c.bestBlock() // NOTE: in reality this may be lower than the chain service's best block blk := c.getBlock(bestHash.String()) return waddrmgr.BlockStamp{ @@ -293,7 +299,7 @@ func (c *tBtcWallet) syncedTo() waddrmgr.BlockStamp { } } -func (c *tBtcWallet) signTransaction(tx *wire.MsgTx) error { +func (c *tBtcWallet) SignTx(tx *wire.MsgTx) error { if c.signTxErr != nil { return c.signTxErr } @@ -304,8 +310,24 @@ func (c *tBtcWallet) signTransaction(tx *wire.MsgTx) error { return nil } -func (c *tBtcWallet) txNotifications() wallet.TransactionNotificationsClient { - return wallet.TransactionNotificationsClient{} +func (c *tBtcWallet) AccountProperties(scope waddrmgr.KeyScope, acct uint32) (*waddrmgr.AccountProperties, error) { + return nil, nil +} + +func (c *tBtcWallet) BlockNotifications(ctx context.Context) <-chan *BlockNotification { + return nil +} + +func (c *tBtcWallet) ForceRescan() {} + +func (c *tBtcWallet) RescanAsync() error { return nil } + +func (c *tBtcWallet) Birthday() time.Time { + return time.Time{} +} + +func (c *tBtcWallet) Reconfigure(*asset.WalletConfig, string) (bool, error) { + return false, nil } type tNeutrinoClient struct { @@ -341,14 +363,14 @@ func (c *tNeutrinoClient) BestBlock() (*headerfs.BlockStamp, error) { }, nil } -func (c *tNeutrinoClient) Peers() []*neutrino.ServerPeer { +func (c *tNeutrinoClient) Peers() []SPVPeer { c.blockchainMtx.RLock() defer c.blockchainMtx.RUnlock() peer := &neutrino.ServerPeer{Peer: &peer.Peer{}} if c.getBlockchainInfo != nil { peer.UpdateLastBlockHeight(int32(c.getBlockchainInfo.Headers)) } - return []*neutrino.ServerPeer{peer} + return []SPVPeer{peer} } func (c *tNeutrinoClient) GetBlockHeight(hash *chainhash.Hash) (int32, error) { diff --git a/client/cmd/simnet-trade-tests/run b/client/cmd/simnet-trade-tests/run index 1450848eba..df3ca579b6 100755 --- a/client/cmd/simnet-trade-tests/run +++ b/client/cmd/simnet-trade-tests/run @@ -26,6 +26,11 @@ case $1 in --regasset dcr ${@:2} ;; + bchspvdcr) + ./simnet-trade-tests --base bch --quote dcr --quote1node trading1 --quote2node trading2 \ + --regasset dcr --base1type=spv ${@:2} + ;; + ltcdcr) ./simnet-trade-tests --base ltc --quote dcr --quote1node trading1 --quote2node trading2 \ --regasset dcr ${@:2} @@ -65,6 +70,7 @@ dcrspvbtc - Decred SPV wallet and Bitcoin RPC wallet on DCR-BTC dcrbtcspv - Decred RPC wallet and Bitcoin SPV wallet on DCR-BTC market dcrbtcelectrum - Decred RPC wallet and Bitcoin Electrum wallet on DCR-BTC market bchdcr - RPC wallets on BCH-DCR market +bchspvdcr - Bitcoin Cash SPV wallet and Decred RPC Wallet on BCH-DCR market ltcdcr - RPC wallets on LTC-DCR market ltcelectrumdcr - Litecoin Electrum wallet and Decred RPC wallet on LTC-DCR market dcrdoge - RPC wallets on DCR-DOGE market diff --git a/dex/errors.go b/dex/errors.go index 2abac8ea4c..947e647fc4 100644 --- a/dex/errors.go +++ b/dex/errors.go @@ -37,3 +37,46 @@ func NewError(err error, detail string) Error { detail: detail, } } + +// ErrorCloser is used to synchronize shutdown when an error is encountered in a +// multi-step process. After each successful step, a shutdown routine can be +// scheduled with Add. If Success is not signaled before Done, the shutdown +// routines will be run in the reverse order that they are added. +type ErrorCloser struct { + log Logger + closers []func() error + success bool +} + +// NewErrorCloser creates a new ErrorCloser. +func NewErrorCloser(log Logger) *ErrorCloser { + return &ErrorCloser{ + log: log, + closers: make([]func() error, 0, 3), + } +} + +// Add adds a new function to the queue. If Success is not called before Done, +// the Add'ed functions will be run in the reverse order that they were added. +func (e *ErrorCloser) Add(closer func() error) { + e.closers = append(e.closers, closer) +} + +// Success cancels the running of any Add'ed functions. +func (e *ErrorCloser) Success() { + e.success = true +} + +// Done signals that the ErrorClose can run its registered functions if success +// has not yet been flagged. +func (e *ErrorCloser) Done() { + if e.success { + return + } + + for i := len(e.closers) - 1; i >= 0; i-- { + if err := e.closers[i](); err != nil { + e.log.Errorf("error running shutdown function %d: %v", i, err) + } + } +} diff --git a/dex/networks/bch/cashaddr.go b/dex/networks/bch/cashaddr.go index f95316d214..d6a4c3ae4f 100644 --- a/dex/networks/bch/cashaddr.go +++ b/dex/networks/bch/cashaddr.go @@ -22,25 +22,26 @@ func RecodeCashAddress(addr string, net *chaincfg.Params) (string, error) { return EncodeCashAddress(btcAddr, net) } -// EncodeCashAddress converts a btcutil.Address that the BTC backend into a Cash -// Address string. For example, if a pkScript was decoded to a btcutil.Address, -// the correct address string would not be from the Address' String method, but -// from EncodeCashAddress. This is more direct than doing -// RecodeCashAddress(addr.String()), which needlessly decodes the string. -func EncodeCashAddress(btcAddr btcutil.Address, net *chaincfg.Params) (string, error) { - var bchAddr bchutil.Address - var err error +func BTCAddrToBCHAddr(btcAddr btcutil.Address, net *chaincfg.Params) (bchutil.Address, error) { switch at := btcAddr.(type) { case *btcutil.AddressPubKeyHash: - bchAddr, err = bchutil.NewAddressPubKeyHash(btcAddr.ScriptAddress(), convertParams(net)) + return bchutil.NewAddressPubKeyHash(btcAddr.ScriptAddress(), convertParams(net)) case *btcutil.AddressScriptHash: - bchAddr, err = bchutil.NewAddressScriptHashFromHash(btcAddr.ScriptAddress(), convertParams(net)) + return bchutil.NewAddressScriptHashFromHash(btcAddr.ScriptAddress(), convertParams(net)) case *btcutil.AddressPubKey: - bchAddr, err = bchutil.NewAddressPubKey(btcAddr.ScriptAddress(), convertParams(net)) + return bchutil.NewAddressPubKey(btcAddr.ScriptAddress(), convertParams(net)) default: - return "", fmt.Errorf("unsupported address type %T", at) + return nil, fmt.Errorf("unsupported address type %T", at) } +} +// EncodeCashAddress converts a btcutil.Address that the BTC backend into a Cash +// Address string. For example, if a pkScript was decoded to a btcutil.Address, +// the correct address string would not be from the Address' String method, but +// from EncodeCashAddress. This is more direct than doing +// RecodeCashAddress(addr.String()), which needlessly decodes the string. +func EncodeCashAddress(btcAddr btcutil.Address, net *chaincfg.Params) (string, error) { + bchAddr, err := BTCAddrToBCHAddr(btcAddr, net) if err != nil { return "", err } @@ -48,14 +49,7 @@ func EncodeCashAddress(btcAddr btcutil.Address, net *chaincfg.Params) (string, e return withPrefix(bchAddr, net), nil } -// DecodeCashAddress decodes a Cash Address string into a btcutil.Address -// that the BTC backend can use internally. -func DecodeCashAddress(addr string, net *chaincfg.Params) (btcutil.Address, error) { - bchAddr, err := bchutil.DecodeAddress(addr, convertParams(net)) - if err != nil { - return nil, fmt.Errorf("error decoding CashAddr address: %v", err) - } - +func BCHAddrtoBTCAddr(bchAddr bchutil.Address, net *chaincfg.Params) (btcutil.Address, error) { switch at := bchAddr.(type) { // From what I can tell, the legacy address formats are probably // unnecessary, but I'd hate to be wrong. @@ -70,6 +64,17 @@ func DecodeCashAddress(addr string, net *chaincfg.Params) (btcutil.Address, erro } } +// DecodeCashAddress decodes a Cash Address string into a btcutil.Address +// that the BTC backend can use internally. +func DecodeCashAddress(addr string, net *chaincfg.Params) (btcutil.Address, error) { + bchAddr, err := bchutil.DecodeAddress(addr, convertParams(net)) + if err != nil { + return nil, fmt.Errorf("error decoding CashAddr address: %v", err) + } + + return BCHAddrtoBTCAddr(bchAddr, net) +} + // convertParams converts the btcd/*chaincfg.Params to a bchd/*chaincfg.Params. func convertParams(btcParams *chaincfg.Params) *bchchaincfg.Params { switch btcParams.Net { diff --git a/dex/testing/bch/harness.sh b/dex/testing/bch/harness.sh index a785b6275f..87561b9392 100755 --- a/dex/testing/bch/harness.sh +++ b/dex/testing/bch/harness.sh @@ -23,5 +23,7 @@ export DELTA_WALLET_SEED="cURsyTZ8icuTHwWxSfTC2Geu2F6dMRtnzt1gvSaxHdc9Zf6eviJN" export DELTA_ADDRESS="bchreg:qzhru360ks09fgzuh0ycpvslslvpj72ulqlw5j6ksy" # $1 is the node to create with. $2 is the wallet name export NEW_WALLET_CMD="./\$1 createwallet \$2" +export GODAEMON="go run github.com/gcash/bchd@v0.19.0" +export GOCLIENT="go run github.com/gcash/bchd/cmd/bchctl@v0.19.0" # Run the harness ../btc/base-harness.sh diff --git a/dex/testing/btc/base-harness.sh b/dex/testing/btc/base-harness.sh index ecf5ae11cf..afa05287dc 100755 --- a/dex/testing/btc/base-harness.sh +++ b/dex/testing/btc/base-harness.sh @@ -200,6 +200,7 @@ cat > "${HARNESS_DIR}/quit" < /dev/null + DAEMON_INSTALLED=$? + + if [ $DAEMON_INSTALLED -eq 0 ]; then + echo "Go node found. Starting" + + tmux new-window -t $SESSION:3 -n "go-node" $SHELL + tmux send-keys -t $SESSION:3 "set +o history" C-m + + $GOCLIENT --version &> /dev/null + CLIENT_INSTALLED=$? + if [ $DAEMON_INSTALLED -eq 0 ]; then + echo "${GOCLIENT} installed" + + OMEGA_DIR="${NODES_ROOT}/gonode" + mkdir -p "${OMEGA_DIR}" + + NODE_CONF="${OMEGA_DIR}/gonode.conf" + CLIENT_CONF="${OMEGA_DIR}/goctl.conf" + OMEGA_RPC_PORT=21558 + +cat > "${NODE_CONF}" < "${CLIENT_CONF}" < "${HARNESS_DIR}/omega" < ../../../ +replace github.com/gcash/neutrino => github.com/buck54321/neutrino-bch v0.0.0-20220616193517-b8fcce55a27c + require ( decred.org/dcrdex v0.0.0-20220620230547-1283356d184b github.com/Shopify/toxiproxy/v2 v2.4.0 @@ -30,6 +32,7 @@ require ( github.com/btcsuite/btcwallet/walletdb v1.4.0 // indirect github.com/btcsuite/btcwallet/wtxmgr v1.5.0 // indirect github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd // indirect + github.com/btcsuite/golangcrypto v0.0.0-20150304025918-53f62d9b43e8 // indirect github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect @@ -37,7 +40,8 @@ require ( github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dchest/blake2b v1.0.0 // indirect - github.com/dchest/siphash v1.2.2 // indirect + github.com/dchest/siphash v1.2.3 // indirect + github.com/dcrlabs/neutrino-bch v0.0.0-20220809174944-921b271ba678 // indirect github.com/deckarep/golang-set v1.8.0 // indirect github.com/decred/base58 v1.0.4 // indirect github.com/decred/dcrd/addrmgr/v2 v2.0.0 // indirect @@ -75,6 +79,9 @@ require ( github.com/gcash/bchd v0.19.0 // indirect github.com/gcash/bchlog v0.0.0-20180913005452-b4f036f92fa6 // indirect github.com/gcash/bchutil v0.0.0-20210113190856-6ea28dff4000 // indirect + github.com/gcash/bchwallet v0.10.0 // indirect + github.com/gcash/bchwallet/walletdb v0.0.0-20210524114850-4837f9798568 // indirect + github.com/gcash/neutrino v0.0.0-20210524114821-3b1878290cf9 // indirect github.com/go-chi/chi/v5 v5.0.1 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-stack/stack v1.8.0 // indirect @@ -111,7 +118,7 @@ require ( github.com/prometheus/tsdb v0.7.1 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/rjeczalik/notify v0.9.1 // indirect - github.com/rs/cors v1.7.0 // indirect + github.com/rs/cors v1.8.2 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 // indirect @@ -121,15 +128,16 @@ require ( github.com/tyler-smith/go-bip39 v1.1.0 // indirect github.com/urfave/cli/v2 v2.10.2 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect + github.com/zquestz/grab v0.0.0-20190224022517-abcee96e61b1 // indirect go.etcd.io/bbolt v1.3.7-0.20220130032806-d5db64bdbfde // indirect golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122 // indirect golang.org/x/net v0.0.0-20220607020251-c690dde0001d // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect - golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect + golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect - google.golang.org/protobuf v1.26.0 // indirect + google.golang.org/protobuf v1.28.0 // indirect gopkg.in/ini.v1 v1.66.4 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect lukechampine.com/blake3 v1.1.7 // indirect diff --git a/dex/testing/loadbot/go.sum b/dex/testing/loadbot/go.sum index 4ce3753c63..2ccaec37ac 100644 --- a/dex/testing/loadbot/go.sum +++ b/dex/testing/loadbot/go.sum @@ -153,16 +153,24 @@ github.com/btcsuite/btcwallet/wtxmgr v1.5.0 h1:WO0KyN4l6H3JWnlFxfGR7r3gDnlGT7W2c github.com/btcsuite/btcwallet/wtxmgr v1.5.0/go.mod h1:TQVDhFxseiGtZwEPvLgtfyxuNUDsIdaJdshvWzR0HJ4= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/golangcrypto v0.0.0-20150304025918-53f62d9b43e8 h1:nOsAWScwueMVk/VLm/dvQQD7DuanyvAUb6B3P3eT274= +github.com/btcsuite/golangcrypto v0.0.0-20150304025918-53f62d9b43e8/go.mod h1:tYvUd8KLhm/oXvUeSEs2VlLghFjQt9+ZaF9ghH0JNjc= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/goleveldb v1.0.0 h1:Tvd0BfvqX9o823q1j2UZ/epQo09eJh6dTcRp79ilIN4= github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/snappy-go v1.0.0 h1:ZxaA6lo2EpxGddsA8JwWOcxlzRybb444sgmeJQMJGQE= github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3SkEwmHoWBmX1DNXhXZqlTpq6s4tyJGc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/buck54321/neutrino-bch v0.0.0-20220616193517-b8fcce55a27c h1:4rjc12CvMWS2yIZ/cCDYkjulw1pXUnKkKk60QGgeDBA= +github.com/buck54321/neutrino-bch v0.0.0-20220616193517-b8fcce55a27c/go.mod h1:MshBO/Xf8SCndZFetZ8yg79db/JghnOiMmPiY1Eatlw= github.com/bufbuild/buf v0.37.0/go.mod h1:lQ1m2HkIaGOFba6w/aC3KYBHhKEOESP3gaAEpS3dAFM= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= @@ -181,6 +189,11 @@ github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/companyzero/sntrup4591761 v0.0.0-20200131011700-2b0d299dbd22 h1:vfqLMkB1UqwJliW0I/34oscQawInrVfL1uPjGEEt2YY= @@ -212,8 +225,11 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/dchest/blake2b v1.0.0 h1:KK9LimVmE0MjRl9095XJmKqZ+iLxWATvlcpVFRtaw6s= github.com/dchest/blake2b v1.0.0/go.mod h1:U034kXgbJpCle2wSk5ybGIVhOSHCVLMDqOzcPEA0F7s= github.com/dchest/siphash v1.2.1/go.mod h1:q+IRvb2gOSrUnYoPqHiyHXS0FOBBOdl6tONBlVnOnt4= -github.com/dchest/siphash v1.2.2 h1:9DFz8tQwl9pTVt5iok/9zKyzA1Q6bRGiF3HPiEEVr9I= github.com/dchest/siphash v1.2.2/go.mod h1:q+IRvb2gOSrUnYoPqHiyHXS0FOBBOdl6tONBlVnOnt4= +github.com/dchest/siphash v1.2.3 h1:QXwFc8cFOR2dSa/gE6o/HokBMWtLUaNDVd+22aKHeEA= +github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc= +github.com/dcrlabs/neutrino-bch v0.0.0-20220809174944-921b271ba678 h1:1/HDT7cXD/3PvaPxantDm0De/asWwFd3W9/EXZP7Hc8= +github.com/dcrlabs/neutrino-bch v0.0.0-20220809174944-921b271ba678/go.mod h1:Iq+pOckoLj0Hj7C0W3/bEDpVAj7moSxP5W1v3R0Mhl4= github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4= github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo= github.com/decred/base58 v1.0.3/go.mod h1:pXP9cXCfM2sFLb2viz2FNIdeMWmZDBKG3ZBYbiSM78E= @@ -299,6 +315,8 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.0.14/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/esimonov/ifshort v1.0.2/go.mod h1:yZqNJUrNn20K8Q9n2CrjTKYyVEmX209Hgu+M1LBpeZE= @@ -326,6 +344,7 @@ github.com/gcash/bchd v0.14.7/go.mod h1:Gk/O1ktRVW5Kao0RsnVXp3bWxeYQadqawZ1Im9HE github.com/gcash/bchd v0.15.2/go.mod h1:k9wIjgwnhbrAw+ruIPZ2tHZMzfFNdyUnORZZX7lqXGY= github.com/gcash/bchd v0.17.1/go.mod h1:qwEZ/wr6LyUo5IBgAPcAbYHzXrjnr5gc4tj03n1TwKc= github.com/gcash/bchd v0.17.2-0.20201218180520-5708823e0e99/go.mod h1:qwEZ/wr6LyUo5IBgAPcAbYHzXrjnr5gc4tj03n1TwKc= +github.com/gcash/bchd v0.18.1/go.mod h1:Ev71ERU8MTkTRNFPeNox+9Vz/ZWX0ejpkwgZW/ophgw= github.com/gcash/bchd v0.19.0 h1:qM1wHgb9FlO95f1tj3q2deHVW7c7gB7GRnz2xVpn8EY= github.com/gcash/bchd v0.19.0/go.mod h1:Ev71ERU8MTkTRNFPeNox+9Vz/ZWX0ejpkwgZW/ophgw= github.com/gcash/bchlog v0.0.0-20180913005452-b4f036f92fa6 h1:3pZvWJ8MSfWstGrb8Hfh4ZpLyZNcXypcGx2Ju4ZibVM= @@ -335,7 +354,15 @@ github.com/gcash/bchutil v0.0.0-20191012211144-98e73ec336ba/go.mod h1:nUIrcbbtEQ github.com/gcash/bchutil v0.0.0-20200506001747-c2894cd54b33/go.mod h1:wB++2ZcHUvGLN1OgO9swBmJK1vmyshJLW9SNS+apXwc= github.com/gcash/bchutil v0.0.0-20210113190856-6ea28dff4000 h1:vVi7Ym3I9T4ZKhQy0/XLKzS3xAqX4K+/cSAmnvMR+HM= github.com/gcash/bchutil v0.0.0-20210113190856-6ea28dff4000/go.mod h1:H2USFGwtiu6CNMxiVQPqZkDzsoVSt9BLNqTfBBqGXRo= +github.com/gcash/bchwallet v0.8.3-0.20210524112536-14ca25bc6549/go.mod h1:4hGEkghrAx5yIOdvakkRP5ZT8K/ZMtJhrXXr1Mc6lz4= +github.com/gcash/bchwallet v0.10.0 h1:kAd5q585B/QpjZxv6JAvDYVn1KJpCK8IePzjfUvlYl0= +github.com/gcash/bchwallet v0.10.0/go.mod h1:7Uftb3ZU9+iM5nEpLT2502aYi2x+OuUOo7A7rl13kvw= +github.com/gcash/bchwallet/walletdb v0.0.0-20210524044131-61bcca2ae6f9/go.mod h1:KNPI56t8uMlItrGyu3tS4NCd3jGfA6KjdUg4bsk+QJg= +github.com/gcash/bchwallet/walletdb v0.0.0-20210524114850-4837f9798568 h1:lUckiJp1DwpCHFi8IuvtssDS3i3VHqkyluksH0IhL64= +github.com/gcash/bchwallet/walletdb v0.0.0-20210524114850-4837f9798568/go.mod h1:KNPI56t8uMlItrGyu3tS4NCd3jGfA6KjdUg4bsk+QJg= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/go-chi/chi/v5 v5.0.1 h1:ALxjCrTf1aflOlkhMnCUP86MubbWFrzB3gkRPReLpTo= github.com/go-chi/chi/v5 v5.0.1/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-critic/go-critic v0.5.6/go.mod h1:cVjj0DfqewQVIlIAGexPCaGaZDAqGE29PYDDADIVNEo= @@ -346,14 +373,21 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= @@ -376,6 +410,9 @@ github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2 github.com/go-toolsmith/typep v1.0.2/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU= github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= @@ -387,6 +424,7 @@ github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog= github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -453,8 +491,10 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -512,7 +552,9 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.4.0/go.mod h1:IOyTYjcIO0rkmnGBfJTL0NJ11exy/Tc2QEuv7hCXp24= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.10.0/go.mod h1:XnLCLFp3tjoZJszVKjfpyAK6J8sYIcQXWQxmqLWF21I= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= @@ -561,14 +603,18 @@ github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/improbable-eng/grpc-web v0.9.1/go.mod h1:6hRR09jOEG81ADP5wCQju1z71g6OL4eEvELdran/3cs= github.com/improbable-eng/grpc-web v0.13.0/go.mod h1:6hRR09jOEG81ADP5wCQju1z71g6OL4eEvELdran/3cs= +github.com/improbable-eng/grpc-web v0.14.0/go.mod h1:6hRR09jOEG81ADP5wCQju1z71g6OL4eEvELdran/3cs= +github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPtwNr0l57L4f878wP8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jarcoal/httpmock v1.0.8/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v0.0.0-20181221193153-c0795c8afcf4/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.1-0.20200711081900-c17162fe8fd7/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jgautheron/goconst v1.4.0/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= github.com/jhump/protoreflect v1.6.1/go.mod h1:RZQ/lnuN+zqeRVpQigTwO6o0AJUkxbnSnpuG7toUTG4= github.com/jhump/protoreflect v1.8.1/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg= @@ -591,7 +637,10 @@ github.com/jrick/wsrpc/v2 v2.3.4/go.mod h1:XPYs8BnRWl99lCvXRM5SLpZmTPqWpSOPkDIqY github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -610,9 +659,12 @@ github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6 github.com/kkdai/bstream v0.0.0-20181106074824-b3251f7901ec/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/kkdai/bstream v1.0.0 h1:Se5gHwgp2VT2uHfDrkbbgbgEvV9cimLELwrPJctSjg8= github.com/kkdai/bstream v1.0.0/go.mod h1:FDnDOHt5Yx4p3FaHcioFT0QjDOtgUpvjeZqAs+NVZZA= +github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.0/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.15.2/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= @@ -633,6 +685,7 @@ github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+ github.com/kyoh86/exportloopref v0.1.8/go.mod h1:1tUcJeiioIs7VWe5gcOObrux3lb66+sBqGZrRkMwPgg= github.com/ldez/gomoddirectives v0.2.1/go.mod h1:sGicqkRgBOg//JfpXwkB9Hj0X5RyJ7mlACM5B9f6Me4= github.com/ldez/tagliatelle v0.2.0/go.mod h1:8s6WJQwEYHbKZDsp/LjArytKOG8qaMrKQQ3mFukHs88= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/letsencrypt/pkcs11key/v4 v4.0.0/go.mod h1:EFUvBDay26dErnNb70Nd0/VW3tJiIbETBPTl9ATXQag= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= @@ -687,6 +740,8 @@ github.com/mgechev/dots v0.0.0-20190921121421-c36f7dcfbb81/go.mod h1:KQ7+USdGKfp github.com/mgechev/revive v1.0.6/go.mod h1:Lj5gIVxjBlH8REa3icEOkdfchwYc291nShzZ4QYWyMo= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/miekg/dns v1.1.42/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= +github.com/miekg/dns v1.1.48/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -710,6 +765,7 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/moricho/tparallel v0.2.1/go.mod h1:fXEIZxG2vdfl0ZF8b42f5a78EhjjD5mX8qUplsoSU4k= github.com/mozilla/scribe v0.0.0-20180711195314-fb71baf557c1/go.mod h1:FIczTrinKo8VaLxe6PWTPEXRXDIHz2QAwiaBaP5/4a8= @@ -719,6 +775,7 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007/go.mod h1:m2XC9Qq0AlmmVksL6FktJCdTYyLk7V3fKyp0sl1yWQo= github.com/mwitkow/go-proto-validators v0.2.0/go.mod h1:ZfA1hW+UH/2ZHOWvQ3HnQaU0DtnpXu850MZiy+YUgcc= +github.com/mwitkow/grpc-proxy v0.0.0-20181017164139-0f1106ef9c76/go.mod h1:x5OoJHDHqxHS801UIuhqGl6QdSAEJvtausosHSdazIo= github.com/nakabonne/nestif v0.3.0/go.mod h1:dI314BppzXjJ4HsCnbo7XzrJHPszZsjnk5wEBSYHI2c= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= @@ -811,6 +868,8 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -823,15 +882,21 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.25.0/go.mod h1:H6QK/N6XVT42whUeIdI3dp36w49c+/iMDk7UAI2qm7Q= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.34.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/pseudomuto/protoc-gen-doc v1.3.2/go.mod h1:y5+P6n3iGrbKG+9O04V5ld71in3v/bX88wUwgt+U8EA= @@ -858,8 +923,9 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= +github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= @@ -883,6 +949,7 @@ github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxr github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/simpleledgerinc/goslp v0.0.0-20210310142058-5920ead5c7a0/go.mod h1:H95uvOA9ea+6KkX647VlNLbV+UFBV/i+vPktgnXiQJw= +github.com/simpleledgerinc/goslp v0.0.0-20210423125905-3c2e5f2ef33f/go.mod h1:H95uvOA9ea+6KkX647VlNLbV+UFBV/i+vPktgnXiQJw= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= @@ -957,7 +1024,9 @@ github.com/tommy-muehle/go-mnd/v2 v2.3.2/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr github.com/twitchtv/twirp v7.1.0+incompatible/go.mod h1:RRJoFSAmTEh2weEqWtpPE3vFK5YBhA6bqp2l1kfCC5A= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ultraware/funlen v0.0.3/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= @@ -986,12 +1055,15 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/zquestz/grab v0.0.0-20190224022517-abcee96e61b1 h1:1qKTeMTSIEvRIjvVYzgcRp0xVp0eoiRTTiHSncb5gD8= github.com/zquestz/grab v0.0.0-20190224022517-abcee96e61b1/go.mod h1:bslhAiUxakrA6z6CHmVyvkfpnxx18RJBwVyx2TluJWw= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.5-0.20200615073812-232d8fc87f50/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go.etcd.io/bbolt v1.3.7-0.20220130032806-d5db64bdbfde h1:jqAsjG/dU6OSvhzkskltTptEQ+xeolIxgK2jh5qKqGo= go.etcd.io/bbolt v1.3.7-0.20220130032806-d5db64bdbfde/go.mod h1:sh/Yp01MYDakY7RVfzKZn+T1WOMTTFJrWjl7+M73RXA= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= @@ -1005,6 +1077,7 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.6/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -1039,6 +1112,8 @@ golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122 h1:NvGWuYG8dkDHFSKksI1P9faiVJ9rayE6l0+ouWVIDs8= golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1077,6 +1152,7 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/net v0.0.0-20170915142106-8351a756f30f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1132,7 +1208,14 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210521195947-fe42d452be8f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d h1:4SFsTMi4UahlKoloni7L4eYzhFRifURQLw+yv0QDCx8= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1141,6 +1224,9 @@ golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1209,6 +1295,7 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201022201747-fb209a7c41cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201024232916-9f70ab9862d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1218,6 +1305,7 @@ golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210217105451-b926d437f341/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210228012217-479acdf4ea46/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1227,17 +1315,23 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210521203332-0cec03c779c1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 h1:EH1Deb8WZJ0xc0WK//leUHXcX9aLE5SymusoTmMZye8= +golang.org/x/term v0.0.0-20220411215600-e5f449aeb171/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915090833-1cbadb444a80/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1351,10 +1445,13 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= golang.org/x/tools v0.1.2-0.20210512205948-8287d5da45e4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df h1:5Pf6pFKu98ODmgnpvkJ3kFUOQGGLIzLIkbzUHp47618= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= @@ -1413,6 +1510,7 @@ google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= @@ -1422,9 +1520,12 @@ google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201022181438-0ff5f38871d5/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210207032614-bba0dbe2a9ea/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210426193834-eac7f76ac494/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210521181308-5ccab8a35a9a/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= @@ -1451,9 +1552,12 @@ google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.35.0-dev.0.20201218190559-666aea1fb34c/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.0.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -1468,8 +1572,10 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.25.1-0.20200805231151-a709e31e5d12/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.25.1-0.20201208041424-160c7477e0e8/go.mod h1:hFxJC2f0epmp1elRCiEGJTKAWbwxZ2nvqZdHl3FQXCY= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1523,9 +1629,12 @@ mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIa mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= mvdan.cc/unparam v0.0.0-20210104141923-aac4ce9116a7/go.mod h1:hBpJkZE8H/sb+VRFvw2+rBpHNsTBcvSpk61hr8mzXZE= mvdan.cc/unparam v0.0.0-20210520122750-2ac67f130a88/go.mod h1:hBpJkZE8H/sb+VRFvw2+rBpHNsTBcvSpk61hr8mzXZE= +nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/go.mod b/go.mod index ff290c4a65..2e8c680c8f 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( github.com/btcsuite/btcwallet/wtxmgr v1.5.0 github.com/davecgh/go-spew v1.1.1 github.com/dchest/blake2b v1.0.0 + github.com/dcrlabs/neutrino-bch v0.0.0-20220809174944-921b271ba678 github.com/decred/base58 v1.0.4 github.com/decred/dcrd/addrmgr/v2 v2.0.0 github.com/decred/dcrd/blockchain/stake/v4 v4.0.0 @@ -41,10 +42,13 @@ require ( github.com/dgraph-io/badger v1.6.2 github.com/ethereum/go-ethereum v1.10.21 github.com/gcash/bchd v0.19.0 + github.com/gcash/bchlog v0.0.0-20180913005452-b4f036f92fa6 github.com/gcash/bchutil v0.0.0-20210113190856-6ea28dff4000 + github.com/gcash/bchwallet v0.10.0 + github.com/gcash/bchwallet/walletdb v0.0.0-20210524114850-4837f9798568 github.com/go-chi/chi/v5 v5.0.1 github.com/gorilla/websocket v1.5.0 - github.com/jessevdk/go-flags v1.4.1-0.20200711081900-c17162fe8fd7 + github.com/jessevdk/go-flags v1.5.0 github.com/jrick/logrotate v1.0.0 github.com/lib/pq v1.10.4 github.com/lightninglabs/neutrino v0.14.2 @@ -53,7 +57,7 @@ require ( go.etcd.io/bbolt v1.3.7-0.20220130032806-d5db64bdbfde golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c - golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 + golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 golang.org/x/text v0.3.7 golang.org/x/time v0.0.0-20220411224347-583f2d630306 gopkg.in/ini.v1 v1.66.4 @@ -70,12 +74,13 @@ require ( github.com/btcsuite/btcwallet/wallet/txrules v1.2.0 // indirect github.com/btcsuite/btcwallet/wallet/txsizes v1.1.0 // indirect github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd // indirect + github.com/btcsuite/golangcrypto v0.0.0-20150304025918-53f62d9b43e8 // indirect github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/companyzero/sntrup4591761 v0.0.0-20200131011700-2b0d299dbd22 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect - github.com/dchest/siphash v1.2.2 // indirect + github.com/dchest/siphash v1.2.3 // indirect github.com/deckarep/golang-set v1.8.0 // indirect github.com/decred/dcrd/blockchain/standalone/v2 v2.1.0 // indirect github.com/decred/dcrd/crypto/ripemd160 v1.0.1 // indirect @@ -86,7 +91,7 @@ require ( github.com/edsrzf/mmap-go v1.0.0 // indirect github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 // indirect github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect - github.com/gcash/bchlog v0.0.0-20180913005452-b4f036f92fa6 // indirect + github.com/gcash/neutrino v0.0.0-20210524114821-3b1878290cf9 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-stack/stack v1.8.0 // indirect github.com/golang-jwt/jwt/v4 v4.3.0 // indirect @@ -118,7 +123,7 @@ require ( github.com/prometheus/tsdb v0.7.1 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/rjeczalik/notify v0.9.1 // indirect - github.com/rs/cors v1.7.0 // indirect + github.com/rs/cors v1.8.2 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 // indirect @@ -127,8 +132,9 @@ require ( github.com/tklauser/numcpus v0.2.2 // indirect github.com/urfave/cli/v2 v2.10.2 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect + github.com/zquestz/grab v0.0.0-20190224022517-abcee96e61b1 // indirect golang.org/x/net v0.0.0-20220607020251-c690dde0001d // indirect golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect - google.golang.org/protobuf v1.26.0 // indirect + google.golang.org/protobuf v1.28.0 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect ) diff --git a/go.sum b/go.sum index ea28074976..e898885cc9 100644 --- a/go.sum +++ b/go.sum @@ -107,6 +107,7 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/bkielbasa/cyclop v1.2.0/go.mod h1:qOI0yy6A7dYC4Zgsa72Ppm9kONl0RoIlPbzot9mhmeI= github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0= +github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/bombsimon/wsl/v3 v3.3.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2Pm1FNZIc= 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= @@ -151,9 +152,13 @@ github.com/btcsuite/btcwallet/wtxmgr v1.5.0 h1:WO0KyN4l6H3JWnlFxfGR7r3gDnlGT7W2c github.com/btcsuite/btcwallet/wtxmgr v1.5.0/go.mod h1:TQVDhFxseiGtZwEPvLgtfyxuNUDsIdaJdshvWzR0HJ4= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/golangcrypto v0.0.0-20150304025918-53f62d9b43e8 h1:nOsAWScwueMVk/VLm/dvQQD7DuanyvAUb6B3P3eT274= +github.com/btcsuite/golangcrypto v0.0.0-20150304025918-53f62d9b43e8/go.mod h1:tYvUd8KLhm/oXvUeSEs2VlLghFjQt9+ZaF9ghH0JNjc= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/goleveldb v1.0.0 h1:Tvd0BfvqX9o823q1j2UZ/epQo09eJh6dTcRp79ilIN4= github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/snappy-go v1.0.0 h1:ZxaA6lo2EpxGddsA8JwWOcxlzRybb444sgmeJQMJGQE= github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3SkEwmHoWBmX1DNXhXZqlTpq6s4tyJGc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= @@ -161,6 +166,8 @@ github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46f github.com/bufbuild/buf v0.37.0/go.mod h1:lQ1m2HkIaGOFba6w/aC3KYBHhKEOESP3gaAEpS3dAFM= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= @@ -178,7 +185,13 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/companyzero/sntrup4591761 v0.0.0-20200131011700-2b0d299dbd22 h1:vfqLMkB1UqwJliW0I/34oscQawInrVfL1uPjGEEt2YY= @@ -210,8 +223,11 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/dchest/blake2b v1.0.0 h1:KK9LimVmE0MjRl9095XJmKqZ+iLxWATvlcpVFRtaw6s= github.com/dchest/blake2b v1.0.0/go.mod h1:U034kXgbJpCle2wSk5ybGIVhOSHCVLMDqOzcPEA0F7s= github.com/dchest/siphash v1.2.1/go.mod h1:q+IRvb2gOSrUnYoPqHiyHXS0FOBBOdl6tONBlVnOnt4= -github.com/dchest/siphash v1.2.2 h1:9DFz8tQwl9pTVt5iok/9zKyzA1Q6bRGiF3HPiEEVr9I= github.com/dchest/siphash v1.2.2/go.mod h1:q+IRvb2gOSrUnYoPqHiyHXS0FOBBOdl6tONBlVnOnt4= +github.com/dchest/siphash v1.2.3 h1:QXwFc8cFOR2dSa/gE6o/HokBMWtLUaNDVd+22aKHeEA= +github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc= +github.com/dcrlabs/neutrino-bch v0.0.0-20220809174944-921b271ba678 h1:1/HDT7cXD/3PvaPxantDm0De/asWwFd3W9/EXZP7Hc8= +github.com/dcrlabs/neutrino-bch v0.0.0-20220809174944-921b271ba678/go.mod h1:Iq+pOckoLj0Hj7C0W3/bEDpVAj7moSxP5W1v3R0Mhl4= github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4= github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo= github.com/decred/base58 v1.0.3/go.mod h1:pXP9cXCfM2sFLb2viz2FNIdeMWmZDBKG3ZBYbiSM78E= @@ -295,8 +311,11 @@ github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4s github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.0.14/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/esimonov/ifshort v1.0.2/go.mod h1:yZqNJUrNn20K8Q9n2CrjTKYyVEmX209Hgu+M1LBpeZE= @@ -324,6 +343,9 @@ github.com/gcash/bchd v0.14.7/go.mod h1:Gk/O1ktRVW5Kao0RsnVXp3bWxeYQadqawZ1Im9HE github.com/gcash/bchd v0.15.2/go.mod h1:k9wIjgwnhbrAw+ruIPZ2tHZMzfFNdyUnORZZX7lqXGY= github.com/gcash/bchd v0.17.1/go.mod h1:qwEZ/wr6LyUo5IBgAPcAbYHzXrjnr5gc4tj03n1TwKc= github.com/gcash/bchd v0.17.2-0.20201218180520-5708823e0e99/go.mod h1:qwEZ/wr6LyUo5IBgAPcAbYHzXrjnr5gc4tj03n1TwKc= +github.com/gcash/bchd v0.18.1-0.20210522092846-10614544cf00/go.mod h1:M8ps+ZMPvdUoqCMoI/aKWKXg8GOE4zTKQpvGK9D940Y= +github.com/gcash/bchd v0.18.1-0.20210524104807-34d7fe5c34b2/go.mod h1:Ev71ERU8MTkTRNFPeNox+9Vz/ZWX0ejpkwgZW/ophgw= +github.com/gcash/bchd v0.18.1/go.mod h1:Ev71ERU8MTkTRNFPeNox+9Vz/ZWX0ejpkwgZW/ophgw= github.com/gcash/bchd v0.19.0 h1:qM1wHgb9FlO95f1tj3q2deHVW7c7gB7GRnz2xVpn8EY= github.com/gcash/bchd v0.19.0/go.mod h1:Ev71ERU8MTkTRNFPeNox+9Vz/ZWX0ejpkwgZW/ophgw= github.com/gcash/bchlog v0.0.0-20180913005452-b4f036f92fa6 h1:3pZvWJ8MSfWstGrb8Hfh4ZpLyZNcXypcGx2Ju4ZibVM= @@ -333,7 +355,24 @@ github.com/gcash/bchutil v0.0.0-20191012211144-98e73ec336ba/go.mod h1:nUIrcbbtEQ github.com/gcash/bchutil v0.0.0-20200506001747-c2894cd54b33/go.mod h1:wB++2ZcHUvGLN1OgO9swBmJK1vmyshJLW9SNS+apXwc= github.com/gcash/bchutil v0.0.0-20210113190856-6ea28dff4000 h1:vVi7Ym3I9T4ZKhQy0/XLKzS3xAqX4K+/cSAmnvMR+HM= github.com/gcash/bchutil v0.0.0-20210113190856-6ea28dff4000/go.mod h1:H2USFGwtiu6CNMxiVQPqZkDzsoVSt9BLNqTfBBqGXRo= +github.com/gcash/bchwallet v0.8.3-0.20210524032547-09a7e9ef6126/go.mod h1:w+CpcX7VBjAiLMq+pkubcbEU6IqJWg/VNu3skgm6RGc= +github.com/gcash/bchwallet v0.8.3-0.20210524084514-53ddbcfd3712/go.mod h1:C7YNuYMdesznEyUVU305/9jtWDkzVbcNU9/ZgwD1QAU= +github.com/gcash/bchwallet v0.8.3-0.20210524112536-14ca25bc6549/go.mod h1:4hGEkghrAx5yIOdvakkRP5ZT8K/ZMtJhrXXr1Mc6lz4= +github.com/gcash/bchwallet v0.10.0 h1:kAd5q585B/QpjZxv6JAvDYVn1KJpCK8IePzjfUvlYl0= +github.com/gcash/bchwallet v0.10.0/go.mod h1:7Uftb3ZU9+iM5nEpLT2502aYi2x+OuUOo7A7rl13kvw= +github.com/gcash/bchwallet/walletdb v0.0.0-20210524032111-4a6e424b2c66/go.mod h1:KNPI56t8uMlItrGyu3tS4NCd3jGfA6KjdUg4bsk+QJg= +github.com/gcash/bchwallet/walletdb v0.0.0-20210524032946-5175b789def6/go.mod h1:KNPI56t8uMlItrGyu3tS4NCd3jGfA6KjdUg4bsk+QJg= +github.com/gcash/bchwallet/walletdb v0.0.0-20210524044131-61bcca2ae6f9/go.mod h1:KNPI56t8uMlItrGyu3tS4NCd3jGfA6KjdUg4bsk+QJg= +github.com/gcash/bchwallet/walletdb v0.0.0-20210524114850-4837f9798568 h1:lUckiJp1DwpCHFi8IuvtssDS3i3VHqkyluksH0IhL64= +github.com/gcash/bchwallet/walletdb v0.0.0-20210524114850-4837f9798568/go.mod h1:KNPI56t8uMlItrGyu3tS4NCd3jGfA6KjdUg4bsk+QJg= +github.com/gcash/neutrino v0.0.0-20210524024247-f7bf0435d155/go.mod h1:91zIrel7tOt35+0hAN8Rrr7O07LZrR9b98Nk4AcC/Lg= +github.com/gcash/neutrino v0.0.0-20210524083541-2900eef48821/go.mod h1:ud/wsgR459Qy+HmEAoQZF9XPTYaOYep5df8ynowCnLs= +github.com/gcash/neutrino v0.0.0-20210524105223-4cec86bbd8a4/go.mod h1:YBR6T+ZT02eR1S7JGqJ2gVPxZlfjWswTCXB4HZafp/U= +github.com/gcash/neutrino v0.0.0-20210524114821-3b1878290cf9 h1:V5UNzi/5pZxE5s6kfCe59VjJRmfkyI+npZizMcAvEdI= +github.com/gcash/neutrino v0.0.0-20210524114821-3b1878290cf9/go.mod h1:MshBO/Xf8SCndZFetZ8yg79db/JghnOiMmPiY1Eatlw= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/go-chi/chi/v5 v5.0.1 h1:ALxjCrTf1aflOlkhMnCUP86MubbWFrzB3gkRPReLpTo= github.com/go-chi/chi/v5 v5.0.1/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-critic/go-critic v0.5.6/go.mod h1:cVjj0DfqewQVIlIAGexPCaGaZDAqGE29PYDDADIVNEo= @@ -344,14 +383,21 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= @@ -374,6 +420,9 @@ github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2 github.com/go-toolsmith/typep v1.0.2/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU= github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= @@ -385,6 +434,7 @@ github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog= github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -451,8 +501,10 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -510,7 +562,10 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.1.0/go.mod h1:ly5QWKtiqC7tGfzgXYtpoZYmEWx5Z82/b18ASEL+yGc= github.com/grpc-ecosystem/grpc-gateway/v2 v2.4.0/go.mod h1:IOyTYjcIO0rkmnGBfJTL0NJ11exy/Tc2QEuv7hCXp24= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.10.0/go.mod h1:XnLCLFp3tjoZJszVKjfpyAK6J8sYIcQXWQxmqLWF21I= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= @@ -559,15 +614,19 @@ github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/improbable-eng/grpc-web v0.9.1/go.mod h1:6hRR09jOEG81ADP5wCQju1z71g6OL4eEvELdran/3cs= github.com/improbable-eng/grpc-web v0.13.0/go.mod h1:6hRR09jOEG81ADP5wCQju1z71g6OL4eEvELdran/3cs= +github.com/improbable-eng/grpc-web v0.14.0/go.mod h1:6hRR09jOEG81ADP5wCQju1z71g6OL4eEvELdran/3cs= +github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPtwNr0l57L4f878wP8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jarcoal/httpmock v1.0.8/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v0.0.0-20181221193153-c0795c8afcf4/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jessevdk/go-flags v1.4.1-0.20200711081900-c17162fe8fd7 h1:Ug59miTxVKVg5Oi2S5uHlKOIV5jBx4Hb2u0jIxxDaSs= github.com/jessevdk/go-flags v1.4.1-0.20200711081900-c17162fe8fd7/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= +github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jgautheron/goconst v1.4.0/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= github.com/jhump/protoreflect v1.6.1/go.mod h1:RZQ/lnuN+zqeRVpQigTwO6o0AJUkxbnSnpuG7toUTG4= github.com/jhump/protoreflect v1.8.1/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg= @@ -590,7 +649,10 @@ github.com/jrick/wsrpc/v2 v2.3.4/go.mod h1:XPYs8BnRWl99lCvXRM5SLpZmTPqWpSOPkDIqY github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -609,9 +671,12 @@ github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6 github.com/kkdai/bstream v0.0.0-20181106074824-b3251f7901ec/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/kkdai/bstream v1.0.0 h1:Se5gHwgp2VT2uHfDrkbbgbgEvV9cimLELwrPJctSjg8= github.com/kkdai/bstream v1.0.0/go.mod h1:FDnDOHt5Yx4p3FaHcioFT0QjDOtgUpvjeZqAs+NVZZA= +github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.0/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.15.2/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= @@ -632,6 +697,7 @@ github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+ github.com/kyoh86/exportloopref v0.1.8/go.mod h1:1tUcJeiioIs7VWe5gcOObrux3lb66+sBqGZrRkMwPgg= github.com/ldez/gomoddirectives v0.2.1/go.mod h1:sGicqkRgBOg//JfpXwkB9Hj0X5RyJ7mlACM5B9f6Me4= github.com/ldez/tagliatelle v0.2.0/go.mod h1:8s6WJQwEYHbKZDsp/LjArytKOG8qaMrKQQ3mFukHs88= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/letsencrypt/pkcs11key/v4 v4.0.0/go.mod h1:EFUvBDay26dErnNb70Nd0/VW3tJiIbETBPTl9ATXQag= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= @@ -686,6 +752,8 @@ github.com/mgechev/dots v0.0.0-20190921121421-c36f7dcfbb81/go.mod h1:KQ7+USdGKfp github.com/mgechev/revive v1.0.6/go.mod h1:Lj5gIVxjBlH8REa3icEOkdfchwYc291nShzZ4QYWyMo= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/miekg/dns v1.1.42/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= +github.com/miekg/dns v1.1.48/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -709,6 +777,7 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/moricho/tparallel v0.2.1/go.mod h1:fXEIZxG2vdfl0ZF8b42f5a78EhjjD5mX8qUplsoSU4k= github.com/mozilla/scribe v0.0.0-20180711195314-fb71baf557c1/go.mod h1:FIczTrinKo8VaLxe6PWTPEXRXDIHz2QAwiaBaP5/4a8= @@ -718,6 +787,7 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007/go.mod h1:m2XC9Qq0AlmmVksL6FktJCdTYyLk7V3fKyp0sl1yWQo= github.com/mwitkow/go-proto-validators v0.2.0/go.mod h1:ZfA1hW+UH/2ZHOWvQ3HnQaU0DtnpXu850MZiy+YUgcc= +github.com/mwitkow/grpc-proxy v0.0.0-20181017164139-0f1106ef9c76/go.mod h1:x5OoJHDHqxHS801UIuhqGl6QdSAEJvtausosHSdazIo= github.com/nakabonne/nestif v0.3.0/go.mod h1:dI314BppzXjJ4HsCnbo7XzrJHPszZsjnk5wEBSYHI2c= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= @@ -809,7 +879,10 @@ github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDf github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.9.0/go.mod h1:FqZLKOZnGdFAhOK4nqGHa7D66IdsO+O441Eve7ptJDU= github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -822,15 +895,22 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.25.0/go.mod h1:H6QK/N6XVT42whUeIdI3dp36w49c+/iMDk7UAI2qm7Q= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.34.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/pseudomuto/protoc-gen-doc v1.3.2/go.mod h1:y5+P6n3iGrbKG+9O04V5ld71in3v/bX88wUwgt+U8EA= @@ -857,8 +937,9 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= +github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= @@ -882,6 +963,7 @@ github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxr github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/simpleledgerinc/goslp v0.0.0-20210310142058-5920ead5c7a0/go.mod h1:H95uvOA9ea+6KkX647VlNLbV+UFBV/i+vPktgnXiQJw= +github.com/simpleledgerinc/goslp v0.0.0-20210423125905-3c2e5f2ef33f/go.mod h1:H95uvOA9ea+6KkX647VlNLbV+UFBV/i+vPktgnXiQJw= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= @@ -958,7 +1040,9 @@ github.com/tommy-muehle/go-mnd/v2 v2.3.2/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr github.com/twitchtv/twirp v7.1.0+incompatible/go.mod h1:RRJoFSAmTEh2weEqWtpPE3vFK5YBhA6bqp2l1kfCC5A= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ultraware/funlen v0.0.3/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= @@ -987,12 +1071,15 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/zquestz/grab v0.0.0-20190224022517-abcee96e61b1 h1:1qKTeMTSIEvRIjvVYzgcRp0xVp0eoiRTTiHSncb5gD8= github.com/zquestz/grab v0.0.0-20190224022517-abcee96e61b1/go.mod h1:bslhAiUxakrA6z6CHmVyvkfpnxx18RJBwVyx2TluJWw= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.5-0.20200615073812-232d8fc87f50/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go.etcd.io/bbolt v1.3.7-0.20220130032806-d5db64bdbfde h1:jqAsjG/dU6OSvhzkskltTptEQ+xeolIxgK2jh5qKqGo= go.etcd.io/bbolt v1.3.7-0.20220130032806-d5db64bdbfde/go.mod h1:sh/Yp01MYDakY7RVfzKZn+T1WOMTTFJrWjl7+M73RXA= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= @@ -1006,6 +1093,7 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.6/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -1040,6 +1128,8 @@ golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122 h1:NvGWuYG8dkDHFSKksI1P9faiVJ9rayE6l0+ouWVIDs8= golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1078,6 +1168,7 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/net v0.0.0-20170915142106-8351a756f30f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1133,7 +1224,14 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210521195947-fe42d452be8f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d h1:4SFsTMi4UahlKoloni7L4eYzhFRifURQLw+yv0QDCx8= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1141,7 +1239,11 @@ golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1210,15 +1312,18 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201022201747-fb209a7c41cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201024232916-9f70ab9862d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210217105451-b926d437f341/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210228012217-479acdf4ea46/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1228,17 +1333,24 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210521203332-0cec03c779c1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= +golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 h1:EH1Deb8WZJ0xc0WK//leUHXcX9aLE5SymusoTmMZye8= +golang.org/x/term v0.0.0-20220411215600-e5f449aeb171/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915090833-1cbadb444a80/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1352,10 +1464,13 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= golang.org/x/tools v0.1.2-0.20210512205948-8287d5da45e4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df h1:5Pf6pFKu98ODmgnpvkJ3kFUOQGGLIzLIkbzUHp47618= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= @@ -1414,6 +1529,7 @@ google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= @@ -1423,9 +1539,13 @@ google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201022181438-0ff5f38871d5/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210106152847-07624b53cd92/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210207032614-bba0dbe2a9ea/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210426193834-eac7f76ac494/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210521181308-5ccab8a35a9a/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= @@ -1451,10 +1571,14 @@ google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0-dev.0.20201218190559-666aea1fb34c/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.0.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -1469,8 +1593,10 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.25.1-0.20200805231151-a709e31e5d12/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.25.1-0.20201208041424-160c7477e0e8/go.mod h1:hFxJC2f0epmp1elRCiEGJTKAWbwxZ2nvqZdHl3FQXCY= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1524,9 +1650,12 @@ mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIa mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= mvdan.cc/unparam v0.0.0-20210104141923-aac4ce9116a7/go.mod h1:hBpJkZE8H/sb+VRFvw2+rBpHNsTBcvSpk61hr8mzXZE= mvdan.cc/unparam v0.0.0-20210520122750-2ac67f130a88/go.mod h1:hBpJkZE8H/sb+VRFvw2+rBpHNsTBcvSpk61hr8mzXZE= +nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=