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

test: Fix intermittent failure in feature_dbcrash #19022

Merged
merged 1 commit into from
May 29, 2020

Conversation

maflcko
Copy link
Member

@maflcko maflcko commented May 19, 2020

@maflcko
Copy link
Member Author

maflcko commented May 19, 2020

This was presumably introduced in aab8172

@fanquake fanquake added the Tests label May 19, 2020
Copy link
Contributor

@jnewbery jnewbery left a comment

Choose a reason for hiding this comment

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

utACK fa2ca0c

Perhaps a longer-term solution would be to change the generate() method in TestNode:

  • set an hd seed on the node instead of a private key in import_deterministic_coinbase_privkeys()
  • use generatetodescriptor to generate to a key in the hd tree
  • keep a static variable in generate() to ensure a new keypath is used for each call.

Could be a good first issue?

test/functional/feature_dbcrash.py Show resolved Hide resolved
@maflcko
Copy link
Member Author

maflcko commented May 29, 2020

keep a static variable in generate() to ensure a new keypath is used for each call.

You mean a member variable? (Different nodes shouldn't influence each other)

@jnewbery
Copy link
Contributor

You mean a member variable? (Different nodes shouldn't influence each other)

You're right. Should be a member variable.

@maflcko maflcko merged commit c19fd96 into bitcoin:master May 29, 2020
@maflcko maflcko deleted the 2005-testFixIntermittentFailDbCrash branch May 29, 2020 15:29
@glowang
Copy link
Contributor

glowang commented May 30, 2020

utACK fa2ca0c

Perhaps a longer-term solution would be to change the generate() method in TestNode:

  • set an hd seed on the node instead of a private key in import_deterministic_coinbase_privkeys()
  • use generatetodescriptor to generate to a key in the hd tree
  • keep a static variable in generate() to ensure a new keypath is used for each call.

Could be a good first issue?

I can work on this!

@maflcko
Copy link
Member Author

maflcko commented May 30, 2020

Nice! I see that this method is lacking a comment to explain its motivation. The background the tests need deterministic keys is:

  • When the wallet is not compiled into Bitcoin Core, the tests should still be able to generate blocks. Blocks need to be generated to an address (or descriptor), so we need some information to derive those
  • When the wallet is compiled into Bitcoin Core (and mock-time is used), we want blocks to be generated deterministically in some tests. See for example test/functional/data/rpc_getblockstats.json
  • Finally, a minor side-effect, is that we don't need to cache the wallets directory in the functional test cache.

Just make sure to preserve those use-cases.

Let me know if you need any other pointers.

sidhujag pushed a commit to syscoin/syscoin that referenced this pull request May 31, 2020
fa2ca0c test: Fix intermittent failure in feature_dbcrash (MarcoFalke)

Pull request description:

  Example backtrace https://cirrus-ci.com/task/6005716207009792?command=functional_test#L817

ACKs for top commit:
  jnewbery:
    utACK fa2ca0c

Tree-SHA512: 978b3ac222f4764c887719240cfd1b29f72cdd273a456345b631e622db0a38e345c25a70d0bae8d4063c1ff6c1af892a7ee37d0d66f47284c2524b663c3afe55
@glowang
Copy link
Contributor

glowang commented Jun 1, 2020

Thank you so much @MarcoFalke and @jnewbery !

1.You mentioned that Blocks need to be generated to an address (or descriptor), so we need some information to derive those. I understand that you want to generate blocks to an address/descriptor, but what woud happen if the keys are not deterministic anyways? What benefits do we get from having information to derive them? Sorry if this is super obvious.

2.I did a little research, but I'm not sure if I'm getting what you meant by Do not cache the wallets directory in functional test cache. Looks like this behavior has been enforced in test_framework.py, os.rmdir(cache_path('wallets')). Is this what you mean? Is this the exact behavior we want to maintain?

3.Additionally, I would like to make sure I understand the context & goal of this task:

Background: feature_dbcrash test experienced intermittent failures due to the fact that generate() uses a deterministic address. Deterministic addresses don't work when a block is invalidated uniformly randomly (but why does invalid block not work well with deterministic addresses? Why does using a new address solve this problem?). This has been worked around by calling the getnewaddress() function.

Goal: we want to rewrite the generate() function to this logic:

  • If the wallet is compiled && mocktime is used:
    • Blocks should be generated deterministically, like rpc_getblockstats.json
  • If the wallet is not compiled:
    • Blocks are generated to an address or descriptor:
      - Set an hd seed on the node instead of using get_deterministic_priv_key().address
      - Use generatetodesriptor to generate keys from the seed
      - Use a ember variable in generate() to ensure a new keypath is used

@maflcko
Copy link
Member Author

maflcko commented Jun 1, 2020

Why does using a new address solve this problem?

If you call

  • generate
  • invalidateblock(best_block)
  • generate

And all of this happens in the same second, then the two generated blocks will be completely identical in all fields of their struct. Thus, the second call to generate will fail because the generated block is already marked invalid.

@maflcko
Copy link
Member Author

maflcko commented Jun 1, 2020

Looks like this behavior has been enforced in test_framework.py, os.rmdir(cache_path('wallets')). Is this what you mean? Is this the exact behavior we want to maintain?

Yes, I'd say so. It allows to simply cache the blockchain once instead of MAX_NODES datadirs (including the wallet dirs)

And about your other questions: In general, the more deterministic a test is, the easier it is to reproduce failures.

@glowang
Copy link
Contributor

glowang commented Jun 5, 2020

thank you for your answers!! I have some follow up questions 😂

In your answer, there seems to be an emphasis of using mock time when the wallet is enabled, but not so important if we are only generating to address...is there a reason for that? It seems that we set mocktime when we expect there is some time consuming processes (such as tx rebroadcast) & that we use mocktime to time travel.

The feature_crash.py test is using generatetoaddress for mining after this pr, so right now it is independent of wallet. Does this mean that this test scenario does not require a wallet to be enabled? Is there any harm if I pass in the -disablewallet param?

In the case that wallet is enabled & that we want to generate blocks deterministically, is it okay if we reuse the block data in rpc_getblockstats.json?

In the case that wallet is not enable, do you have any preference as to whether we should use generatetodescriptor or generatetoaddress ? @jnewbery asked specifically to use generatetodescriptor in his previous comment, but @MarcoFalke seemed to suggest that either is okay?

Thank you again 🙏

@maflcko
Copy link
Member Author

maflcko commented Jun 5, 2020

Don't worry too much about mocktime. This is just another dimension to achieve more determinism. It should be orthogonal to your changes. rpc_getblockstats.json was just an example. It shouldn't affect your changes.

Sometimes mocktime is used to "speed up" tests by telling them how much time has passed. In other cases, it is used to deterministically generate blocks. (The time ends up in the block header, see https://btcinformation.org/en/developer-reference#block-headers)

Is there any harm if I pass in the -disablewallet param?

Currently the test does require a wallet. However, it might be possible to remove that requirement.

self.skip_if_no_wallet()

@glowang
Copy link
Contributor

glowang commented Jun 16, 2020

I feel like maybe I am spinning my wheel for a bit...

If you got sometime to take a look and let me know if I am heading in the right direction, I would really appreciate it! #19297

jasonbcox pushed a commit to Bitcoin-ABC/bitcoin-abc that referenced this pull request Sep 9, 2020
Summary:
test: Fix intermittent failure in feature_dbcrash (MarcoFalke)

Pull request description:

  Example backtrace https://cirrus-ci.com/task/6005716207009792?command=functional_test#L817

---

Backport of Core [[bitcoin/bitcoin#19022 | PR19022]]

Test Plan:
  ninja
  test_runner.py feature_dbcrash

Reviewers: #bitcoin_abc, deadalnix

Reviewed By: #bitcoin_abc, deadalnix

Differential Revision: https://reviews.bitcoinabc.org/D7406
PastaPastaPasta pushed a commit to PastaPastaPasta/dash that referenced this pull request Sep 17, 2021
fa2ca0c test: Fix intermittent failure in feature_dbcrash (MarcoFalke)

Pull request description:

  Example backtrace https://cirrus-ci.com/task/6005716207009792?command=functional_test#L817

ACKs for top commit:
  jnewbery:
    utACK fa2ca0c

Tree-SHA512: 978b3ac222f4764c887719240cfd1b29f72cdd273a456345b631e622db0a38e345c25a70d0bae8d4063c1ff6c1af892a7ee37d0d66f47284c2524b663c3afe55
PastaPastaPasta pushed a commit to PastaPastaPasta/dash that referenced this pull request Sep 19, 2021
fa2ca0c test: Fix intermittent failure in feature_dbcrash (MarcoFalke)

Pull request description:

  Example backtrace https://cirrus-ci.com/task/6005716207009792?command=functional_test#L817

ACKs for top commit:
  jnewbery:
    utACK fa2ca0c

Tree-SHA512: 978b3ac222f4764c887719240cfd1b29f72cdd273a456345b631e622db0a38e345c25a70d0bae8d4063c1ff6c1af892a7ee37d0d66f47284c2524b663c3afe55
thelazier pushed a commit to thelazier/dash that referenced this pull request Sep 25, 2021
fa2ca0c test: Fix intermittent failure in feature_dbcrash (MarcoFalke)

Pull request description:

  Example backtrace https://cirrus-ci.com/task/6005716207009792?command=functional_test#L817

ACKs for top commit:
  jnewbery:
    utACK fa2ca0c

Tree-SHA512: 978b3ac222f4764c887719240cfd1b29f72cdd273a456345b631e622db0a38e345c25a70d0bae8d4063c1ff6c1af892a7ee37d0d66f47284c2524b663c3afe55
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Feb 15, 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.

5 participants