Skip to content

Commit

Permalink
Best attempt at not using latest address for db path
Browse files Browse the repository at this point in the history
  • Loading branch information
martonp committed Mar 24, 2024
1 parent 8265a21 commit 8f9e4ba
Show file tree
Hide file tree
Showing 9 changed files with 156 additions and 57 deletions.
44 changes: 34 additions & 10 deletions client/asset/btc/btc.go
Original file line number Diff line number Diff line change
Expand Up @@ -1393,21 +1393,27 @@ func (btc *baseWallet) Info() *asset.WalletInfo {
return btc.walletInfo
}

func (btc *baseWallet) startTxHistoryDB() error {
func (btc *baseWallet) txHistoryDBPath(walletID string) string {
return filepath.Join(btc.walletDir, fmt.Sprintf("txhistory-%s.db", walletID))
}

// findExistingAddressBasedTxHistoryDB finds the path of a tx history db that
// was created using an address controlled by the wallet. This should only be
// used for wallets that are unable to generate a fingerprint.
func (btc *baseWallet) findExistingAddressBasedTxHistoryDB() (string, error) {
dir, err := os.Open(btc.walletDir)
if err != nil {
return fmt.Errorf("error opening wallet directory: %w", err)
return "", fmt.Errorf("error opening wallet directory: %w", err)
}
defer dir.Close()

entries, err := dir.Readdir(0)
if err != nil {
return fmt.Errorf("error reading wallet directory: %w", err)
return "", fmt.Errorf("error reading wallet directory: %w", err)
}

pattern := regexp.MustCompile(`^txhistory-(.+)\.db$`)

var dbPath string
for _, entry := range entries {
if !entry.IsDir() {
continue
Expand All @@ -1421,13 +1427,30 @@ func (btc *baseWallet) startTxHistoryDB() error {
address := match[1]
owns, err := btc.OwnsDepositAddress(address)
if err != nil {
btc.log.Errorf("Error checking if wallet owns deposit address %s: %w", address, err)
continue
}
if owns {
btc.log.Infof("Using tx history db %s", entry.Name())
dbPath = filepath.Join(btc.walletDir, entry.Name())
break
return btc.txHistoryDBPath(entry.Name()), nil
}
}

return "", nil
}

func (btc *baseWallet) startTxHistoryDB() error {
var dbPath string
fingerPrint, err := btc.node.fingerprint()
if err == nil && fingerPrint != "" {
dbPath = btc.txHistoryDBPath(fingerPrint)
}

if dbPath == "" {
addressPath, err := btc.findExistingAddressBasedTxHistoryDB()
if err != nil {
return err
}
if addressPath != "" {
dbPath = addressPath
}
}

Expand All @@ -1436,10 +1459,11 @@ func (btc *baseWallet) startTxHistoryDB() error {
if err != nil {
return fmt.Errorf("error getting deposit address: %w", err)
}
btc.log.Infof("Creating tx history db txhistory-%s.db", depositAddr)
dbPath = filepath.Join(btc.walletDir, fmt.Sprintf("txhistory-%s.db", depositAddr))
}

btc.log.Debugf("Using tx history db at %s", dbPath)

db, err := NewBadgerTxDB(dbPath, btc.log)
if err != nil {
return fmt.Errorf("error opening tx history db: %w", err)
Expand Down Expand Up @@ -5593,7 +5617,7 @@ func (btc *intermediaryWallet) checkPendingTxs(tip uint64) {
// WalletTransaction returns a transaction that either the wallet has made or
// one in which the wallet has received funds. The txID can be either a byte
// reversed tx hash or a hex encoded coin ID.
func (btc *ExchangeWalletSPV) WalletTransaction(ctx context.Context, txID string) (*asset.WalletTransaction, error) {
func (btc *intermediaryWallet) WalletTransaction(ctx context.Context, txID string) (*asset.WalletTransaction, error) {
coinID, err := hex.DecodeString(txID)
if err == nil {
txHash, _, err := decodeCoinID(coinID)
Expand Down
4 changes: 4 additions & 0 deletions client/asset/btc/electrum_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -1030,6 +1030,10 @@ func (ew *electrumWallet) getWalletTransaction(txHash *chainhash.Hash) (*GetTran
}, nil
}

func (ew *electrumWallet) fingerprint() (string, error) {
return "", fmt.Errorf("fingerprint not implemented")
}

// part of the walletTxChecker interface
func (ew *electrumWallet) swapConfirmations(txHash *chainhash.Hash, vout uint32, contract []byte, startTime time.Time) (confs uint32, spent bool, err error) {
// To determine if it is spent, we need the address of the output.
Expand Down
15 changes: 15 additions & 0 deletions client/asset/btc/rpcclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -921,6 +921,21 @@ func (wc *rpcClient) GetWalletInfo() (*GetWalletInfoResult, error) {
return wi, wc.call(methodGetWalletInfo, nil, wi)
}

// fingerprint returns an identifier for this wallet. Only HD wallets will have
// an identifier. Descriptor wallets will not.
func (wc *rpcClient) fingerprint() (string, error) {
walletInfo, err := wc.GetWalletInfo()
if err != nil {
return "", err
}

if walletInfo.HdSeedID == "" {
return "", fmt.Errorf("fingerprint not availble")
}

return walletInfo.HdSeedID, nil
}

// GetAddressInfo gets information about the given address by calling
// getaddressinfo RPC command.
func (wc *rpcClient) getAddressInfo(addr btcutil.Address, method string) (*GetAddressInfoResult, error) {
Expand Down
20 changes: 20 additions & 0 deletions client/asset/btc/spv_wrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -1024,6 +1024,26 @@ func (w *spvWallet) numDerivedAddresses() (internal, external uint32, err error)
return props.InternalKeyCount, props.ExternalKeyCount, nil
}

// fingerprint returns an identifier for this wallet. It is the hash of the
// compressed serialization of the account pub key.
func (w *spvWallet) fingerprint() (string, error) {
props, err := w.wallet.AccountProperties(waddrmgr.KeyScopeBIP0084, w.acctNum)
if err != nil {
return "", err
}

if props.AccountPubKey == nil {
return "", fmt.Errorf("no account key available")
}

pk, err := props.AccountPubKey.ECPubKey()
if err != nil {
return "", err
}

return hex.EncodeToString(btcutil.Hash160(pk.SerializeCompressed())), nil
}

// getTxOut finds an unspent transaction output and its number of confirmations.
// To match the behavior of the RPC method, even if an output is found, if it's
// known to be spent, no *wire.TxOut and no error will be returned.
Expand Down
1 change: 1 addition & 0 deletions client/asset/btc/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ type Wallet interface {
ownsAddress(addr btcutil.Address) (bool, error) // this should probably just take a string
getWalletTransaction(txHash *chainhash.Hash) (*GetTransactionResult, error)
reconfigure(walletCfg *asset.WalletConfig, currentAddress string) (restartRequired bool, err error)
fingerprint() (string, error)
}

type txLister interface {
Expand Down
71 changes: 61 additions & 10 deletions client/asset/dcr/dcr.go
Original file line number Diff line number Diff line change
Expand Up @@ -902,21 +902,28 @@ func (dcr *ExchangeWallet) Info() *asset.WalletInfo {
// }
// }

func (dcr *ExchangeWallet) startTxHistoryDB(ctx context.Context) error {
func (dcr *ExchangeWallet) txHistoryDBPath(walletID string) string {
return filepath.Join(dcr.walletDir, fmt.Sprintf("txhistory-%s.db", walletID))
}

// findExistingAddressBasedTxHistoryDB finds the path of a tx history db that
// was created using an address controlled by the wallet. This should only be
// used for RPC wallets, as SPV wallets are able to get the first address
// generated by the wallet.
func (dcr *ExchangeWallet) findExistingAddressBasedTxHistoryDB() (string, error) {
dir, err := os.Open(dcr.walletDir)
if err != nil {
return fmt.Errorf("error opening wallet directory: %w", err)
return "", fmt.Errorf("error opening wallet directory: %w", err)
}
defer dir.Close()

entries, err := dir.Readdir(0)
if err != nil {
return fmt.Errorf("error reading wallet directory: %w", err)
return "", fmt.Errorf("error reading wallet directory: %w", err)
}

pattern := regexp.MustCompile(`^txhistory-(.+)\.db$`)

var dbPath string
for _, entry := range entries {
if !entry.IsDir() {
continue
Expand All @@ -930,13 +937,34 @@ func (dcr *ExchangeWallet) startTxHistoryDB(ctx context.Context) error {
address := match[1]
owns, err := dcr.OwnsDepositAddress(address)
if err != nil {
dcr.log.Errorf("Error checking if wallet owns deposit address %s: %w", address, err)
continue
}
if owns {
dcr.log.Infof("Using tx history db %s", entry.Name())
dbPath = filepath.Join(dcr.walletDir, entry.Name())
break
return dcr.txHistoryDBPath(entry.Name()), nil
}
}

return "", nil
}

func (dcr *ExchangeWallet) startTxHistoryDB(ctx context.Context) error {
var dbPath string
if spvWallet, ok := dcr.wallet.(*spvWallet); ok {
initialAddress, err := spvWallet.InitialAddress(ctx)
if err != nil {
return err
}

dbPath = dcr.txHistoryDBPath(initialAddress)
}

if dbPath == "" {
addressPath, err := dcr.findExistingAddressBasedTxHistoryDB()
if err != nil {
return err
}
if addressPath != "" {
dbPath = addressPath
}
}

Expand All @@ -945,10 +973,11 @@ func (dcr *ExchangeWallet) startTxHistoryDB(ctx context.Context) error {
if err != nil {
return fmt.Errorf("error getting deposit address: %w", err)
}
dcr.log.Infof("Creating tx history db txhistory-%s.db", depositAddr)
dbPath = filepath.Join(dcr.walletDir, fmt.Sprintf("txhistory-%s.db", depositAddr))
dbPath = dcr.txHistoryDBPath(depositAddr)
}

dcr.log.Debugf("Using tx history db at %s", dbPath)

db, err := btc.NewBadgerTxDB(dbPath, dcr.log)
if err != nil {
return fmt.Errorf("error opening tx history db: %w", err)
Expand Down Expand Up @@ -6410,6 +6439,28 @@ func float64PtrStr(v *float64) string {
return strconv.FormatFloat(*v, 'f', 8, 64)
}

// WalletTransaction returns a transaction that either the wallet has made or
// one in which the wallet has received funds.
func (dcr *ExchangeWallet) WalletTransaction(ctx context.Context, txID string) (*asset.WalletTransaction, error) {
coinID, err := hex.DecodeString(txID)
if err == nil {
txHash, _, err := decodeCoinID(coinID)
if err == nil {
txID = txHash.String()
}
}

txs, err := dcr.TxHistory(1, &txID, false)
if err != nil {
return nil, err
}
if len(txs) == 0 {
return nil, asset.CoinNotFoundError
}

return txs[0], nil
}

// TxHistory returns all the transactions the wallet has made. If refID is nil,
// then transactions starting from the most recent are returned (past is ignored).
// If past is true, the transactions prior to the refID are returned, otherwise
Expand Down
37 changes: 0 additions & 37 deletions client/asset/dcr/native_wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"context"
"crypto/tls"
"crypto/x509"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
Expand Down Expand Up @@ -377,39 +376,3 @@ func (w *NativeWallet) transferAccount(ctx context.Context, toAcct string, fromA
}
return nil
}

// WalletTransaction returns a transaction that either the wallet has made or
// one in which the wallet has received funds.
func (dcr *NativeWallet) WalletTransaction(ctx context.Context, txID string) (*asset.WalletTransaction, error) {
coinID, err := hex.DecodeString(txID)
if err == nil {
txHash, _, err := decodeCoinID(coinID)
if err == nil {
txID = txHash.String()
}
}

txs, err := dcr.TxHistory(1, &txID, false)
if err != nil {
return nil, err
}
if len(txs) == 0 {
return nil, asset.CoinNotFoundError
}

return txs[0], nil
}

// TxHistory returns all the transactions the wallet has made. If refID is nil,
// then transactions starting from the most recent are returned (past is ignored).
// If past is true, the transactions prior to the refID are returned, otherwise
// the transactions after the refID are returned. n is the number of
// transactions to return. If n is <= 0, all the transactions will be returned.
func (dcr *NativeWallet) TxHistory(n int, refID *string, past bool) ([]*asset.WalletTransaction, error) {
txHistoryDB := dcr.txDB()
if txHistoryDB == nil {
return nil, fmt.Errorf("tx database not initialized")
}

return txHistoryDB.GetTxs(n, refID, past)
}
17 changes: 17 additions & 0 deletions client/asset/dcr/spv.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ const (
type dcrWallet interface {
KnownAddress(ctx context.Context, a stdaddr.Address) (wallet.KnownAddress, error)
AccountNumber(ctx context.Context, accountName string) (uint32, error)
AddressAtIdx(ctx context.Context, account, branch, childIdx uint32) (stdaddr.Address, error)
AccountBalance(ctx context.Context, account uint32, confirms int32) (wallet.Balances, error)
LockedOutpoints(ctx context.Context, accountName string) ([]chainjson.TransactionInput, error)
ListUnspent(ctx context.Context, minconf, maxconf int32, addresses map[string]struct{}, accountName string) ([]*walletjson.ListUnspentResult, error)
Expand Down Expand Up @@ -350,6 +351,22 @@ func (w *spvWallet) Reconfigure(ctx context.Context, cfg *asset.WalletConfig, ne
return cfg.Type != walletTypeSPV, nil
}

// InitialAddress returns the branch 0, child 0 address of the default
// account.
func (w *spvWallet) InitialAddress(ctx context.Context) (string, error) {
acctNum, err := w.dcrWallet.AccountNumber(ctx, defaultAccountName)
if err != nil {
return "", err
}

addr, err := w.dcrWallet.AddressAtIdx(ctx, acctNum, 0, 0)
if err != nil {
return "", err
}

return addr.String(), nil
}

func (w *spvWallet) startWallet(ctx context.Context) error {
netDir := filepath.Dir(w.dir)
if err := initLogging(netDir); err != nil {
Expand Down
4 changes: 4 additions & 0 deletions client/asset/dcr/spv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,10 @@ func (w *tDcrWallet) ListSinceBlock(ctx context.Context, start, end, syncHeight
return nil, nil
}

func (w *tDcrWallet) AddressAtIdx(ctx context.Context, account, branch, childIdx uint32) (stdaddr.Address, error) {
return nil, nil
}

func tNewSpvWallet() (*spvWallet, *tDcrWallet) {
dcrw := &tDcrWallet{
blockHeader: make(map[chainhash.Hash]*wire.BlockHeader),
Expand Down

0 comments on commit 8f9e4ba

Please sign in to comment.