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

feat!: correctly creating the data commitments when the window is changed #1695

Merged
merged 20 commits into from
May 5, 2023

Conversation

rach-id
Copy link
Member

@rach-id rach-id commented May 4, 2023

Overview

This PR allows creating the data commitments correctly when the data commitments window changes. This change can be via an upgrade or a gov proposal.

Closes #1685

@rach-id rach-id added the x/qgb label May 4, 2023
@rach-id rach-id requested a review from evan-forbes as a code owner May 4, 2023 08:22
@rach-id rach-id self-assigned this May 4, 2023
@rach-id rach-id changed the title feat!: correctly creating the data commitments when the window is cha… feat!: correctly creating the data commitments when the window is changed May 4, 2023
@MSevey MSevey requested review from a team and rootulp and removed request for a team May 4, 2023 08:23
@codecov-commenter
Copy link

codecov-commenter commented May 4, 2023

Codecov Report

Merging #1695 (8e57c11) into main (82b22d4) will decrease coverage by 0.14%.
The diff coverage is 0.00%.

@@            Coverage Diff             @@
##             main    #1695      +/-   ##
==========================================
- Coverage   52.82%   52.68%   -0.14%     
==========================================
  Files          97       97              
  Lines        6256     6265       +9     
==========================================
- Hits         3305     3301       -4     
- Misses       2618     2631      +13     
  Partials      333      333              
Impacted Files Coverage Δ
x/qgb/keeper/keeper_data_commitment.go 53.16% <0.00%> (-12.55%) ⬇️

@evan-forbes evan-forbes added this to the Mainnet milestone May 4, 2023
x/qgb/abci_test.go Outdated Show resolved Hide resolved
Copy link
Contributor

@cmwaters cmwaters left a comment

Choose a reason for hiding this comment

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

I think creating a data commitment should not be predicated on:

if ctx.BlockHeight() != 0 && ctx.BlockHeight()%int64(k.GetDataCommitmentWindowParam(ctx)) == 0 {

but

if ctx.BlockHeight() != 0 && ctx.BlockHeight()-k.GetLastDataCommitment(ctx).EndBlock >= int64(k.GetDataCommitmentWindowParam(ctx)) {

@rach-id
Copy link
Member Author

rach-id commented May 4, 2023

In case of a window change, for example from 400 to 199 at block 900,

if ctx.BlockHeight() != 0 && ctx.BlockHeight()%int64(k.GetDataCommitmentWindowParam(ctx)) == 0 {

Would give us ranges like: [1, 400], [401, 800], [801, 995], [996, 1194]. Which gives us an intermediate data commitment that has a custom range.

if ctx.BlockHeight() != 0 && ctx.BlockHeight()-k.GetLastDataCommitment(ctx).EndBlock >= int64(k.GetDataCommitmentWindowParam(ctx)) {

Would give us: [1, 400], [401, 800], [801, 999], [1000, 1199], which wouldn't have the intermediate data commitment that has a custom range.

So that depends on whether we want to have an intermediate data commitment range or not

Edit: The second way will not give us an intermediate data commitment range if the upgrade/gov proposal was done in the range [lastDataCommitment.EndBlock, lastDataCommitment.EndBlock + newWindow]. If not, it will behave similar to the first way and have an intermediate data commitment that has a custom range

x/qgb/abci_test.go Outdated Show resolved Hide resolved
x/qgb/abci_test.go Outdated Show resolved Hide resolved
x/qgb/abci_test.go Outdated Show resolved Hide resolved
x/qgb/abci_test.go Outdated Show resolved Hide resolved
x/qgb/abci_test.go Outdated Show resolved Hide resolved
x/qgb/abci_test.go Outdated Show resolved Hide resolved
x/qgb/abci_test.go Outdated Show resolved Hide resolved
x/qgb/abci_test.go Outdated Show resolved Hide resolved
@@ -11,16 +11,29 @@ import (
// TODO add unit tests for all the keepers

// GetCurrentDataCommitment creates the latest data commitment at current height according to
// the data commitment window specified
// the data commitment window specified.
Copy link
Collaborator

Choose a reason for hiding this comment

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

[nit] the data commitment window isn't specified as a parameter to this function so I wonder if it needs to be in the godoc.

Copy link
Member Author

Choose a reason for hiding this comment

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

It is defined in the params store... do you think we should reword it?

Copy link
Collaborator

Choose a reason for hiding this comment

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

IMO describing that this function depends on the data commitment window is an implementation detail that doesn't need to be documented. Interested readers can read the function body. If we avoid documenting it then we don't need to update the godoc when implementation details change. So my proposal would be:

// GetCurrentDataCommitment creates the latest data commitment at the current height.

Although that makes me think that more than one data commitment can exist for a given height. Why is "latest" necessary?

Copy link
Member Author

Choose a reason for hiding this comment

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

cool, will remove the comment.

Although that makes me think that more than one data commitment can exist for a given height. Why is "latest" necessary?

Only one data commitment can exist for height. Also, latest means in here the last one that will be added

Copy link
Collaborator

Choose a reason for hiding this comment

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

will be added to what?

Copy link
Member Author

Choose a reason for hiding this comment

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

to the state, this method will create a new data commitment and add it to the state, making it the latest data commitment

Copy link
Collaborator

Choose a reason for hiding this comment

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

[non-blocking] here's what I would expect the godoc to look like strictly based on the function name:

// GetCurrentDataCommitment returns a data commitment for the current height.
func (k Keeper) GetCurrentDataCommitment(ctx sdk.Context) (types.DataCommitment, error) {

In the function body, I don't see where it adds a data commitment to the state. If it does indeed update state, would a more descriptive function be:

// UpdateLatestDataCommitment creates a new data commitment for the current
// height, updates it in state, and returns it.
func (k Keeper) UpdateLatestDataCommitment(ctx sdk.Context) (types.DataCommitment, error) {

x/qgb/abci_test.go Show resolved Hide resolved
rach-id and others added 3 commits May 4, 2023 20:11
Co-authored-by: Rootul P <rootulp@gmail.com>
Co-authored-by: Rootul P <rootulp@gmail.com>
Co-authored-by: Rootul P <rootulp@gmail.com>
@MSevey MSevey requested a review from a team May 4, 2023 18:12
rach-id and others added 10 commits May 4, 2023 20:12
Co-authored-by: Rootul P <rootulp@gmail.com>
Co-authored-by: Rootul P <rootulp@gmail.com>
Co-authored-by: Rootul P <rootulp@gmail.com>
Co-authored-by: Rootul P <rootulp@gmail.com>
Co-authored-by: Rootul P <rootulp@gmail.com>
Co-authored-by: Rootul P <rootulp@gmail.com>
Co-authored-by: Rootul P <rootulp@gmail.com>
Co-authored-by: Rootul P <rootulp@gmail.com>
Co-authored-by: Rootul P <rootulp@gmail.com>
Copy link
Member

@evan-forbes evan-forbes left a comment

Choose a reason for hiding this comment

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

question: what happens if the data commitment gets changed to something so small that multiple data commitments are needed? for example, what if we go from 400 -> 5? 400-> 1?

mostly just doc stuff otherwise LGTM

x/qgb/keeper/keeper_data_commitment.go Outdated Show resolved Hide resolved
x/qgb/keeper/keeper_data_commitment.go Outdated Show resolved Hide resolved
Comment on lines 171 to 178
ctx = ctx.WithBlockHeight(wantedHeight)
dc3, err := qk.GetCurrentDataCommitment(ctx)
require.Nil(t, err)
require.Equal(t, dc2.EndBlock+1, dc3.BeginBlock)
require.Equal(t, dc2.EndBlock+newShrinkedDCWindow, dc3.EndBlock)
require.Equal(t, uint64(3), dc3.Nonce)
// set the third data commitment
err = qk.SetAttestationRequest(ctx, &dc3)
Copy link
Member

Choose a reason for hiding this comment

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

as mentioned in a different reviewer's comment, parsing this is difficult because its difficult to understand what criteria is being checked. so we could perhaps add a few comments to elaborate on what we are looking for and why.

Copy link
Member Author

Choose a reason for hiding this comment

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

What do you think about this explanation? 90593fd.
If not clear enough, I will inline comments with every line of the test.
Let me know what you think is better.

@rach-id
Copy link
Member Author

rach-id commented May 4, 2023

what happens if the data commitment gets changed to something so small that multiple data commitments are needed? for example, what if we go from 400 -> 5? 400-> 1?

We will have an intermediary data commitment that will contain all those data commitments, then continue with the provided range. This comment has some details about it: #1695 (comment)

So, for example if we go from 400 to 2 (1 shouldn't be possible, Also, we're setting the lower bound of windows to 101, so we shouldn't get into that case), and we activate the change at height 1000, we will have the following ranges: [1, 400], [401, 800], [801, 1000], [1001, 1002], [1003, 1004]...

@MSevey MSevey requested a review from a team May 4, 2023 21:29
evan-forbes
evan-forbes previously approved these changes May 4, 2023
Copy link
Member

@evan-forbes evan-forbes left a comment

Choose a reason for hiding this comment

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

not blocking, but left some comments 🙂

@rach-id
Copy link
Member Author

rach-id commented May 4, 2023

Thanks 👍 I will try to refactor that test tomorrow and see.

Also, your opinion on this is valuable: #1695 (comment)

Which do you think is better?

Copy link
Collaborator

@rootulp rootulp left a comment

Choose a reason for hiding this comment

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

Approving to unblock but TBH I still don't understand the ranges or how this fixes

@@ -11,16 +11,29 @@ import (
// TODO add unit tests for all the keepers

// GetCurrentDataCommitment creates the latest data commitment at current height according to
// the data commitment window specified
// the data commitment window specified.
Copy link
Collaborator

Choose a reason for hiding this comment

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

[non-blocking] here's what I would expect the godoc to look like strictly based on the function name:

// GetCurrentDataCommitment returns a data commitment for the current height.
func (k Keeper) GetCurrentDataCommitment(ctx sdk.Context) (types.DataCommitment, error) {

In the function body, I don't see where it adds a data commitment to the state. If it does indeed update state, would a more descriptive function be:

// UpdateLatestDataCommitment creates a new data commitment for the current
// height, updates it in state, and returns it.
func (k Keeper) UpdateLatestDataCommitment(ctx sdk.Context) (types.DataCommitment, error) {

@rach-id
Copy link
Member Author

rach-id commented May 5, 2023

@rootulp The data commitment is set here:

https://github.com/celestiaorg/celestia-app/blob/main/x/qgb/abci.go#L28

Also, this shows I will need to write more documentation around that. Thanks for letting me know.

@rootulp
Copy link
Collaborator

rootulp commented May 5, 2023

Based on https://github.com/celestiaorg/celestia-app/blob/main/x/qgb/abci.go#L28 the function GetCurrentDataCommitment doesn't update the data commitment in state so we can use this option instead of the other option:

// GetCurrentDataCommitment returns a data commitment for the current height.
func (k Keeper) GetCurrentDataCommitment(ctx sdk.Context) (types.DataCommitment, error) {

@rach-id
Copy link
Member Author

rach-id commented May 5, 2023

Based on https://github.com/celestiaorg/celestia-app/blob/main/x/qgb/abci.go#L28 the function GetCurrentDataCommitment doesn't update the data commitment in state so we can use this option instead of the other option:

// GetCurrentDataCommitment returns a data commitment for the current height.
func (k Keeper) GetCurrentDataCommitment(ctx sdk.Context) (types.DataCommitment, error) {

Cool, opened issue and will update in a subsequent PR #1710, thanks

@rach-id
Copy link
Member Author

rach-id commented May 5, 2023

Merging, will address the documentation changes in subsequent PRs. Thanks a lot everyone for the thorough reviews 👍 👍

@rach-id rach-id merged commit 9b9a481 into celestiaorg:main May 5, 2023
@cmwaters
Copy link
Contributor

cmwaters commented May 8, 2023

So that depends on whether we want to have an intermediate data commitment range or not

Yeah the reasoning behind why I mentioned that was to specifically remove this intermediate commitment range. There should just be the old one and the new one.

Edit: The second way will not give us an intermediate data commitment range if the upgrade/gov proposal was done in the range [lastDataCommitment.EndBlock, lastDataCommitment.EndBlock + newWindow]. If not, it will behave similar to the first way and have an intermediate data commitment that has a custom range

I'm a bit confused by this, I thought this would remove the possibility of an intermediate data commitment range in all cases

@rach-id
Copy link
Member Author

rach-id commented May 8, 2023

I'm a bit confused by this, I thought this would remove the possibility of an intermediate data commitment range in all cases

Let's take for example an initial data commitment window of 500.
Then, the first ranges, up to height 1000, will be:

  • [1, 500]
  • [501, 1000]

Then, at block 1300, we make a gov proposal to change the window down to 100. Then, the following condition:

if ctx.BlockHeight() != 0 && ctx.BlockHeight()-k.GetLastDataCommitment(ctx).EndBlock >= int64(k.GetDataCommitmentWindowParam(ctx)) {

will be true at height 1300, and we will create a new data commitment as follows:

lastDCC, err := k.GetLastDataCommitment(ctx)
if err != nil {
return types.DataCommitment{}, err
}
beginBlock = lastDCC.EndBlock + 1
endBlock = lastDCC.EndBlock + dcWindow

Which will be: [1001, 1300].

After that, we will have the following ranges: [1301, 1400], [1401, 1500]...

Thus, we will still have the intermediate range of [1001, 1300]. Unless I am missing your point.

If we don't want to have intermediate ranges, one way is to create multiple attestations at the same height. In the above case, at height 1300, we create the following attestations: [1001, 1100], [1101, 1200], [1201, 1300].

@cmwaters
Copy link
Contributor

cmwaters commented May 8, 2023

Which will be: [1001, 1300].

Won't it be [1001, 1100] if the dcWindow is 100?

@rach-id
Copy link
Member Author

rach-id commented May 8, 2023

yes, that if the window change happens in height in the following [1001, 1100]. However, if it happens later, it will be the above

@cmwaters
Copy link
Contributor

cmwaters commented May 8, 2023

Hmm the way I understand the code here, if the window was previously 500, the last commitment at height 1000, if we change the window to 100 at height 1300, that will trigger this condition immediately and it will create a data commitment from [1001, 1100] (as it's based from the last commitment and the window) and then the very next height it will trigger again and create the [1101, 1200] and the same for the next height until height 1303 where the last commitment ends at 1300 and the condition no longer triggers (we could also trigger multiple commitments to be generated in the same block).

Am I missing something?

@rach-id
Copy link
Member Author

rach-id commented May 8, 2023

This assumes that end blocker will run multiple times until we have all the attestations created. However, it's only ran once.

This is what I meant by adding the possibility to creating multiple attestations per height if needed and we won't have the intermediate range. But that would require changing the implementation of end blocker.

@rach-id
Copy link
Member Author

rach-id commented May 8, 2023

I will create an issue to investigate having this. However, I still don't why having an intermediate range is bad. Please let me know if there is something I'm missing

@evan-forbes
Copy link
Member

evan-forbes commented May 8, 2023

yes, that if the window change happens in height in the following [1001, 1100]. However, if it happens later, it will be the above

my understanding of the code was what @cmwaters said, and that's what appears to happen in the test if we modify it to the above scenario.

this is mainly why I asked this question, because it looked like we could only create a single commitment per block, and we would only set a data commitment if the block height is a multiple of the window. Meaning that we might be in a scenario where it takes a long time for the data commitment to catch up to the block height.

if ctx.BlockHeight() != 0 && ctx.BlockHeight()%int64(k.GetDataCommitmentWindowParam(ctx)) == 0 {

This was also why I thought #1713 solved, was by setting to the min to 100, its reasonable that we would always catch up.

so... imo we should keep the code as is here, but then add the ability to create multiple data commitments to cover the edge case.

perhaps we're missing something, and if so, @sweexordious, when you get the chance, do you mind adding a test that demonstrates the intermediate range? thanks! no rush either we have plenty of time 🙂

@rach-id
Copy link
Member Author

rach-id commented May 9, 2023

but then add the ability to create multiple data commitments to cover the edge case.

This is so we don't have the intermediate range, right?

Why is it not good to have an intermediate range that's used to catchup?

Sure, will create a test and let you know

@cmwaters
Copy link
Contributor

cmwaters commented May 9, 2023

However, I still don't why having an intermediate range is bad

I don't think it's that bad (I don't have a full view on things), it's just not correct. You've gone from one range to another so those would be the two ranges we expect posted but now there's a third range to "bridge the gap".

@rach-id
Copy link
Member Author

rach-id commented May 9, 2023

Per sync, will create an issue to catchup on the data commitments. Good catch guys 👍 👍

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.

Update the data commitment creation mechanism to support window changes
5 participants