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.
This commit is contained in:
Wilmer Paulino 2019-05-11 13:05:36 -07:00
parent 0efe836773
commit bf9cc20045
No known key found for this signature in database
GPG key ID: 6DF57B9F9514972F
3 changed files with 30 additions and 13 deletions

4
go.mod
View file

@ -1,9 +1,9 @@
module github.com/btcsuite/btcwallet module github.com/btcsuite/btcwallet
require ( 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/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/golangcrypto v0.0.0-20150304025918-53f62d9b43e8
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792
github.com/coreos/bbolt v1.3.2 github.com/coreos/bbolt v1.3.2

5
go.sum
View file

@ -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 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4=
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= 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-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-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 h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= 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 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-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 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-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-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/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= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw=

View file

@ -3414,6 +3414,14 @@ func (w *Wallet) publishTransaction(tx *wire.MsgTx) (*chainhash.Hash, error) {
} }
txid, err := chainClient.SendRawTransaction(tx, false) 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 { switch {
case err == nil: case err == nil:
return txid, 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 // This error is returned when broadcasting/sending a transaction to a
// btcd node that already has it in their mempool. // 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 fallthrough
// This error is returned when broadcasting a transaction to a bitcoind // This error is returned when broadcasting a transaction to a bitcoind
// node that already has it in their mempool. // 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 return txid, nil
// If the transaction has already confirmed, we can safely remove it // 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 // confirmed store. We'll avoid returning an error as the broadcast was
// in a sense successful. // in a sense successful.
// //
// This error is returned when broadcasting/sending a transaction that // This error is returned when sending a transaction that has already
// has already confirmed to a btcd node. // confirmed to a btcd/bitcoind node over RPC.
case strings.Contains(err.Error(), "transaction already exists"): case rpcTxConfirmed:
fallthrough fallthrough
// This error is returned when broadcasting a transaction that has // This error is returned when broadcasting a transaction that has
// already confirmed to a bitcoind node. // already confirmed to a btcd node over the P2P network.
case strings.Contains(err.Error(), "txn-already-known"): case strings.Contains(
strings.ToLower(err.Error()), "transaction already exists",
):
fallthrough fallthrough
// This error is returned when sending a transaction that has already // This error is returned when broadcasting a transaction that has
// confirmed to a bitcoind node over RPC. // already confirmed to a bitcoind node over the P2P network.
case strings.Contains(err.Error(), "transaction already in block chain"): case strings.Contains(strings.ToLower(err.Error()), "txn-already-known"):
dbErr := walletdb.Update(w.db, func(dbTx walletdb.ReadWriteTx) error { dbErr := walletdb.Update(w.db, func(dbTx walletdb.ReadWriteTx) error {
txmgrNs := dbTx.ReadWriteBucket(wtxmgrNamespaceKey) txmgrNs := dbTx.ReadWriteBucket(wtxmgrNamespaceKey)
txRec, err := wtxmgr.NewTxRecordFromMsgTx(tx, time.Now()) txRec, err := wtxmgr.NewTxRecordFromMsgTx(tx, time.Now())