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

reporter: fuzz tests for btccache #98

Merged
merged 28 commits into from
Nov 9, 2022
Merged

Conversation

gusin13
Copy link
Collaborator

@gusin13 gusin13 commented Nov 4, 2022

Fixes

https://babylon-chain.atlassian.net/browse/BM-152

Description

Adds fuzz tests for btc cache

@gusin13 gusin13 marked this pull request as ready for review November 4, 2022 02:06
Copy link
Member

@SebastianElvis SebastianElvis left a comment

Choose a reason for hiding this comment

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

Thanks, I believe you get the fuzz tests right in the first place!

types/btccache_test.go Show resolved Hide resolved
types/btccache_test.go Outdated Show resolved Hide resolved
types/btccache_test.go Outdated Show resolved Hide resolved
types/btccache_test.go Outdated Show resolved Hide resolved
types/btccache_test.go Outdated Show resolved Hide resolved
Copy link
Member

@vitsalis vitsalis left a comment

Choose a reason for hiding this comment

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

Nice work! I suggest testing a few more stuff:

blocks, _, _ := GenRandomBlockchainWithBabylonTx(numBlocks, 0, 0)
var ibs []*types.IndexedBlock

blockHeight := int32(numBlocks - 1)
Copy link
Member

Choose a reason for hiding this comment

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

Maybe we can have the starting height be a random int32 in the range of [0, max_int32-num_blocks]. Currently the height of the earliest block is always 0.

Copy link
Collaborator Author

@gusin13 gusin13 Nov 5, 2022

Choose a reason for hiding this comment

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

yup I agree, but blockHeight is the height of last/best block here, so I think we can do
blockHeight := rand.Int31() + int32(numBlocks) to randomize and then it would decrement subsequent block heights in loop.

Copy link
Member

Choose a reason for hiding this comment

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

Yep makes sense.

rand.Seed(seed)

// Create a new cache
maxEntries := datagen.RandomInt(100) + 2 // ensure maxEntries > 1
Copy link
Member

Choose a reason for hiding this comment

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

Why have 102 as the maximum size of the cache? We can test with more as well.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

sure, changed to 1000 now.

types/btccache_test.go Show resolved Hide resolved

return b.reverse()
}

// thread-unsafe version of Reverse
func (b *BTCCache) reverse() error {
Copy link
Member

Choose a reason for hiding this comment

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

Why does this return an error if we always return nil?

Copy link
Collaborator Author

@gusin13 gusin13 Nov 4, 2022

Choose a reason for hiding this comment

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

maybe it was left over in a previous clean up, removing it now. We don't need to return errors in reverse.

types/btccache_test.go Show resolved Hide resolved

// Get prev hash
tip := cache.Tip()
require.NotNil(t, tip)
Copy link
Member

Choose a reason for hiding this comment

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

Should we check that the tip is the last block of those that were inserted? Also, that the tip has the highest height than all other blocks.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Also, that the tip has the highest height than all other blocks.

Do we require this? The helper function which generates blocks here already ensures the heights are sorted.

Copy link
Member

Choose a reason for hiding this comment

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

Yep, the block generation mechanism does that, but we should test that this invariant holds in the cache as well. Minor though.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

sure, fixed it now.

block, _ := vdatagen.GenRandomBlock(1, &prevHash)
newIb := types.NewIndexedBlockFromMsgBlock(rand.Int31(), block)
cache.Add(newIb)
require.Equal(t, numBlocks+1, cache.Size())
Copy link
Member

Choose a reason for hiding this comment

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

We should check that cache.Tip() is the new block that we added as well.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

fixed.

err = cache.RemoveLast()
require.NoError(t, err)
}
require.Equal(t, prevSize-deleteCount, cache.Size())
Copy link
Member

Choose a reason for hiding this comment

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

We should check the tip of the cache and also that the blocks that are still there correspond to the slice of the ones that we added.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

fixed.

Copy link
Member

Choose a reason for hiding this comment

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

I don't see this being added.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I thought this comment was for newly added blocks so I added it here? 🤔

Copy link
Collaborator Author

@gusin13 gusin13 Nov 8, 2022

Choose a reason for hiding this comment

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

ok, finally added this check now on deleted blocks here, as per our call yesterday.

require.Equal(t, cacheBlocksBeforeDeletion[:len(cacheBlocksBeforeDeletion)-int(deleteCount)], cacheBlocksAfterDeletion)

Copy link
Member

@vitsalis vitsalis left a comment

Choose a reason for hiding this comment

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

Thanks for the updates! Looks good overall, added some further comments

testutil/datagen/reporter.go Show resolved Hide resolved
testutil/datagen/reporter.go Outdated Show resolved Hide resolved
blocks, _, _ := GenRandomBlockchainWithBabylonTx(numBlocks, 0, 0)
var ibs []*types.IndexedBlock

blockHeight := rand.Int31() + int32(numBlocks)
Copy link
Member

Choose a reason for hiding this comment

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

Are there any overflow issues here? For example if rand.Int31 returns the largest positive integer for an int32, then we might have an overflow. That's why I suggested taking a random integer from [0, max_int32-numBlocks] and then adding numBlocks to it.

Copy link
Member

Choose a reason for hiding this comment

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

btw, once we identify the height, we could use the GetRandomIndexedBlocksFromHeight function. Currently those functions have overlap.

