Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

client/asset/btc: Identify unknown transactions #2723

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

martonp
Copy link
Contributor

@martonp martonp commented Mar 31, 2024

This diff updates the btc wallet to identify all past transactions that
the wallet has made. This way, if dexc is reinitalized with a seed that
was already used, the transaction history of native wallets can be
recovered. When an RPC wallet is connected, the transaction history prior
to connecting will be displayed.

The SPV wallet uses the `GetTransactions` method to retrieve unknown
transactions rather than `ListSinceBlock` as was previously used to get
incoming transactions. This is because `ListSinceBlock` does not include
incoming transactions that pay to a change address, which is done by
redemption and refund transactions. The RPC wallet continues to use the
listsinceblock RPC call.

During initial syncing of the transaction history, the wallet does not
send notifications to the front end each time it discovers a new
transaction. Instead, a notification that the syncing has complete is sent
to the front end.

Comes on top of #2693 and builds on #2694

Comment on lines 1607 to 1609
btc.tipMtx.Lock()
tip := btc.currentTip
btc.tipMtx.Unlock()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be a read lock.

Copy link
Member

@buck54321 buck54321 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Decred rpc history too?

func (w *bchSPVWallet) GetTransactions(startBlock, endBlock int32, _ string, cancel <-chan struct{}) (*btcwallet.GetTransactionsResult, error) {
startID := wallet.NewBlockIdentifierFromHeight(startBlock)
endID := wallet.NewBlockIdentifierFromHeight(endBlock)
ltcGTR, err := w.Wallet.GetTransactions(startID, endID, cancel)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bchGTR

Comment on lines +504 to +506
// We use GetTransactions instead of ListSinceBlock, because ListSinceBlock
// does not include transactions that pay to a change address, which
// Redeem, Refund, and RedeemBond do.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oooohhh. Nice catch.

return nil, err
}

ctx, die := context.WithCancel(context.Background())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's pass in a context.Context to the constructor.

seq *badger.Sequence

running atomic.Bool
wg *sync.WaitGroup
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make this a value and you don't have to initialize it.

time.Sleep(10 * time.Millisecond)
}

return err
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can never be anything but nil.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be badger.ErrConflict if we got conflicts 10 times.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah

@@ -149,3 +164,7 @@ type listDescriptorsResult struct {
Next int64 `json:"next"` // next index to addresses generation; only set for ranged descriptors
} `json:"descriptors"`
}

type listTransactionsResult struct {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're only using this struct in one place, you can define it there.

Comment on lines 951 to 955
var dbPath string
if spvWallet, ok := dcr.wallet.(*spvWallet); ok {
initialAddress, err := spvWallet.InitialAddress(ctx)
if err != nil {
return err
}

dbPath = dcr.txHistoryDBPath(initialAddress)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type assertion is fine, but using an interface is cooler and more flexible imo.

var dbPath string
if initialAddresser, is := dcr.wallet.(interface {
	InitialAddress(ctx context.Context) (string, error)
}); is {
	initialAddress, err := initialAddresser.InitialAddress(ctx)
	if err != nil {
		return err
	}

	dbPath = dcr.txHistoryDBPath(initialAddress)
}

dcr.subprocessWg.Add(1)
go func() {
defer dcr.subprocessWg.Done()
dcr.checkPendingTxs(ctx, uint64(newTipHeight))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to sequence calls to checkPendingTxs?

@@ -2529,6 +2534,12 @@ export default class WalletsPage extends BasePage {
if (n.assetID === this.selectedAssetID) this.handleTxNote(n.transaction, n.new)
break
}
case 'transactionHistorySynced'
: {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New line is accident?

@@ -901,6 +902,125 @@ func (dcr *ExchangeWallet) Info() *asset.WalletInfo {
// }
// }

func (dcr *ExchangeWallet) txHistoryDBPath(walletID string) string {
return filepath.Join(dcr.walletDir, fmt.Sprintf("txhistory-%s.db", walletID))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's a directory, should drop the file extension.

@martonp
Copy link
Contributor Author

martonp commented Apr 14, 2024

@buck54321 This PR comes on top of #2693. For this one I was only going to do identifying BTC transactions, then I'll add another PR for DCR later. Let's merge #2693 first, then I'll rebase this one.

@martonp martonp force-pushed the unknownTxs branch 2 times, most recently from ebf36db to b4c1c96 Compare April 18, 2024 22:07
This diff updates the btc wallet to identify all past transactions that
the wallet has made. This way, if dexc is reinitalized with a seed that
was already used, the transaction history of native wallets can be
recovered. When an RPC wallet is connected, the transaction history prior
to connecting will be displayed.

The SPV wallet uses the `GetTransactions` method to retrieve unknown
transactions rather than `ListSinceBlock` as was previously used to get
incoming transactions. This is because `ListSinceBlock` does not include
incoming transactions that pay to a change address, which is done by
redemption and refund transactions. The RPC wallet continues to use the
listsinceblock RPC call.

During initial syncing of the transaction history, the wallet does not
send notifications to the front end each time it discovers a new
transaction. Instead, a notification that the syncing has complete is sent
to the front end.

Co-authored-by: buck54321 <buck54321@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants