From bf9cc2004560704bef177f98baec6a2b989eefc7 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Sat, 11 May 2019 13:05:36 -0700 Subject: [PATCH] wallet: check RPC error code for rejected confirmed transactions This unifies the logic of receiving an error when broadcasting a confirmed transaction through btcd's/bitcoind's RPC interface. The btcd dependency update is required in order for it to match bitcoind's behavior. For older nodes that have yet to update, the confirmed transaction will still be caught by the "transaction already exists" case. This is not needed for bitcoind however, because its been sending the same RPC error code for several major releases now. --- go.mod | 4 ++-- go.sum | 5 ++++- wallet/wallet.go | 34 ++++++++++++++++++++++++---------- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index 1f240d7..6f83b2c 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,9 @@ module github.com/btcsuite/btcwallet require ( - github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32 + github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f - github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803 + github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d github.com/btcsuite/golangcrypto v0.0.0-20150304025918-53f62d9b43e8 github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 github.com/coreos/bbolt v1.3.2 diff --git a/go.sum b/go.sum index 7a9c5c7..664ee2e 100644 --- a/go.sum +++ b/go.sum @@ -4,14 +4,17 @@ github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBA github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/btcsuite/btcd v0.0.0-20180823030728-d81d8877b8f3/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ= -github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32 h1:qkOC5Gd33k54tobS36cXdAzJbeHaduLtnLQQwNoIi78= github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= +github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c h1:aEbSeNALREWXk0G7UdNhR3ayBV7tZ4M2PNmnrCAph6Q= +github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20180706230648-ab6388e0c60a h1:RQMUrEILyYJEoAT34XS/kLu40vC0+po/UfxrBBA4qZE= github.com/btcsuite/btcutil v0.0.0-20180706230648-ab6388e0c60a/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803 h1:j3AgPKKZtZStM2nyhrDSLSYgT7YHrZKdSkq1OYeLjvM= github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d h1:yJzD/yFppdVCf6ApMkVy8cUxV0XrxdP9rVf6D87/Mng= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcwallet v0.0.0-20180904010540-284e2e0e696e33d5be388f7f3d9a26db703e0c06/go.mod h1:/d7QHZsfUAruXuBhyPITqoYOmJ+nq35qPsJjz/aSpCg= github.com/btcsuite/btcwallet v0.0.0-20190313032608-acf3b04b0273/go.mod h1:mkOYY8/psBiL5E+Wb0V7M0o+N7NXi2SZJz6+RKkncIc= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw= diff --git a/wallet/wallet.go b/wallet/wallet.go index f9cce35..1c5755f 100644 --- a/wallet/wallet.go +++ b/wallet/wallet.go @@ -3414,6 +3414,14 @@ func (w *Wallet) publishTransaction(tx *wire.MsgTx) (*chainhash.Hash, error) { } txid, err := chainClient.SendRawTransaction(tx, false) + + // Determine if this was an RPC error thrown due to the transaction + // already confirming. + var rpcTxConfirmed bool + if rpcErr, ok := err.(*btcjson.RPCError); ok { + rpcTxConfirmed = rpcErr.Code == btcjson.ErrRPCTxAlreadyInChain + } + switch { case err == nil: return txid, nil @@ -3425,12 +3433,16 @@ func (w *Wallet) publishTransaction(tx *wire.MsgTx) (*chainhash.Hash, error) { // // This error is returned when broadcasting/sending a transaction to a // btcd node that already has it in their mempool. - case strings.Contains(err.Error(), "already have transaction"): + case strings.Contains( + strings.ToLower(err.Error()), "already have transaction", + ): fallthrough // This error is returned when broadcasting a transaction to a bitcoind // node that already has it in their mempool. - case strings.Contains(err.Error(), "txn-already-in-mempool"): + case strings.Contains( + strings.ToLower(err.Error()), "txn-already-in-mempool", + ): return txid, nil // If the transaction has already confirmed, we can safely remove it @@ -3438,19 +3450,21 @@ func (w *Wallet) publishTransaction(tx *wire.MsgTx) (*chainhash.Hash, error) { // confirmed store. We'll avoid returning an error as the broadcast was // in a sense successful. // - // This error is returned when broadcasting/sending a transaction that - // has already confirmed to a btcd node. - case strings.Contains(err.Error(), "transaction already exists"): + // This error is returned when sending a transaction that has already + // confirmed to a btcd/bitcoind node over RPC. + case rpcTxConfirmed: fallthrough // This error is returned when broadcasting a transaction that has - // already confirmed to a bitcoind node. - case strings.Contains(err.Error(), "txn-already-known"): + // already confirmed to a btcd node over the P2P network. + case strings.Contains( + strings.ToLower(err.Error()), "transaction already exists", + ): fallthrough - // This error is returned when sending a transaction that has already - // confirmed to a bitcoind node over RPC. - case strings.Contains(err.Error(), "transaction already in block chain"): + // This error is returned when broadcasting a transaction that has + // already confirmed to a bitcoind node over the P2P network. + case strings.Contains(strings.ToLower(err.Error()), "txn-already-known"): dbErr := walletdb.Update(w.db, func(dbTx walletdb.ReadWriteTx) error { txmgrNs := dbTx.ReadWriteBucket(wtxmgrNamespaceKey) txRec, err := wtxmgr.NewTxRecordFromMsgTx(tx, time.Now())