Copy link
Collaborator Author

@gusin13 gusin13 Nov 8, 2022

Choose a reason for hiding this comment

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

Yup, you are right, there will be overflow issues. Sure I can use [0, max_int32-numBlocks].

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Currently those functions have overlap.

Sure I have refactored GetRandomIndexedBlocks, it can now call internally GetRandomIndexedBlocksFromHeight

@@ -35,7 +35,8 @@ func (b *BTCCache) Init(ibs []*IndexedBlock) error {
b.add(ib)
}

return b.reverse()
b.reverse()
Copy link
Member

Choose a reason for hiding this comment

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

It is weird that we expect the input to the Init function to be blocks in the reverse order. I think it would be better if this function received the blocks in the order that they should be added instead of having to do reversing stuff. The one that calls it should be responsible for providing the correct order.

Copy link
Collaborator Author

@gusin13 gusin13 Nov 8, 2022

Choose a reason for hiding this comment

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

Sure, I like this suggestion. I have refactored Init now, it expects blocks with sorted height, also we won't need the reverse now

blockHeight := rand.Int31() + int32(numBlocks)
for _, block := range blocks {
ibs = append(ibs, types.NewIndexedBlockFromMsgBlock(blockHeight, block))
blockHeight -= 1
Copy link
Member

Choose a reason for hiding this comment

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

It is weird that we need to construct a list in decreasing order in order to properly test Init(). See my comment on the function.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Sure, I have refactored Init, don't need to reverse it now.

@@ -139,7 +130,7 @@ func (b *BTCCache) GetAllBlocks() []*IndexedBlock {
return b.blocks
}

// FindBlock finds block at the given height in cache
// FindBlock uses binary search to find the block with the given height in cache
Copy link
Member

Choose a reason for hiding this comment

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

Nice!


// Add all indexed blocks to the cache
err = cache.Init(ibs)
if numBlocks > maxEntries {
Copy link
Member

Choose a reason for hiding this comment

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

Since this might happen more often that we want it to (did not do the exact probability calculation), this means that many test cases are just going to test this and stop. I suppose we don't want to many test cases to fail on this, so maybe you can only test this case 1/10 times? You can use the datagen.OneInN(10) method. We are already following this practice for some Babylon fuzz tests.

}
require.Equal(t, prevCacheHeight+int32(addCount), cache.Tip().Height)
require.Equal(t, newIbs[addCount-1], cache.Tip())
if addCount >= maxEntries {
Copy link
Member

Choose a reason for hiding this comment

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

From my understanding addCount is the of new blocks. But the cache already has numBlocks inside of it. Then, in that case, we should check that in the case that addCount+numBlocks>=maxEntries:

  • The last addCount blocks in the cache are equal to all the newIbs blocks
  • The first maxEntries-addCount blocks in the cache are equal to the last maxEntries-addCount blocks of the initial blocks that were added.

Otherwise, we should just check that the last addCount blocks in the cache are equal to all the newIbs blocks.

Copy link
Collaborator Author

@gusin13 gusin13 Nov 8, 2022

Choose a reason for hiding this comment

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

sure, good point. I have added these cases and some comments in the code to clarify as discussed in our call yesterday.

err = cache.RemoveLast()
require.NoError(t, err)
}
require.Equal(t, prevSize-deleteCount, cache.Size())
Copy link
Member

Choose a reason for hiding this comment

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

I don't see this being added.

@vitsalis vitsalis changed the base branch from main to dev November 6, 2022 07:23
Copy link
Member

@vitsalis vitsalis left a comment

Choose a reason for hiding this comment

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

Great work, thanks for the updates! Very minor comments, LGTM!

@@ -71,5 +71,10 @@ func (c *Client) GetLastBlocks(stopHeight uint64) ([]*types.IndexedBlock, error)
}
}

// reverse the order of the blocks
Copy link
Member

Choose a reason for hiding this comment

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

Maybe add a note in the docstring about the ordering of the result?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

sure, added.

if sortedByHeight := sort.SliceIsSorted(ibs, func(i, j int) bool {
return ibs[i].Height < ibs[j].Height
}); !sortedByHeight {
return ErrorUnsortedBlocks
Copy link
Member

Choose a reason for hiding this comment

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

Great check!


cache, err := types.NewBTCCache(maxEntries)
if err != nil {
require.ErrorIs(t, err, types.ErrInvalidMaxEntries)
Copy link
Member

Choose a reason for hiding this comment

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

If datagen.OneInN(10) returns false and the types.NewBTCCache returns an error, this check will pass, but it should not.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

sure added this check

if !invalidMaxEntries {
   t.Fatalf("NewBTCCache returned error %s", err)
}

// Add all indexed blocks to the cache
err = cache.Init(ibs)
if err != nil {
require.ErrorIs(t, err, types.ErrTooManyEntries)
Copy link
Member

Choose a reason for hiding this comment

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

Same here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

sure, fixed now added check same as above.

@gusin13 gusin13 force-pushed the BM-152-types-btccache-test-go branch from 437a06c to dd9e756 Compare November 9, 2022 22:21
@gusin13 gusin13 merged commit e7cfa6b into dev Nov 9, 2022
@gusin13 gusin13 deleted the BM-152-types-btccache-test-go branch November 9, 2022 22:27
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.

3 participants