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

Support proposervm historical block deletion #1929

Merged
merged 16 commits into from Aug 29, 2023

Conversation

StephenButtolph
Copy link
Contributor

@StephenButtolph StephenButtolph commented Aug 25, 2023

Why this should be merged

High performance blockchains issue large blocks and issue blocks frequently. Even if such blockchain has a robust state bloat prevention mechanism, the block data also needs to be maintained. This allows node operators to restrict the number of historical blocks that will be kept on disk.

It's important for a network maintainer to be aware however that historical block state may be lost if every node is configured to delete historical state. Thankfully historical block state isn't required for validators, so specialized storage solutions can be readily applied here.

How this works

  • Added proposerNumHistoricalBlocks option to subnet configs.
  • Added block pruner that runs on startup to cleanup stale blocks.
  • Added historical block deletion that runs as part of block acceptance.
  • Required that the height index is fully repaired for any chain attempting to prune old blocks.
  • Should guaranteed that the indexed heights are continuous in the range [lastAcceptedHeight - proposerNumHistoricalBlocks, lastAcceptedHeight]
    • ex: lastAcceptedHeight=10 proposerNumHistoricalBlocks=2 indexed heights should be [8,10] because 10 is not historical, 9 and 8 are the 2 most recent historical blocks.

How this was tested

  • Unit test
  • Local testing (see below)
- Start new network with proposerNumHistoricalBlocks = 0 (infinite default)

[08-25|19:23:05.869] DEBUG <X Chain> proposervm/height_indexed_vm.go:132 indexed block {"blkID": "2Qpky4XexDu2dDhWbvYmNJ97SUWr1SKhyFKwnnMcqZadfZumsS", "height": 1}
[08-25|19:23:23.392] DEBUG <X Chain> proposervm/height_indexed_vm.go:132 indexed block {"blkID": "269AoJMCD9jGwjhRmQDqbtoMTFDXwDjcxMoKsoyDVdrdXr6tNQ", "height": 2}
[08-25|19:23:29.030] DEBUG <X Chain> proposervm/height_indexed_vm.go:132 indexed block {"blkID": "2anCvpG5waoVNC3DbMMgAExqDPXFDcgWwsFumvoYiskYvKxXrw", "height": 3}
[08-25|19:23:34.191] DEBUG <X Chain> proposervm/height_indexed_vm.go:132 indexed block {"blkID": "i16mGnEHTzniergZNXS38igngeLBY3AtwoowFj7t2vdD2TeLm", "height": 4}
[08-25|19:23:39.273] DEBUG <X Chain> proposervm/height_indexed_vm.go:132 indexed block {"blkID": "MdKWNyXTanP1gkeYUevsnJAqvWGs3SDpjC6Q2Z4dnTDbBmQhy", "height": 5}

- Restart setting proposerNumHistoricalBlocks = 2

[08-25|19:27:56.258] DEBUG <X Chain> proposervm/height_indexed_vm.go:205 deleted block {"blkID": "2Qpky4XexDu2dDhWbvYmNJ97SUWr1SKhyFKwnnMcqZadfZumsS", "height": 1}
[08-25|19:27:56.258] DEBUG <X Chain> proposervm/height_indexed_vm.go:205 deleted block {"blkID": "269AoJMCD9jGwjhRmQDqbtoMTFDXwDjcxMoKsoyDVdrdXr6tNQ", "height": 2}
[08-25|19:30:31.626] DEBUG <X Chain> proposervm/height_indexed_vm.go:132 indexed block {"blkID": "ct964fFALeNqzV7tjEtJ7HMnQhBkfgX6tKnNYcvCbWLjcq1sG", "height": 6}
[08-25|19:30:31.626] DEBUG <X Chain> proposervm/height_indexed_vm.go:172 deleted block {"blkID": "2anCvpG5waoVNC3DbMMgAExqDPXFDcgWwsFumvoYiskYvKxXrw", "height": 3}
[08-25|19:30:56.282] DEBUG <X Chain> proposervm/height_indexed_vm.go:132 indexed block {"blkID": "KCv9wv9kHwSN3iVTVeN4cU4zyrNGPJNpwpr6SEGqi4R1A7jaU", "height": 7}
[08-25|19:30:56.282] DEBUG <X Chain> proposervm/height_indexed_vm.go:172 deleted block {"blkID": "i16mGnEHTzniergZNXS38igngeLBY3AtwoowFj7t2vdD2TeLm", "height": 4}

