Skip to content

Conversation

@ryanofsky
Copy link
Contributor

@ryanofsky ryanofsky commented Aug 24, 2020

Returning false will give us a recoverable error instead of killing the node entirely. In that situation, the wallet is still recoverable by deleting all txs and rescanning.

This commit was originally part of #19457.

Original motivation for this change was to avoid crashes with #19078, but a better fix for that problem is in #19793. This change is still beneficial because it removes an unsafe assert.

Returning false will give us a recoverable error instead of killing the
node entirely. In that situation, the wallet is still recoverable by
deleting all txs and rescanning.

Co-authored-by: Russell Yanofsky <[email protected]>
Copy link
Member

@maflcko maflcko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concept ACK on removing an assert that should only be used for code internal logic errors and not user/disk input validation

@ryanofsky ryanofsky marked this pull request as draft August 25, 2020 16:37
@ryanofsky ryanofsky marked this pull request as ready for review August 25, 2020 18:41
Copy link
Contributor Author

@ryanofsky ryanofsky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated 8e734a1 -> c4deddb (pr/badsalv.1 -> pr/badsalv.2, compare) just tweaking the comment.

@achow101
Copy link
Member

ACK c4deddb

@fanquake fanquake requested a review from meshcollider August 27, 2020 22:36
Copy link
Contributor

@meshcollider meshcollider left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK c4deddb

Very sorry I missed this, nice simple PR shouldn't take over a month to review 😅

if (wss.corrupt || IsKeyType(strType) || strType == DBKeys::DEFAULTKEY) {
result = DBErrors::CORRUPT;
} else if (strType == DBKeys::FLAGS) {
// reading the wallet flags can only fail if unknown flags are present
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should the other corruption reasons also latch to true?

wss.corrupt would never be set to false, so the error TOO_NEW is translated to the error CORRUPT (after at least one CORRUPT error).

With a lost key this doesn't seem to happen and the error might be rewritten to TOO_NEW.

Probably doesn't matter in practice, but I wanted to ask to be sure.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re: #19793 (comment)

should the other corruption reasons also latch to true?

wss.corrupt would never be set to false, so the error TOO_NEW is translated to the error CORRUPT (after at least one CORRUPT error).

With a lost key this doesn't seem to happen and the error might be rewritten to TOO_NEW.

Probably doesn't matter in practice, but I wanted to ask to be sure.

Looking at the calling code, in practice the wallet will fail to load either way if TOO_NEW or CORRUPT is returned, only the error text will be different. It's not even a new thing for the CORRUPT error to take priority over the TOO_NEW error since it can also happen in other the places result = DBErrors::CORRUPT is set below.

But one somewhat ugly side effect of this is it can make gArgs.SoftSetBoolArg("-rescan", true) line not get called consistency. It would really be better not to do this and for rescan status were passed back more directly, but that requires more changes outside the file.

Copy link
Contributor Author

@ryanofsky ryanofsky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Closing this since it's out of date and has some odd behaviors. Things it would be nice to do if someone wants to clean this code up:

  1. Replace assert(new_tx) with error handling that triggers the CWallet::Create "Wallet Corrupted" error
  2. Fix the "This error is recoverable with zapwallettxs" comment now that zapwallettxs is removed.
  3. Make the TOO_NEW error take precedence over the CORRUPT error or enforce some other consistent precedence
  4. Replace SoftSetBoolArg("-rescan", true) with a rescan_required return value so one wallet requiring a rescan doesn't cause other wallets to be rescanned

if (wss.corrupt || IsKeyType(strType) || strType == DBKeys::DEFAULTKEY) {
result = DBErrors::CORRUPT;
} else if (strType == DBKeys::FLAGS) {
// reading the wallet flags can only fail if unknown flags are present
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re: #19793 (comment)

should the other corruption reasons also latch to true?

wss.corrupt would never be set to false, so the error TOO_NEW is translated to the error CORRUPT (after at least one CORRUPT error).

With a lost key this doesn't seem to happen and the error might be rewritten to TOO_NEW.

Probably doesn't matter in practice, but I wanted to ask to be sure.

Looking at the calling code, in practice the wallet will fail to load either way if TOO_NEW or CORRUPT is returned, only the error text will be different. It's not even a new thing for the CORRUPT error to take priority over the TOO_NEW error since it can also happen in other the places result = DBErrors::CORRUPT is set below.

But one somewhat ugly side effect of this is it can make gArgs.SoftSetBoolArg("-rescan", true) line not get called consistency. It would really be better not to do this and for rescan status were passed back more directly, but that requires more changes outside the file.

@ryanofsky ryanofsky closed this Oct 21, 2020
// losing keys is considered a catastrophic error, anything else
// we assume the user can live with:
if (IsKeyType(strType) || strType == DBKeys::DEFAULTKEY) {
if (wss.corrupt || IsKeyType(strType) || strType == DBKeys::DEFAULTKEY) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A corrupt/missing transaction isn't supposed to follow this path, but rather the one below which simply triggers a rescan.

@ryanofsky
Copy link
Contributor Author

Closing this since it's out of date and has some odd behaviors. Things it would be nice to do if someone wants to clean this code up:

  1. Replace assert(new_tx) with error handling that triggers the CWallet::Create "Wallet Corrupted" error

  2. Fix the "This error is recoverable with zapwallettxs" comment now that zapwallettxs is removed.

  3. Make the TOO_NEW error take precedence over the CORRUPT error or enforce some other consistent precedence

  4. Replace SoftSetBoolArg("-rescan", true) with a rescan_required return value so one wallet requiring a rescan doesn't cause other wallets to be rescanned

1-3 seems to be handled by #23142 and 4 seems to be handled by #23123

laanwj added a commit that referenced this pull request Oct 1, 2021
0ab4c3b Return false on corrupt tx rather than asserting (Samuel Dobson)

Pull request description:

  Takes up #19793

  Rather than asserting, we log an error and return CORRUPT so that the user is informed. This type of error isn't critical so it isn't worth `assert`ing.

ACKs for top commit:
  achow101:
    ACK 0ab4c3b
  laanwj:
    Code review ACK 0ab4c3b
  ryanofsky:
    Code review ACK 0ab4c3b. There may be room for more improvements later like better error messages or easier recovery options, but changing from an assert to an error seems like a clear improvement, and this seems to avoid all the pitfalls of the last PR that tried this.

Tree-SHA512: 4a1a412e7c473d176c4e09123b85f390a6b0ea195e78d28ebd50b13814b7852f8225a172511a2efb6affb555b11bd4e667c19eb8c78b060c5444b62f0fae5f7a
sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Oct 1, 2021
0ab4c3b Return false on corrupt tx rather than asserting (Samuel Dobson)

Pull request description:

  Takes up bitcoin#19793

  Rather than asserting, we log an error and return CORRUPT so that the user is informed. This type of error isn't critical so it isn't worth `assert`ing.

ACKs for top commit:
  achow101:
    ACK 0ab4c3b
  laanwj:
    Code review ACK 0ab4c3b
  ryanofsky:
    Code review ACK 0ab4c3b. There may be room for more improvements later like better error messages or easier recovery options, but changing from an assert to an error seems like a clear improvement, and this seems to avoid all the pitfalls of the last PR that tried this.

Tree-SHA512: 4a1a412e7c473d176c4e09123b85f390a6b0ea195e78d28ebd50b13814b7852f8225a172511a2efb6affb555b11bd4e667c19eb8c78b060c5444b62f0fae5f7a
@bitcoin bitcoin locked and limited conversation to collaborators Oct 30, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants