From adf4970fa4e6ea4ef6ab22fb5612c3e2c6aaf268 Mon Sep 17 00:00:00 2001 From: Josh Rickmar Date: Wed, 23 Oct 2013 18:23:20 -0400 Subject: [PATCH] Keep a pool of unmined transactions, and resend if unmined. --- cmdmgr.go | 6 ++++++ createtx.go | 12 ++++++++++++ sockets.go | 41 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) diff --git a/cmdmgr.go b/cmdmgr.go index 65541d1..fe16539 100644 --- a/cmdmgr.go +++ b/cmdmgr.go @@ -574,6 +574,12 @@ func SendMany(reply chan []byte, msg *btcjson.Message) { w.UtxoStore.Unlock() } + // Add hex string of raw tx to sent tx pool. If future blocks + // do not contain a tx, a resend is attempted. + UnminedTxs.Lock() + UnminedTxs.m[result.(string)] = hex.EncodeToString(rawtx) + UnminedTxs.Unlock() + ReplySuccess(reply, msg.Id, result) // TODO(jrick): If message succeeded in being sent, save the diff --git a/createtx.go b/createtx.go index 6d143ea..a6e444a 100644 --- a/createtx.go +++ b/createtx.go @@ -44,6 +44,18 @@ var TxFee struct { i int64 } +// UnminedTXs holds a map of transaction IDs as keys mapping to a +// hex string of a raw transaction. If sending a raw transaction +// succeeds, the tx is added to this map and checked again after each +// new block. If the new block contains a tx, it is removed from +// this map. Otherwise, btcwallet will resend the tx to btcd. +var UnminedTxs = struct { + sync.Mutex + m map[string]string +}{ + m: make(map[string]string), +} + // ByAmount defines the methods needed to satisify sort.Interface to // sort a slice of Utxos by their amount. type ByAmount []*tx.Utxo diff --git a/sockets.go b/sockets.go index b8c1316..3f8c4c0 100644 --- a/sockets.go +++ b/sockets.go @@ -341,8 +341,23 @@ func NtfnBlockConnected(r interface{}) { heightf, ok := result["height"].(float64) if !ok { log.Error("blockconnected notification: invalid height") + return } height := int64(heightf) + iminedTxs, ok := result["minedtxs"].([]interface{}) + if !ok { + log.Error("blockconnected notification: invalid mined tx array") + return + } + minedTxs := make([]string, len(iminedTxs)) + for i, iminedTx := range iminedTxs { + minedTx, ok := iminedTx.(string) + if !ok { + log.Error("blockconnected notification: mined tx is not a string") + continue + } + minedTxs[i] = minedTx + } curHeight.Lock() curHeight.h = height @@ -370,6 +385,32 @@ func NtfnBlockConnected(r interface{}) { NotifyWalletBalanceUnconfirmed(frontendNotificationMaster, w.name, unconfirmed) } wallets.RUnlock() + + // Remove all mined transactions from pool. + UnminedTxs.Lock() + for _, txid := range minedTxs { + delete(UnminedTxs.m, txid) + } + + // Resend any remaining transactions still left in pool. These are + // transactions that have not yet been mined into a block. + for _, hextx := range UnminedTxs.m { + n := <-NewJSONID + var id interface{} = fmt.Sprintf("btcwallet(%v)", n) + m, err := btcjson.CreateMessageWithId("sendrawtransaction", id, hextx) + if err != nil { + log.Errorf("cannot create resend request: %v", err) + continue + } + replyHandlers.Lock() + replyHandlers.m[n] = func(result interface{}, err *btcjson.Error) bool { + // Do nothing, just remove the handler. + return true + } + replyHandlers.Unlock() + btcdMsgs <- m + } + UnminedTxs.Unlock() } // NtfnBlockDisconnected handles btcd notifications resulting from