- Restart setting proposerNumHistoricalBlocks = 4

[08-25|19:32:02.101] DEBUG <X Chain> proposervm/height_indexed_vm.go:132 indexed block {"blkID": "2oEHCZHJf34m6LrUwyHX4ui7oAbG39rRNbibZVChRYmSiRC4RK", "height": 8}
[08-25|19:33:00.551] DEBUG <X Chain> proposervm/height_indexed_vm.go:132 indexed block {"blkID": "2UhLwuwAyZDVTXsEiwjiaV55HhyxXciBkxcQaTd94kc4UQYkYb", "height": 9}
[08-25|19:33:17.375] DEBUG <X Chain> proposervm/height_indexed_vm.go:132 indexed block {"blkID": "2TqxFYspbjLFdVgBaENaLSe83z2vLkxTmB3dD6yVkRE2oqB2pJ", "height": 10}
[08-25|19:33:17.375] DEBUG <X Chain> proposervm/height_indexed_vm.go:172 deleted block {"blkID": "MdKWNyXTanP1gkeYUevsnJAqvWGs3SDpjC6Q2Z4dnTDbBmQhy", "height": 5}

@@ -134,3 +135,8 @@ func (s *blockState) PutBlock(blk block.Block, status choices.Status) error {
s.blkCache.Put(blkID, &blkWrapper)
return s.db.Put(blkID[:], bytes)
}

func (s *blockState) DeleteBlock(blkID ids.ID) error {
s.blkCache.Evict(blkID)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should we s.blkCache.Put(blkID, nil) here rather than evicting?

Copy link
Contributor

Choose a reason for hiding this comment

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

Delete seems fine with me.
IIRC we peek historical blocks only via GetAncestors call which should stop at the first database.ErrNotFound. I'd rather use the cache for fresh blocks, rather than historical ones

@StephenButtolph StephenButtolph added this to the v1.10.10 milestone Aug 25, 2023
@StephenButtolph StephenButtolph self-assigned this Aug 25, 2023
@StephenButtolph
Copy link
Contributor Author

StephenButtolph commented Aug 26, 2023

Still need to write some unit tests - but I think this is ready for at least a first pass review

@StephenButtolph StephenButtolph marked this pull request as ready for review August 27, 2023 18:28
Copy link
Contributor

@abi87 abi87 left a comment

Choose a reason for hiding this comment

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

questions and minor requests for comments

subnets/config.go Show resolved Hide resolved
subnets/config.go Show resolved Hide resolved
vms/proposervm/height_indexed_vm.go Show resolved Hide resolved
vms/proposervm/height_indexed_vm.go Show resolved Hide resolved
vms/proposervm/state/block_height_index.go Show resolved Hide resolved
@@ -134,3 +135,8 @@ func (s *blockState) PutBlock(blk block.Block, status choices.Status) error {
s.blkCache.Put(blkID, &blkWrapper)
return s.db.Put(blkID[:], bytes)
}

func (s *blockState) DeleteBlock(blkID ids.ID) error {
s.blkCache.Evict(blkID)
Copy link
Contributor

Choose a reason for hiding this comment

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

Delete seems fine with me.
IIRC we peek historical blocks only via GetAncestors call which should stop at the first database.ErrNotFound. I'd rather use the cache for fresh blocks, rather than historical ones

@@ -599,7 +619,10 @@ func (vm *VM) repairAcceptedChainByHeight(ctx context.Context) error {

newProLastAcceptedID, err := vm.State.GetBlockIDAtHeight(innerLastAcceptedHeight)
if err != nil {
return err
// This fatal error can happen if NumHistoricalBlocks is set too
Copy link
Contributor

Choose a reason for hiding this comment

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

q: again this shouldn't really happen unless innerVM is being clever right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's correct - this should not happen unless the inner VM had a rollback more than the proposervm is configured to support.

vms/proposervm/vm_test.go Outdated Show resolved Hide resolved
subnets/config.go Outdated Show resolved Hide resolved
subnets/config.go Show resolved Hide resolved
vms/proposervm/height_indexed_vm.go Show resolved Hide resolved
@rarepepi
Copy link

LGTM

@StephenButtolph StephenButtolph merged commit dd78602 into dev Aug 29, 2023
16 checks passed
@StephenButtolph StephenButtolph deleted the proposervm-block-deletion branch August 29, 2023 17:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
No open projects
Archived in project
Development

Successfully merging this pull request may close these issues.

None yet

4 participants