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

GetAllHistoricalInfo returns wrong order when height goes through 10^n (i.e. number of digits change) #11463

Closed
4 tasks
nnkken opened this issue Mar 25, 2022 · 8 comments · Fixed by #15701
Closed
4 tasks

Comments

@nnkken
Copy link
Contributor

nnkken commented Mar 25, 2022

Summary of Bug

In staking module, when the block heights for historical info goes through boundary of 10^n (i.e. number of digits change), GetAllHistoricalInfo returns the info in wrong order.

Reason: the module is using decimal string of the block height as store key for historical info:

func GetHistoricalInfoKey(height int64) []byte {
	return append(HistoricalInfoKey, []byte(strconv.FormatInt(height, 10))...)
}

So when the number of digits in the decimal string changes, the key order will be wrong: 9, 10, 11 results in 10, 11, 9 since this is the character order for the strings.

Unfortunately there is no easy fix, since it's related to key format. Doing extra sort in GetAllHistoricalInfo will fix this function, but the iterator order can't be fixed.

Fortunately GetAllHistoricalInfo and IterateHistoricalInfo are not in use by any code in the SDK (including ibc-go) other than the test case. So why writing them in the first place?

Version

Tested in v0.44.6, suspects that this exists in every version

Steps to Reproduce

Simply change the block heights in TestGetAllHistoricalInfo from 10, 11, 12 to 9, 10, 11, then the test will fail.

func TestGetAllHistoricalInfo(t *testing.T) {
	_, app, ctx := createTestInput()

	addrDels := simapp.AddTestAddrsIncremental(app, ctx, 50, sdk.NewInt(0))
	addrVals := simapp.ConvertAddrsToValAddrs(addrDels)

	valSet := []types.Validator{
		teststaking.NewValidator(t, addrVals[0], PKs[0]),
		teststaking.NewValidator(t, addrVals[1], PKs[1]),
	}

	header1 := tmproto.Header{ChainID: "HelloChain", Height: 9}
	header2 := tmproto.Header{ChainID: "HelloChain", Height: 10}
	header3 := tmproto.Header{ChainID: "HelloChain", Height: 11}

	hist1 := types.HistoricalInfo{Header: header1, Valset: valSet}
	hist2 := types.HistoricalInfo{Header: header2, Valset: valSet}
	hist3 := types.HistoricalInfo{Header: header3, Valset: valSet}

	expHistInfos := []types.HistoricalInfo{hist1, hist2, hist3}

	for i, hi := range expHistInfos {
		app.StakingKeeper.SetHistoricalInfo(ctx, int64(9+i), &hi)
	}

	infos := app.StakingKeeper.GetAllHistoricalInfo(ctx)
	require.Equal(t, expHistInfos, infos)
}

Result:

...
                Diff:
                --- Expected
                +++ Actual
                @@ -8,3 +8,3 @@
                    ChainID: (string) (len=10) "HelloChain",
                -   Height: (int64) 9,
                +   Height: (int64) 10,
                    Time: (time.Time) {
                @@ -209,3 +209,3 @@
                    ChainID: (string) (len=10) "HelloChain",
                -   Height: (int64) 10,
                +   Height: (int64) 11,
                    Time: (time.Time) {
                @@ -410,3 +410,3 @@
                    ChainID: (string) (len=10) "HelloChain",
                -   Height: (int64) 11,
                +   Height: (int64) 9,
                    Time: (time.Time) {
Test:           TestGetAllHistoricalInfo


For Admin Use

  • Not duplicate issue
  • Appropriate labels applied
  • Appropriate contributors tagged
  • Contributor assigned/self-assigned
@tac0turtle
Copy link
Member

@AdityaSripal does this effect IBC?

@alexanderbez
Copy link
Contributor

Looks like the key is poorly designed, yes. If need be, we can fix it with a migration.

@AdityaSripal
Copy link
Member

Yes that is unintended, but as stated, it luckily does not affect IBC.

The only place where it could have been an issue is in our pruning logic. Since we prune old historical info once we no longer need it.

But we retrieve it by getting each individual historical info here:

func (k Keeper) TrackHistoricalInfo(ctx sdk.Context) {

Rather than iterating lexicographically.

It would be nice to fix this so that the above gets are efficient. But it is not a critical issue

@deepto98
Copy link
Contributor

Can I pick this up?

@alexanderbez
Copy link
Contributor

Yes please @deepto98! Thanks for all the help :)

@deepto98
Copy link
Contributor

@alexanderbez @AdityaSripal I'm working on this, but am not able to reproduce the exact issue. For me, TestGetAllHistoricalInfo passes even when I pass 9,10,11 as the heights. Can you please give me a brief about the code and what changes I should implement?

@alexanderbez
Copy link
Contributor

@deepto98 you mean you implemented the test in the issue body and it did not fail for you?

@babadro
Copy link
Contributor

babadro commented Apr 5, 2023

Hi, I would appreciate some early feedback.

The question is - how should we prepare the migration?
Should it be in a separate PR or included in the same one?

#15701

@mergify mergify bot closed this as completed in #15701 Apr 13, 2023
mergify bot pushed a commit that referenced this issue Apr 13, 2023
## Description

Closes: #11463



---

### Author Checklist

*All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.*

I have...

* [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
* [ ] added `!` to the type prefix if API or client breaking change
* [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/main/CONTRIBUTING.md#pr-targeting))
* [ ] provided a link to the relevant issue or specification
* [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/main/docs/docs/building-modules)
* [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/main/CONTRIBUTING.md#testing)
* [ ] added a changelog entry to `CHANGELOG.md`
* [ ] included comments for [documenting Go code](https://blog.golang.org/godoc)
* [ ] updated the relevant documentation or specification
* [ ] reviewed "Files changed" and left comments if necessary
* [ ] confirmed all CI checks have passed

### Reviewers Checklist

*All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.*

I have...

* [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
* [ ] confirmed `!` in the type prefix if API or client breaking change
* [ ] confirmed all author checklist items have been addressed 
* [ ] reviewed state machine logic
* [ ] reviewed API design and naming
* [ ] reviewed documentation is accurate
* [ ] reviewed tests and test coverage
* [ ] manually tested (if applicable)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants