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

blockchain: Add invalidate/reconsider infrastructure. #2536

Merged
merged 4 commits into from
Jan 7, 2021

Conversation

davecgh
Copy link
Member

@davecgh davecgh commented Dec 30, 2020

This requires #2518.

This adds infrastructure to support invalidating arbitrary blocks as if they had violated a consensus rule as well as reconsidering arbitrary blocks for validation under the current consensus rules and includes comprehensive tests to ensure proper functionality.

It also adds two new rpc commands invalidateblock and reconsiderblock to expose the new functionality and updates the JSON-RPC API documentation accordingly.

Example use cases this enables:

  • Revalidating blocks under new consensus rules
    • Consider the case of old software rejecting blocks due to new consensus rules activating on the network and then upgrading to a new version that supports the new rules
  • Possibility of manually generating snapshots of historical state such as live tickets and available utxos
  • Manually recovering from unexpected circumstances
  • Easier chain reorganization testing

Testing notes:

In order to make the new commands available to dcrctl, a replace directive to use the updated and unreleased types module is needed. The following command from the dcrctl directory will accomplish that:

go mod edit -replace=github.com/decred/dcrd/rpc/jsonrpc/types/v2=../dcrd/rpc/jsonrpc/types

@davecgh davecgh added documentation Issues and/or pull requests related to documentation. rpc server api change Issues and/or pull requests that involve a new RPC server version or breaking to change to the API. labels Dec 30, 2020
@davecgh davecgh added this to the 1.7.0 milestone Dec 30, 2020
@davecgh davecgh force-pushed the blockchain_invalidate_reconsider branch 2 times, most recently from d5c5706 to 7c290c2 Compare December 30, 2020 03:03
@davecgh
Copy link
Member Author

davecgh commented Dec 30, 2020

Here is an example of the PR in action on simnet:

Invalidate and reconsider same block:

$ for i in $(seq 28 1 32); do echo "$(./ctl getblockhash $i) (height $i)"; done
19630e8a7bd723f0d37e7f76b824f43e878ae005063007248220350365bf42d9 (height 28)
0e48bb52098b5bc014f94e42543504f4f5f799aa96601a8ba5e8717632a1ba06 (height 29)
04e9a016058439f4f19c16f9b316dd52259258baf9e0067a311b0ed33c739569 (height 30)
0692d68e9abb2c9049a10e98fa11789df21b90bbd4fe3191d833826117b2040e (height 31)
00c1e024cdadb091e3f24b40c4a73f51704a60b8fbc4a735725c3c1577a20f7a (height 32)

$ ./ctl invalidateblock 04e9a016058439f4f19c16f9b316dd52259258baf9e0067a311b0ed33c739569  # height 30
$ ./ctl getbestblockhash | ./ctl getblockheader - | jq '{height,hash}'
{
  "height": 29,
  "hash": "0e48bb52098b5bc014f94e42543504f4f5f799aa96601a8ba5e8717632a1ba06"
}
$ ./ctl reconsiderblock 04e9a016058439f4f19c16f9b316dd52259258baf9e0067a311b0ed33c739569  # height 30
$ ./ctl getbestblockhash | ./ctl getblockheader - | jq '{height,hash}'
{
  "height": 32,
  "hash": "00c1e024cdadb091e3f24b40c4a73f51704a60b8fbc4a735725c3c1577a20f7a"
}

Nested invalidate and reconsider:

