Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix wallet load error on incomplete gettransaction (Failed to load utxos, IndexError: list index out of range) #2467

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

leon-costa
Copy link
Contributor

The error happens when the wallet has some locked outputs in listlockunspent and the corresponding gettransaction doesn't contain the details of this particular output.

It may be related to bitcoin/bitcoin#28555. It is at least the same symptom.

The locked outputs were locked by creating a transaction in Specter. This has happened to me multiple times.

The UI says it failed to load the wallet with the following error: Failed to load utxos, IndexError: list index out of range

The raw transaction does contain the missing output so we use that instead.

Here's an example that generates the error:
listlockunspent:
[
  {
    "txid": "<some txid>",
    "vout": 0
  }
]

gettransaction <some txid>:
{
  "amount": <redacted>,
  "fee": <redacted>,
  "confirmations": <redacted>,
  "blockhash": "<redacted>",
  "blockheight": <redacted>,
  "blockindex": <redacted>,
  "blocktime": <redacted>,
  "txid": "<some tx id>",
  "wtxid": "<redacted>",
  "walletconflicts": [
  ],
  "time": <redacted>,
  "timereceived": <redacted>,
  "bip125-replaceable": "no",
  "details": [
    {
      "address": "<redacted>",
      "category": "send",
      "amount": <redacted>,
      "label": "<redacted>",
      "vout": 1,
      "fee": <redacted>,
      "abandoned": false
    }
  ],
  "hex": "<some raw tx hex>",
  "lastprocessedblock": {
    "hash": "<redacted>",
    "height": <redacted>
  }
}

decoderawtransaction <some raw tx hex>:
{
  "txid": "<some txid>",
  "hash": "<redacted>",
  "version": 2,
  "size": <redacted>,
  "vsize": <redacted>,
  "weight": <redacted>,
  "locktime": <redacted>,
  "vin": [
    {
      "txid": "<some other txid>",
      "vout": 0,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "txinwitness": [
        "<redacted>",
        "<redacted>"
      ],
      "sequence": <redacted>
    }
  ],
  "vout": [
    {
      "value": <redacted>,
      "n": 0,
      "scriptPubKey": {
        "asm": "<redacted>",
        "desc": "<redacted>",
        "hex": "<redacted>",
        "address": "<redacted>",
        "type": "<redacted>"
      }
    },
    {
      "value": <redacted>,
      "n": 1,
      "scriptPubKey": {
        "asm": "<redacted>",
        "desc": "<redacted>",
        "hex": "<redacted>",
        "address": "<redacted>",
        "type": "<redacted>"
      }
    }
  ]
}

Note: I'm connecting to a Bitcoin Core version v27.1.0.

The error happens when the wallet has some locked outputs in
`listlockunspent` and the corresponding `gettransaction` doesn't contain
the details of this particular output.

It may be related to bitcoin/bitcoin#28555. It
is at least the same symptom.

The locked outputs were locked by creating a transaction in Specter.
This has happened to me multiple times.

The UI says it failed to load the wallet with the following error:
Failed to load utxos, IndexError: list index out of range

The raw transaction does contain the missing output so we use that
instead.

Here's an example that generates the error:
listlockunspent:
[
  {
    "txid": "<some txid>",
    "vout": 0
  }
]

gettransaction <some txid>:
{
  "amount": <redacted>,
  "fee": <redacted>,
  "confirmations": <redacted>,
  "blockhash": "<redacted>",
  "blockheight": <redacted>,
  "blockindex": <redacted>,
  "blocktime": <redacted>,
  "txid": "<some tx id>",
  "wtxid": "<redacted>",
  "walletconflicts": [
  ],
  "time": <redacted>,
  "timereceived": <redacted>,
  "bip125-replaceable": "no",
  "details": [
    {
      "address": "<redacted>",
      "category": "send",
      "amount": <redacted>,
      "label": "<redacted>",
      "vout": 1,
      "fee": <redacted>,
      "abandoned": false
    }
  ],
  "hex": "<some raw tx hex>",
  "lastprocessedblock": {
    "hash": "<redacted>",
    "height": <redacted>
  }
}

