1
0
Fork 0
mirror of https://github.com/ACINQ/eclair.git synced 2025-02-23 22:46:44 +01:00

Fix concurrent spends with Electrum (#233)

By keeping temporary spending items in history
This commit is contained in:
Pierre-Marie Padiou 2017-11-29 17:40:07 +01:00 committed by GitHub
parent 2d5d68bf3f
commit 2ef479d38c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -128,9 +128,16 @@ class ElectrumWallet(mnemonics: Seq[String], client: ActorRef, params: ElectrumW
goto(stateName) using data1 // goto instead of stay because we want to fire transitions goto(stateName) using data1 // goto instead of stay because we want to fire transitions
case Event(ElectrumClient.GetScriptHashHistoryResponse(scriptHash, history), data) => case Event(ElectrumClient.GetScriptHashHistoryResponse(scriptHash, items), data) =>
log.debug(s"scriptHash=$scriptHash has history=$history") log.debug(s"scriptHash=$scriptHash has history=$items")
val (heights1, pendingTransactionRequests1) = history.foldLeft((data.heights, data.pendingTransactionRequests)) { val shadow_items = data.history.get(scriptHash) match {
case Some(existing_items) => existing_items.filterNot(item => items.exists(_.tx_hash == item.tx_hash))
case None => Nil
}
shadow_items.foreach(item => log.warning(s"keeping shadow item for txid=${item.tx_hash}"))
val items0 = items ++ shadow_items
val (heights1, pendingTransactionRequests1) = items0.foldLeft((data.heights, data.pendingTransactionRequests)) {
case ((heights, hashes), item) if !data.transactions.contains(item.tx_hash) && !data.pendingTransactionRequests.contains(item.tx_hash) => case ((heights, hashes), item) if !data.transactions.contains(item.tx_hash) && !data.pendingTransactionRequests.contains(item.tx_hash) =>
// we retrieve the tx if we don't have it and haven't yet requested it // we retrieve the tx if we don't have it and haven't yet requested it
client ! GetTransaction(item.tx_hash) client ! GetTransaction(item.tx_hash)
@ -157,7 +164,7 @@ class ElectrumWallet(mnemonics: Seq[String], client: ActorRef, params: ElectrumW
// no reorg, nothing to do // no reorg, nothing to do
} }
} }
val data1 = data.copy(heights = heights1, history = data.history + (scriptHash -> history), pendingHistoryRequests = data.pendingHistoryRequests - scriptHash, pendingTransactionRequests = pendingTransactionRequests1) val data1 = data.copy(heights = heights1, history = data.history + (scriptHash -> items0), pendingHistoryRequests = data.pendingHistoryRequests - scriptHash, pendingTransactionRequests = pendingTransactionRequests1)
goto(stateName) using data1 // goto instead of stay because we want to fire transitions goto(stateName) using data1 // goto instead of stay because we want to fire transitions
case Event(GetTransactionResponse(tx), data) => case Event(GetTransactionResponse(tx), data) =>
@ -410,6 +417,9 @@ object ElectrumWallet {
* @param heights transactions heights * @param heights transactions heights
* @param history script hash -> history * @param history script hash -> history
* @param locks transactions which lock some of our utxos. * @param locks transactions which lock some of our utxos.
* @param pendingHistoryRequests requests pending a response from the electrum server
* @param pendingTransactionRequests requests pending a response from the electrum server
* @param pendingTransactions transactions received but not yet connected to their parents
*/ */
case class Data(tip: ElectrumClient.Header, case class Data(tip: ElectrumClient.Header,
accountKeys: Vector[ExtendedPrivateKey], accountKeys: Vector[ExtendedPrivateKey],