$ ./ctl invalidateblock 0692d68e9abb2c9049a10e98fa11789df21b90bbd4fe3191d833826117b2040e  # height 31
$ ./ctl invalidateblock 0e48bb52098b5bc014f94e42543504f4f5f799aa96601a8ba5e8717632a1ba06  # height 29
$ ./ctl getbestblockhash | ./ctl getblockheader - | jq '{height,hash}'
{
  "height": 28,
  "hash": "19630e8a7bd723f0d37e7f76b824f43e878ae005063007248220350365bf42d9"
}
$ ./ctl reconsiderblock 0e48bb52098b5bc014f94e42543504f4f5f799aa96601a8ba5e8717632a1ba06  # height 29
$ ./ctl getbestblockhash | ./ctl getblockheader - | jq '{height,hash}'
{
  "height": 30,
  "hash": "04e9a016058439f4f19c16f9b316dd52259258baf9e0067a311b0ed33c739569"
}
$ ./ctl reconsiderblock 0692d68e9abb2c9049a10e98fa11789df21b90bbd4fe3191d833826117b2040e  # height 31
$ ./ctl getbestblockhash | ./ctl getblockheader - | jq '{height,hash}'
{
  "height": 32,
  "hash": "00c1e024cdadb091e3f24b40c4a73f51704a60b8fbc4a735725c3c1577a20f7a"
}

Reconsider descendant of one or more invalidated ancestors:

$ ./ctl invalidateblock 0692d68e9abb2c9049a10e98fa11789df21b90bbd4fe3191d833826117b2040e  # height 31
$ ./ctl getbestblockhash | ./ctl getblockheader - | jq '{height,hash}'
{
  "height": 30,
  "hash": "04e9a016058439f4f19c16f9b316dd52259258baf9e0067a311b0ed33c739569"
}
$ ./ctl invalidateblock 0e48bb52098b5bc014f94e42543504f4f5f799aa96601a8ba5e8717632a1ba06  # height 29
{
  "height": 28,
  "hash": "19630e8a7bd723f0d37e7f76b824f43e878ae005063007248220350365bf42d9"
}
$ ./ctl reconsiderblock 00c1e024cdadb091e3f24b40c4a73f51704a60b8fbc4a735725c3c1577a20f7a  # height 32
$ ./ctl getbestblockhash | ./ctl getblockheader - | jq '{height,hash}'
{
  "height": 32,
  "hash": "00c1e024cdadb091e3f24b40c4a73f51704a60b8fbc4a735725c3c1577a20f7a"
}

@davecgh davecgh force-pushed the blockchain_invalidate_reconsider branch from 7c290c2 to 584c336 Compare December 31, 2020 05:47
@davecgh davecgh added the non-forking consensus Changes that involve modifying consensus code without causing any forking changes. label Jan 1, 2021
blockchain/process.go Outdated Show resolved Hide resolved
blockchain/process.go Outdated Show resolved Hide resolved
@davecgh davecgh force-pushed the blockchain_invalidate_reconsider branch from 584c336 to 5103db3 Compare January 5, 2021 08:53
Copy link
Member

@rstaudt2 rstaudt2 left a comment

Choose a reason for hiding this comment

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

This is awesome. I had a few comments inline, and outside of that, everything looks good. I used this to test deep reorgs (up to thousands of blocks deep) against real mainnet data, which wasn't really possible before. I also tested that scenario against #2540 and was able to reproduce an issue, so this has already proven to be very useful!

blockchain/process_test.go Show resolved Hide resolved
blockchain/process_test.go Outdated Show resolved Hide resolved
blockchain/process_test.go Outdated Show resolved Hide resolved
blockchain/process_test.go Outdated Show resolved Hide resolved
blockchain/process_test.go Outdated Show resolved Hide resolved
blockchain/process.go Outdated Show resolved Hide resolved
blockchain/process.go Outdated Show resolved Hide resolved
internal/rpcserver/rpcserver.go Show resolved Hide resolved
@davecgh davecgh force-pushed the blockchain_invalidate_reconsider branch from 5103db3 to 2c3189f Compare January 5, 2021 17:36
Copy link
Member

@dnldd dnldd left a comment

Choose a reason for hiding this comment

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

Tested on simnet, working as expected. These RPCs are really nice! 👍

@davecgh davecgh force-pushed the blockchain_invalidate_reconsider branch from 2c3189f to 5c439c0 Compare January 6, 2021 08:08
@davecgh
Copy link
Member Author

davecgh commented Jan 6, 2021

I added a couple of logging statements so the commands are not silent and rebased.

Copy link
Member

@rstaudt2 rstaudt2 left a comment

Choose a reason for hiding this comment

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

Looks good. Retested with the latest, and everything worked as expected, including the newly added log.

Copy link
Member

@JoeGruffins JoeGruffins left a comment

Choose a reason for hiding this comment

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

When reconsidering, I get a warning for every block: [WRN] FEES: Trying to process mined transactions at block 594631 when previous best block was at height 594641

blockchain/process_test.go Outdated Show resolved Hide resolved
@JoeGruffins
Copy link
Member

If I manually invalidate a block, is it possible to undo that without remembering the block hash? If not an rpc call that shows what I have manually disabled would be handy.

Copy link
Member

@sefbkn sefbkn left a comment

Choose a reason for hiding this comment

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

Ran this on mainnet without issue. When started back up, it syncs back to the best height on the network when dcrd is stopped while invalidating/reconsidering arbitrary blocks.

Just have a couple of minor comments.

blockchain/process.go Outdated Show resolved Hide resolved
blockchain/process.go Outdated Show resolved Hide resolved
@davecgh davecgh force-pushed the blockchain_invalidate_reconsider branch from 5c439c0 to 478412b Compare January 7, 2021 21:13
@davecgh
Copy link
Member Author

davecgh commented Jan 7, 2021

When reconsidering, I get a warning for every block: [WRN] FEES: Trying to process mined transactions at block 594631 when previous best block was at height 594641

@JoeGruffins Yes, that is normal. The fees code doesn't update on reorgs. It probably shouldn't be a warning, but that is not related to this PR, so I'll leave it for another.

@davecgh
Copy link
Member Author

davecgh commented Jan 7, 2021

If I manually invalidate a block, is it possible to undo that without remembering the block hash?

Yes. You can just use getchaintips to find the latest tip hash and then reconsider that tip. This intentionally reconsiders all ancestors too which is largely in part to allow exactly this.

If not an rpc call that shows what I have manually disabled would be handy.

Given the above, I don't think this is really necessary. However, an RPC to show information regarding invalid blocks is not a bad idea! That said, it would have to come with some caveats. Namely, you can't distinguish between a block that was manually marked invalid and one that actually failed consensus validation and this is by design. So, such an RPC would really need to show all blocks that have failed validation which would include both types.

It's not something I would want to do as a part of this PR, so it would be something for another day.

@davecgh davecgh force-pushed the blockchain_invalidate_reconsider branch from 478412b to d3c2ae4 Compare January 7, 2021 21:42
This adds infrastructure to support invalidating arbitrary blocks as if
they had violated a consensus rule as well as reconsidering arbitrary
blocks for validation under the current consensus rules.

It also includes comprehensive tests to ensure proper functionality.

Example use cases this enables:

- Revalidating blocks under new consensus rules
  - Consider the case of old software rejecting blocks due to new
    consensus rules activating on the network and then upgrading to a
    new version that supports the new rules
- Possibility of manually generating snapshots of historical state such
  as live tickets and available utxos
- Manually recovering from unexpected circumstances
- Easier chain reorganization testing
This adds the command types for the upcoming invalidateblock and
reconsiderblock RPC commands.
This implements the invalidateblock and reconsiderblock RPC commands
including the required help strings.
This adds documentation for the new invalidateblock and reconsiderblock
RPC commands to the JSON-RPC API docs.
@davecgh davecgh force-pushed the blockchain_invalidate_reconsider branch from d3c2ae4 to 0e72a3e Compare January 7, 2021 23:48
@davecgh davecgh merged commit 0e72a3e into decred:master Jan 7, 2021
@davecgh davecgh deleted the blockchain_invalidate_reconsider branch January 7, 2021 23:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Issues and/or pull requests related to documentation. non-forking consensus Changes that involve modifying consensus code without causing any forking changes. rpc server api change Issues and/or pull requests that involve a new RPC server version or breaking to change to the API.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants