From 85219a70d30d2d3487163dc18e732ced0d35c872 Mon Sep 17 00:00:00 2001 From: Josh Rickmar Date: Mon, 4 Nov 2013 18:58:41 -0500 Subject: [PATCH] Update for new btcd notifications. This removes the enforced check for the spent field for tx-to-me notifications, as this is no longer sent, and should be calculated by wallet (not done yet). Additionally, the full CreatedTx information is saved with the unmined tx map, so when a tx is mined, information about which inputs and ouputs it creates that are relevant to the wallet can be used. --- cmd.go | 24 +++++++++++------------- cmdmgr.go | 2 +- createtx.go | 31 +++++++++++++++++-------------- sockets.go | 13 ++++++------- 4 files changed, 35 insertions(+), 35 deletions(-) diff --git a/cmd.go b/cmd.go index 6c1a790..1be97ae 100644 --- a/cmd.go +++ b/cmd.go @@ -355,7 +355,7 @@ func (w *BtcWallet) Track() { w.mtx.Unlock() replyHandlers.Lock() - replyHandlers.m[n] = w.newBlockTxHandler + replyHandlers.m[n] = w.newBlockTxOutHandler replyHandlers.Unlock() for _, addr := range w.GetActiveAddresses() { w.ReqNewTxsForAddress(addr.Address) @@ -419,7 +419,7 @@ func (w *BtcWallet) RescanToBestBlock() { replyHandlers.m[n] = func(result interface{}, e *btcjson.Error) bool { // Rescan is compatible with new txs from connected block // notifications, so use that handler. - _ = w.newBlockTxHandler(result, e) + _ = w.newBlockTxOutHandler(result, e) if result != nil { // Notify frontends of new account balance. @@ -552,9 +552,9 @@ func (w *BtcWallet) spentUtxoHandler(result interface{}, e *btcjson.Error) bool return false } -// newBlockTxHandler is the handler function for btcd transaction +// newBlockTxOutHandler is the handler function for btcd transaction // notifications resulting from newly-attached blocks. -func (w *BtcWallet) newBlockTxHandler(result interface{}, e *btcjson.Error) bool { +func (w *BtcWallet) newBlockTxOutHandler(result interface{}, e *btcjson.Error) bool { if e != nil { log.Errorf("Tx Handler: Error %d received from btcd: %s", e.Code, e.Message) @@ -611,34 +611,32 @@ func (w *BtcWallet) newBlockTxHandler(result interface{}, e *btcjson.Error) bool return false } pkscript := btcutil.Base58Decode(pkscript58) - spent, ok := v["spent"].(bool) - if !ok { - log.Error("Tx Handler: Unspecified spent field.") - return false + spent := false + if tspent, ok := v["spent"].(bool); ok { + spent = tspent } // btcd sends the block and tx hashes as BE strings. Convert both // to a LE ShaHash. blockhash, err := btcwire.NewShaHashFromStr(blockhashBE) if err != nil { - log.Error("Tx Handler: Block hash string cannot be parsed: " + err.Error()) + log.Errorf("Tx Handler: Block hash string cannot be parsed: %v", err) return false } txhash, err := btcwire.NewShaHashFromStr(txhashBE) if err != nil { - log.Error("Tx Handler: Tx hash string cannot be parsed: " + err.Error()) + log.Errorf("Tx Handler: Tx hash string cannot be parsed: %v", err) return false } - // TODO(jrick): btcd does not find the sender yet. senderHash, _, _ := btcutil.DecodeAddress(sender) receiverHash, _, err := btcutil.DecodeAddress(receiver) if err != nil { - log.Error("Tx Handler: receiver address can not be decoded: " + err.Error()) + log.Errorf("Tx Handler: receiver address can not be decoded: %v", err) return false } - // Add to TxStore + // Add to TxStore. t := &tx.RecvTx{ Amt: uint64(amt), } diff --git a/cmdmgr.go b/cmdmgr.go index 2cf9f79..0772129 100644 --- a/cmdmgr.go +++ b/cmdmgr.go @@ -599,7 +599,7 @@ func SendMany(reply chan []byte, msg *btcjson.Message) { // 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(createdTx.rawTx) + UnminedTxs.m[TXID(result.(string))] = createdTx UnminedTxs.Unlock() ReplySuccess(reply, msg.Id, result) diff --git a/createtx.go b/createtx.go index eb97da5..77966fe 100644 --- a/createtx.go +++ b/createtx.go @@ -47,6 +47,19 @@ var TxFee = struct { i: 10000, // This is a fee of 0.0001 BTC. } +// CreatedTx is a type holding information regarding a newly-created +// transaction, including the raw bytes, inputs, and an address and UTXO +// for change (if any). +type CreatedTx struct { + rawTx []byte + inputs []*tx.Utxo + changeAddr string + changeUtxo *tx.Utxo +} + +// TXID is a transaction hash identifying a transaction. +type TXID string + // 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 @@ -54,9 +67,9 @@ var TxFee = struct { // this map. Otherwise, btcwallet will resend the tx to btcd. var UnminedTxs = struct { sync.Mutex - m map[string]string + m map[TXID]*CreatedTx }{ - m: make(map[string]string), + m: make(map[TXID]*CreatedTx), } // ByAmount defines the methods needed to satisify sort.Interface to @@ -118,16 +131,6 @@ func selectInputs(s tx.UtxoStore, amt uint64, minconf int) (inputs []*tx.Utxo, b return inputs, btcout, nil } -// createdTx is a type holding information regarding a newly-created -// transaction, including the raw bytes, inputs, and a address and UTXO -// for change. -type createdTx struct { - rawTx []byte - inputs []*tx.Utxo - changeAddr string - changeUtxo *tx.Utxo -} - // txToPairs creates a raw transaction sending the amounts for each // address/amount pair and fee to each address and the miner. minconf // specifies the minimum number of confirmations required before an @@ -137,7 +140,7 @@ type createdTx struct { // address, changeUtxo will point to a unconfirmed (height = -1, zeroed // block hash) Utxo. ErrInsufficientFunds is returned if there are not // enough eligible unspent outputs to create the transaction. -func (w *BtcWallet) txToPairs(pairs map[string]uint64, fee uint64, minconf int) (*createdTx, error) { +func (w *BtcWallet) txToPairs(pairs map[string]uint64, fee uint64, minconf int) (*CreatedTx, error) { // Recorded unspent transactions should not be modified until this // finishes. w.UtxoStore.RLock() @@ -270,5 +273,5 @@ func (w *BtcWallet) txToPairs(pairs map[string]uint64, fee uint64, minconf int) buf := new(bytes.Buffer) msgtx.BtcEncode(buf, btcwire.ProtocolVersion) - return &createdTx{buf.Bytes(), inputs, changeAddr, changeUtxo}, nil + return &CreatedTx{buf.Bytes(), inputs, changeAddr, changeUtxo}, nil } diff --git a/sockets.go b/sockets.go index dd1c50a..30a7a60 100644 --- a/sockets.go +++ b/sockets.go @@ -358,8 +358,7 @@ func NotifyNewBlockChainHeight(reply chan []byte, height int32) { } // NtfnBlockConnected handles btcd notifications resulting from newly -// connected blocks to the main blockchain. Currently, this only creates -// a new notification for frontends with the new blockchain height. +// connected blocks to the main blockchain. func NtfnBlockConnected(r interface{}) { result, ok := r.(map[string]interface{}) if !ok { @@ -382,16 +381,16 @@ func NtfnBlockConnected(r interface{}) { return } height := int32(heightf) - var minedTxs []string + var minedTxs []TXID if iminedTxs, ok := result["minedtxs"].([]interface{}); ok { - minedTxs = make([]string, len(iminedTxs)) + minedTxs = make([]TXID, 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 + minedTxs[i] = TXID(minedTx) } } @@ -440,10 +439,10 @@ func NtfnBlockConnected(r interface{}) { // transaction pool to btcd using the 'sendrawtransaction' RPC // command. func resendUnminedTxs() { - for _, hextx := range UnminedTxs.m { + for _, createdTx := range UnminedTxs.m { n := <-NewJSONID var id interface{} = fmt.Sprintf("btcwallet(%v)", n) - m, err := btcjson.CreateMessageWithId("sendrawtransaction", id, hextx) + m, err := btcjson.CreateMessageWithId("sendrawtransaction", id, string(createdTx.rawTx)) if err != nil { log.Errorf("cannot create resend request: %v", err) continue