decoderawtransaction <some raw tx hex>:
{
  "txid": "<some txid>",
  "hash": "<redacted>",
  "version": 2,
  "size": <redacted>,
  "vsize": <redacted>,
  "weight": <redacted>,
  "locktime": <redacted>,
  "vin": [
    {
      "txid": "<some other txid>",
      "vout": 0,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "txinwitness": [
        "<redacted>",
        "<redacted>"
      ],
      "sequence": <redacted>
    }
  ],
  "vout": [
    {
      "value": <redacted>,
      "n": 0,
      "scriptPubKey": {
        "asm": "<redacted>",
        "desc": "<redacted>",
        "hex": "<redacted>",
        "address": "<redacted>",
        "type": "<redacted>"
      }
    },
    {
      "value": <redacted>,
      "n": 1,
      "scriptPubKey": {
        "asm": "<redacted>",
        "desc": "<redacted>",
        "hex": "<redacted>",
        "address": "<redacted>",
        "type": "<redacted>"
      }
    }
  ]
}
Copy link

netlify bot commented Aug 1, 2024

Deploy Preview for specter-desktop-docs canceled.

Name Link
🔨 Latest commit 2efd56c
🔍 Latest deploy log https://app.netlify.com/sites/specter-desktop-docs/deploys/66c76cf240f1f3000860cd4c

@moneymanolis
Copy link
Collaborator

moneymanolis commented Aug 20, 2024

First, thanks for your time and effort looking into this and making a PR.

I just tested this real quick because I had the same error while testing (again) and one "issue" to mention is that decoderawtransaction is not implemented in Spectrum. I haven't looked at the rest of the code yet to be fair, but if it is needed, ideally, this would be added as well to Spectrum. From a quick look, it might be similar to how getrawtransaction was implemented,, i.e. using an ElectrumX API call.

Traceback (most recent call last):
  File "/Users/manolis/coding/repos/specter-desktop/src/cryptoadvance/specter/wallet/wallet.py", line 735, in check_utxo
    raw_transaction = self.rpc.decoderawtransaction(
  File "/Users/manolis/coding/repos/specter-desktop/src/cryptoadvance/specter/rpc.py", line 507, in fn
    r = self.multi([(method, *args)], **kwargs)[0]
  File "/Users/manolis/coding/repos/specter-desktop/src/cryptoadvance/specterext/spectrum/bridge_rpc.py", line 115, in multi
    raise SpecterRpcError(f"Request error: {rpce.message}", mock_response)
cryptoadvance.specter.rpc.RpcError: Request error: Method not found (decoderawtransaction)

During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File "/Users/manolis/coding/repos/specter-desktop/src/cryptoadvance/specter/managers/wallet_manager.py", line 226, in _update
    loaded_wallet = self.WalletClass.from_json(
  File "/Users/manolis/coding/repos/specter-desktop/src/cryptoadvance/specter/wallet/wallet.py", line 589, in from_json
    return cls(
  File "/Users/manolis/coding/repos/specter-desktop/src/cryptoadvance/specter/wallet/wallet.py", line 175, in __init__
    self.update()
  File "/Users/manolis/coding/repos/specter-desktop/src/cryptoadvance/specter/wallet/wallet.py", line 497, in update
    self.getdata()
  File "/Users/manolis/coding/repos/specter-desktop/src/cryptoadvance/specter/wallet/wallet.py", line 763, in getdata
    self.check_utxo()
  File "/Users/manolis/coding/repos/specter-desktop/src/cryptoadvance/specter/wallet/wallet.py", line 759, in check_utxo
    raise SpecterError(f"Failed to load utxos, {type(e).__name__}: {e}")
cryptoadvance.specter.specter_error.SpecterError: Failed to load utxos, RpcError: Request error: Method not found (decoderawtransaction)

Just for reference this is a sample PR to add methods to Spectrum, if there is no ElectrumX API call that can chucked in.

@leon-costa
Copy link
Contributor Author

ElectrumX doesn't seem to have such an API. blockchain.transaction.get with verbose=true seems pretty close, but it takes a transaction hash as an input, not the transaction hex. It could work here because that's what we start with anyway, but I don't know how that could be done with all the intermediaries in your setup.

I see in the spectrum PR you mentioned that embit is used, which seems to be able to decode raw transactions. So it should not be difficult to implement a minimal version of decoderawtransaction that only returns the fields used by this PR, i.e. the vout array, and inside it only n, value and scriptPubKey / address. The first example in the embit page I linked seems to provide an example of all the necessary code.

Actually, specter-desktop also uses embit, so maybe this should be done directly here instead of calling decoderawtransaction.

@moneymanolis
Copy link
Collaborator

Actually, specter-desktop also uses embit, so maybe this should be done directly here instead of calling decoderawtransaction.

Might be the easiest solution? :-)

Because the decoderawtransaction RPC is not available in Spectrum and
the tools to decode the raw transaction are already there.
@leon-costa
Copy link
Contributor Author

I made the change to use embit in this fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants