Skip to content

Commit

Permalink
Fix a bug causes wallet lockup when making transactions
Browse files Browse the repository at this point in the history
A bug existed that could cause the unusual locking up of the wallet
when requesting a transaction, such as through sendtoaddress. The
new function MakeInputSource opens a database transaction, but when
the address pool runs out of addresses it also attempts to open a
database transaction through waddrmgr.NextInternalAddresses. This
would cause a gridlock. To fix this, the address is pulled before
the database transaction is opened and then committed to later if
the transaction succeeds and includes the change address.
  • Loading branch information
cjepson committed Apr 8, 2016
1 parent d45ff26 commit eb9d082
Showing 1 changed file with 18 additions and 6 deletions.
24 changes: 18 additions & 6 deletions wallet/createtx.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,25 +368,37 @@ func (w *Wallet) txToOutputs(outputs []*wire.TxOut, account uint32, minconf int3
}
pool = w.addrPools[account].internal
}
changeAddrUsed := false
txSucceeded := false
pool.mutex.Lock()
defer pool.mutex.Unlock()
defer func() {
if txSucceeded {
if txSucceeded && changeAddrUsed {
pool.BatchFinish()
} else {
pool.BatchRollback()
}
}()

inputSource := w.TxStore.MakeInputSource(account, minconf, bs.Height)
// The change address is pulled here rather than after
// MakeInputSource is called because MakeInputSource
// accesses the database in a way that deadlocks other
// packages that also access the database like waddmgr.
// Because the address pool occasionally makes calls
// to the address manager to replenish the address pool,
// calling the address function after MakeInputSource
// and before inputSource.CloseTransaction() will
// sometimes cause a lockup.
changeAddr, err := pool.getNewAddress()
if err != nil {
return nil, err
}
changeSource := func() ([]byte, error) {
changeAddr, err := pool.getNewAddress()
if err != nil {
return nil, err
}
changeAddrUsed = true
return txscript.PayToAddrScript(changeAddr)
}

inputSource := w.TxStore.MakeInputSource(account, minconf, bs.Height)
tx, err := txauthor.NewUnsignedTransaction(outputs, w.RelayFee(),
inputSource.SelectInputs, changeSource)
closeErr := inputSource.CloseTransaction()
Expand Down

0 comments on commit eb9d082

Please sign in to comment.