Notifications ariving from btcd were being reordered (each handled by
its own goroutine, rather then being always sent in the order they
originated). This was breaking the new transaction store by inserting
transaction records in an 'impossible' manner, that is, inserting txs
without block info after the store already held records of the same tx
with block info, without first performing a rollback.
This is handled by the transaction store insert methods by checking
for identical transactions (double spends with the same tx sha), but
where the block heights mismatch and the new record does not have a
block set. The error is returned all the way up to the goroutine
running each rpc request/notification handler, and if hit, the btcd
connection is closed and all accounts are reopened from disk. This is
not optimal, but it allows us to use the connect logic to correctly
catch us up to the best chain with the last good state of all accounts
while only rescanning a few blocks.
Fixes#72.
This change replaces the old transaction store file format and
implementation. The most important change is how the full backing
transactions for any received or sent transaction are now saved,
rather than simply saving parsed-out details of the tx (tx shas, block
height/hash, pkScripts, etc.).
To support the change, notifications for received transaction outputs
and txs spending watched outpoints have been updated to use the new
redeemingtx and recvtx notifications as these contain the full tx,
which is deserializead and inserted into the store.
The old transaction store serialization code is completely removed, as
updating to the new format automatically cannot be done. Old wallets
first running past this change will error reading the file and start a
full rescan to rebuild the data. Unlike previous rescan code,
transactions spending outpoint managed by wallet are also included.
This results in recovering not just received history, but history for
sent transactions as well.
It appears that the websocket package will occasionally enter a
Codec's Send function and block forever, never erroring (presumably
due to a closed connection). This change adds a deadline for the send
of two seconds. If the send cannot complete before the deadline is
reached, the send is aborted and the connection is assumed to be lost.
A buffer should be added here as well, so even waiting max two seconds
for the send to error out won't cause wallet code to block.
At any instant when a duplicated notification must be sent, either one
of two channel sends/recvs must occur. The first possibility is that
the client is disconnected, in which case the disconnected channel
will be read, and then the context removed from the goroutine-managed
map. The second possibility is that the disconnect channel has not
yet been closed, in which case it must block on an actual message
send. This change moves the second case out of the default case of
the select statement to avoid a race where:
1) The client has not yet disconnected, and the disconnected chan is
not ready for reads.
2) Control switches to the default case.
3) The client disconnects, the goroutine reading the send channel
returns, closes the disconnected channel, and no more reads occur.
4) The notification duplicator blocks forever trying to send the
message even when the disconnected notification channel has
already been closed.
This shouldn't be nececssary (a TODO was added to remind me to make
clients explicitly ask for this info) but in the meantime this fixes
clients such as btcgui which otherwise wouldn't think btcwallet is
properly connected to btcd and will desensitise some widgets.
The disk syncer now maintains its own countdown timer, creating a new
timer only when necessary (when there is no timer running, and
something is scheduled to be written). When the timer expires, the
select loop begins selecting on a grab of the account manager's binary
semaphore, and if read, performs the sync and nils the select channel
to prevent a future grab until a new timer has expired.
Tested with a race-enabled build on Windows. No lockups or races
related to the disk syncing experienced with constant client requests
and incoming btcd notifications, and scheduled writes run as expected
once the countdown timer expires, locking out all server request and
notifiation handling.
Use the new confirmed function to test whether unspent transaction
outputs are confirmed enough to be used as a possible transaction
inputs instead of the old check (which was incorrect and required an
extra confirmation).
Modified the test to require one confirmation instead of none so the
confirmed enough check actually occurs.
The flag marking chained addresses as needing private keys be
generated on the next wallet unlock was not being correctly unset
after creating and encrypting the private key. After
serializing/deserializing the wallet, on next unlock, recreating
missing private keys would begin too early in the chain and fail due
to trying to encrypt an already encrypted address.
This change correctly unsets the flag and bumps the version so a
special case can be created for ignoring duplicate encryption attempts
when reading an old wallet file. Tests have also been added to the
chained pubkey test to test for this error case.
Previous to this commit, all change addresses were indistinguishable
from manually requested addresses. This adds a new function to return
the new address, setting a new change flag to true, and return the
change status with the AddressInfo.
This is needed as part of resolving #41 (getrawchangeaddress).
This change removes the three separate mutexes which used to lock an
account's wallet, tx store, and utxo store. Accounts no longer
contain any locking mechanism and rely on go's other synchronization
constructs (goroutines and channels) for correct access.
All accounts are now managed as a collection through the new
AccountManager, rather than the old AccountStore. AccountManager runs
as its own goroutine to provide access to accounts.
RPC requests are now queued for handling, being denied if the queue
buffer is exhausted. Notifications are also queued (instead of being
sent from their own goroutine after being received, in which order is
undefined), however, notifications are never dropped and will
potentially grow a queue of infinite size if unhandled.
Fixes several hangs cased by incorrect locking, by removing the
locking. Instead, a single goroutine manages all file writes.
The old account 'dirty' boolean flags have been removed. Instead,
anytime an account structure is modified, the portion that was
modified (wallet, tx store, or utxo store) must be scheduled to be
written.
This commit fixes two issues in the writeDirtyToDisk function:
First, closing the temporary files is now done using a defer, so they
are always closed.
Second, the various account mutexs are no longer unlocked using a
defer, preventing more than one from being held at once and causing a
deadlock caused by incorrect locking order.
Boolean options cannot be unset from a default true value on the
command line, so invert the allowfree option, renaming it
disallowfree, so attaching fees may always be forced by specifying
disallowfree = true in the configuration file, or --disallowfree on
the command line.
It may be desirable to never allow free transactions, even if the
calculated priority is high enough that a fee would not be required,
so this change adds a global configuration option to remove this check
and always attach a fee.
Now that it has been decided that all account wallets will share the
same passphrase, the walletlock and walletpassphrase RPC handlers now
go through the accountstore to lock or unlock all account wallets,
rather than only changing the default account.