diff --git a/wallet/wallet.go b/wallet/wallet.go index 1023908cda..ff95d1d1be 100644 --- a/wallet/wallet.go +++ b/wallet/wallet.go @@ -2385,15 +2385,18 @@ type GetTransactionResult struct { // transaction is returned in a Block structure which records properties about // the block. A bool is also returned to denote if the transaction previously // existed in the database or not. +// The backend must have a transaction index to poll a confirmed transaction +// that does not exist in the internal wallet. func (w *Wallet) GetTransaction(txHash *chainhash.Hash) (*GetTransactionResult, bool, error) { - var res GetTransactionResult - chainClient := w.chainClient - if chainClient == nil { - return nil, false, errors.New("no chain server client") + chainClient, err := w.requireChainClient() + if err != nil { + return nil, false, err } + var res GetTransactionResult + // In case the transaction is unconfirmed it could due to race condition // confirm during the time we receive it from the backend and check it // in the database. @@ -2406,17 +2409,26 @@ func (w *Wallet) GetTransaction(txHash *chainhash.Hash) (*GetTransactionResult, // Get the transaction information from directly calling the backend // endpoint. + var backendErr error var txResult *btcjson.TxRawResult switch client := chainClient.(type) { case *chain.RPCClient: txResult, err = client.GetRawTransactionVerbose(txHash) if err != nil { - return nil, false, err + // If the backend returned an error we will still try to + // find the transaction in the database, but return the + // error if it was also not found there. + backendErr = err + bestHeight = 0 } case *chain.BitcoindClient: txResult, err = client.GetRawTransactionVerbose(txHash) if err != nil { - return nil, false, err + // If the backend returned an error we will still try to + // find the transaction in the database, but return the + // error if it was also not found there. + backendErr = err + bestHeight = 0 } case *chain.NeutrinoClient: return nil, false, errors.New("not supported with neutrino client") @@ -2430,20 +2442,8 @@ func (w *Wallet) GetTransaction(txHash *chainhash.Hash) (*GetTransactionResult, // db can be queried directly without this. var blockHash *chainhash.Hash var height int32 = -1 - if txResult.BlockHash != "" { - blockHashBytes, err := hex.DecodeString(txResult.BlockHash) - if err != nil { - return nil, false, err - } - - // The byte is reversed due to different endianness in response - // and call. - reversed := make([]byte, len(blockHashBytes)) - for i, n := range blockHashBytes { - j := len(blockHashBytes) - i - 1 - reversed[j] = n - } - blockHash, err = chainhash.NewHash(reversed) + if txResult != nil && txResult.BlockHash != "" { + blockHash, err = chainhash.NewHashFromStr(txResult.BlockHash) if err != nil { return nil, false, err } @@ -2461,11 +2461,6 @@ func (w *Wallet) GetTransaction(txHash *chainhash.Hash) (*GetTransactionResult, if err != nil { return nil, false, err } - case *chain.NeutrinoClient: - height, err = client.GetBlockHeight(blockHash) - if err != nil { - return nil, false, err - } } // We know that the transaction definitively is in a specific @@ -2502,8 +2497,9 @@ func (w *Wallet) GetTransaction(txHash *chainhash.Hash) (*GetTransactionResult, return false, nil } - return w.TxStore.RangeTransactions(txmgrNs, bestHeight, - height, rangeFn) + return w.TxStore.RangeTransactions( + txmgrNs, bestHeight, height, rangeFn, + ) }) if err != nil { return nil, false, err @@ -2512,6 +2508,12 @@ func (w *Wallet) GetTransaction(txHash *chainhash.Hash) (*GetTransactionResult, // We need to build the transaction to return as the response if it was // not found in the database. if summary == nil { + // Return the backend error if the transaction was not found in + // the database. + if backendErr != nil { + return nil, false, backendErr + } + txRaw, err := hex.DecodeString(txResult.Hex) if err != nil { return nil, false, err