btcsuite / btcwallet

A secure bitcoin wallet daemon written in Go (golang)
ISC License
1.15k stars 590 forks source link

Allow setting the start block for address rescans #883

Open josephawallace opened 1 year ago

josephawallace commented 1 year ago

Description

In the event that the wallet.db file is deleted, the same wallet can be restored using the seed. Addresses that need their transactions indexed can be added to the wallet with calls to getnewaddress. Upon restarting, btcwallet will perform a rescan on those addresses.

The issue here is that the rescan begins from the "birthdate" of when the addresses were added to the wallet. So if they are newly added, their older transaction history is missed during the rescan.

To Reproduce

  1. Create a btcwallet with btcwallet --create
  2. Make getnewaddress call to add an address to the wallet
  3. Fund the returned address and verify that btcwallet recognized the deposit
  4. Delete the wallet.db file
  5. Repeat steps 1 and 2 (may have to wait ~30min before repeating)
  6. Verify the address transactions were skipped making getbalance and listtransactions calls

btcwallet will think the balance is zero and that the addresses have no transactions because the rescan started at a block above the block that the funding transaction was in.

Tasks

Add a flag to specify the blockhash/blockheight where the rescan should start. This flag should make the address creation date irrelevant to where to start the rescan, which would allow newly created addresses with past transactions to be properly accounted for.

guggero commented 1 year ago

Did you try this on mainnet? Because there is an explicit mechanism added for that where the wallet birthday is turned into a block height. If I remember correctly, there's always a "safety period" of 24 (or was it 48) hours subtracted from the birthday to avoid this exact issue... That might not work on a local network (like regtest/simnet), as the block dates/times might be off.

josephawallace commented 1 year ago

Yeah I tried on mainnet. I see though that the birthday is given a 48 hour safety period. Still, if I (1) create a wallet, (2) fund one of the addresses, (3) delete the wallet.db file, (4) wait >48hrs, (5) recreate the wallet with the seed and re-add the address, the transaction from step 2 will not be indexed. This is because the birthday will be registered as 2 days before the address was added, which will still be further in time than when the transaction happened.

guggero commented 1 year ago

When you say "seed", what format of seed are we talking about? Because in lnd (which uses btcwallet under the hood), we use aezeed, which encodes the birthday in the seed, so we don't need to rely on detecting first address uses. So I think to fix this we should allow the wallet to be created with a manual birthday being specified. Or maybe that's already possible (I'm not really familiar with btcwallet as a standalone tool/wallet, only as a library).

josephawallace commented 1 year ago

I'm talking about the bitcoin wallet seed that is returned when creating a wallet with btcwallet --create. I'm using btcwallet to handle wallet-related bitcoin RPC calls, since btcd doesn't have a wallet built-in.

I haven't seen any option that would allow a user to manually specify a wallet's birthday, but I'd like to implement that as a new feature.