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

epoching: test infra and unit tests of keeper/types #47

Merged
merged 27 commits into from
Jul 8, 2022

Conversation

SebastianElvis
Copy link
Member

@SebastianElvis SebastianElvis commented Jul 5, 2022

Fixes BM-62 and BM-64

Depend on #32 and #35

This PR introduces test infra for the epoching module, and adds some basic unit tests on the types and the keeper. Tests on keeper functionalities (such as maintaining epoch number, msg queues and slashed validators) and module/app will be done in another PR.

I also marked @vitalis as a reviewer as Vitalis merged a PR on tests so may have the corresponding experience. Thanks :)

@SebastianElvis SebastianElvis changed the title epoching: test infra and unit/fuzz test cases epoching: test infra and unit tests of keeper/types Jul 6, 2022
@SebastianElvis SebastianElvis changed the base branch from main to epoching-endblock-beginblock July 6, 2022 05:40
@SebastianElvis SebastianElvis marked this pull request as ready for review July 6, 2022 05:42
Comment on lines 24 to 26
func() {
req = &types.QueryParamsRequest{}
},
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't understand the motivation for this "malleate" pattern. It makes things harder to understand in the general case as you have to consider not just the given test case but all test cases that came before it that have potentially modified the common variable in an accumulative way. That would make it difficult for example to comment out all but a failing test case to concentrate on a single problem.

It could make sense in stateful testing where I want to test that each additional step in a series of operations keeps the model in a valid state.

However in this instance it looks completely unnecessary as the tests do nothing but assign the empty request. They could just return it, or even just use the same instance since it doesn't change.

It's not entirely clear what is being tested here either. The test seems to do nothing more than send a request for params and check that the default is returned, then it checks that for the same request it's not something else that is returned. Is this like a 4 eyes principle 👀 👀 ? That x == y && x != !y? 🙂

I could imagine using a fuzz test in the following way:

  1. Generate some random params and perhaps a flag
  2. If the flag is set, set the params it in the keeper
  3. Send the query to get the current state
  4. If the flag was set, verify that the generated parameter was returned; otherwise verify that the default params are returned

That would verify that the application doesn't always return default, it respects the settings.

Copy link
Member Author

Choose a reason for hiding this comment

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

Fully agree with this one. I copied the tests from Cosmos SDK but malleate and req are indeed unnecessary here as we don't have any parameter in QueryParamsRequest...

Copy link
Member Author

@SebastianElvis SebastianElvis Jul 6, 2022

Choose a reason for hiding this comment

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

It's not entirely clear what is being tested here either. The test seems to do nothing more than send a request for params and check that the default is returned, then it checks that for the same request it's not something else that is returned. Is this like a 4 eyes principle 👀 👀 ? That x == y && x != !y? 🙂

This is indeed a trivial test. It merely ensures that one can query the parameters via GRPC. However both Cosmos SDK (https://github.com/cosmos/cosmos-sdk/blob/v0.45.5/x/slashing/keeper/grpc_query_test.go#L58-L64) and Osmosis (https://github.com/osmosis-labs/osmosis/blob/v10.0.0/x/superfluid/keeper/grpc_query_test.go#L10-L15) have this one. Perhaps let's keep it and add an extra fuzz test that you proposed?

Comment on lines 98 to 101
func() {
suite.keeper.SetEpochNumber(suite.ctx, sdk.NewUint(0))
req = &types.QueryCurrentEpochRequest{}
},
Copy link
Contributor

Choose a reason for hiding this comment

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

Right, here it's more obvious why you want to have the malleate function, to mutate the state.

I would still remove the req from here as it never changes. IIRC it doesn't even have parameters.

Copy link
Contributor

Choose a reason for hiding this comment

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

These are nice tests by the way for testing the database over a series of calls!

Combined with fuzzing it can be very powerful, with the only difference being that you'd generate these steps of increments/sets randomly and calculate the expected state in the test on an idealised model, and check the real implementation against that.

Copy link
Member Author

Choose a reason for hiding this comment

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

Combined with fuzzing it can be very powerful, with the only difference being that you'd generate these steps of increments/sets randomly and calculate the expected state in the test on an idealised model, and check the real implementation against that.

That's a good idea! Will do

Comment on lines 118 to 121
} else {
suite.NotEqual(tc.epochNumber.Uint64(), resp.CurrentEpoch)
suite.NotEqual(tc.epochBoundary.Uint64(), resp.EpochBoundary)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Never used. I understand why you want to keep the test structure the same, easier to copy-paste, but if some code is never actually run, it's just extra cruft to maintain and review.

For example here, it could be that only one of the two doesn't match, it's not necessary for both be wrong. But it doesn't matter because all test cases are expected to pass. Better remove it and keep it real.

Copy link
Member Author

Choose a reason for hiding this comment

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

At the moment this code is unreachable indeed. Will we have some extra test cases that we want to fail?

Copy link
Contributor

Choose a reason for hiding this comment

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

Going by the idea of state-machine tests (or model tests as they are also called), a more realistic scenario is not to check that the result doesn't equal some random rubbish, but rather to generate an invalid input, try to use it as input, then check that it has been rejected, as expected.

So, we either:

  • generate a valid input, update our ideal model with it, update the system under test with it, and compare the results are the same
  • generate a known invalid input (perhaps by perturbing a valid one), try to update the system under test, check that it rejected the input

Sometimes the operations can't fail, there are no invalid inputs, in which case there's no reason to test failures, only that the state is always correct. One example I did in the past is testing a database, which was based on this example.

On another case, testing a consensus protocol I did generate invalid input in a controlled fashion. By controlled I mean that I knew that the input was going to be invalid, I didn't have to code logic in the test to decide about an arbitrary input whether it was valid or not, replicating much of what the system would have to do as well.

Comment on lines 184 to 188
req = &types.QueryEpochMsgsRequest{
Pagination: &query.PageRequest{
Limit: 100,
},
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Once more, the req is the same across all tests. It would reduce code duplication and make it easier to review without having to look closely for differences only to find nothing 🔍

Copy link
Member Author

@SebastianElvis SebastianElvis Jul 6, 2022

Choose a reason for hiding this comment

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

I was planning to add test cases on the pagination with different Limit, but yeah req is still not necessary and can be merged into individual test cases. 👍

Comment on lines 157 to 160
false,
[]*types.QueuedMessage{
{TxId: []byte{0x01}},
},
Copy link
Contributor

Choose a reason for hiding this comment

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

This again looks like the 👀 👀 in action. The previous test already checked what the response should equal, there's no point testing with an arbitrary example that it should not equal, once we established what it is.

Comment on lines 210 to 212
if len(tc.epochMsgs) != len(resp.Msgs) {
suite.T().Skip()
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a bit confusing. We are expecting the test to fail, but we skip it. For this it's enough that it doesn't equal in length to what we are not expecting it to be.

Again, this arm of the test is just a lot of code for something that doesn't add much value, as you can always test for the positive case.

Things would be different if for example the call could return an error, and you could check that it indeed fails.

Comment on lines 203 to 208
suite.Equal(len(tc.epochMsgs), len(resp.Msgs))
suite.Equal(uint64(len(tc.epochMsgs)), suite.keeper.GetQueueLength(suite.ctx).Uint64())
for idx := range tc.epochMsgs {
suite.Equal(tc.epochMsgs[idx].MsgId, resp.Msgs[idx].MsgId)
suite.Equal(tc.epochMsgs[idx].TxId, resp.Msgs[idx].TxId)
}
Copy link
Contributor

@aakoshh aakoshh Jul 6, 2022

Choose a reason for hiding this comment

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

This would be another great use case for fuzz testing. You could also randomly generate the limit in the request, to check that it is respected. Something like this:

suite.fuzz(fun(seed uint64) {
  rand.Seed(seed)  
  numOps := rand.Int() % 10
  k := NewKeeper()
  expTxids := [][]byte{}

  for i in range numOps {
    op := rand.Int() % 10
    if op == 0 {
      k.ClearEpochMsgs()
      expTxids = [][]byte{}
    } else if op <= 6 {
      txid := genBytes(32)
      k.EnqueueMsg(types.QueueMsg(txid)
      expTxids = append(expTxids, txid)
    } else {
      limit := rand.Int() % 5
      req := types.QueryEpochMsgsRequest{
					Pagination: &query.PageRequest{
						Limit: limit,
					},
				}

        resp, err := queryClient.EpochMsgs(wctx, req)
        suite.NoError(err)

        suite.Equal(math.min(len(expTxids), limit), len(resp.Msgs))
        for idx := range resp.Msgs {
            suite.Equal(expTxids[idx], resp.Msgs[idx].TxId)
        }
    } 
  }
})

If it fails, the framework would save the seed for you to repeat the experiment.

The benefit is that while this takes longer to write and often requires more thought, it's much easier to add features to it, such as varying the limit. In your test, if you wanted to test it, you would have to create more test cases and make sure in some instances the limit is less, in other instances greater than the queued items, and keep it in sync by hand. Not nice.

@@ -43,6 +43,21 @@ func (k msgServer) WrappedDelegate(goCtx context.Context, msg *types.MsgWrappedD
// enqueue msg
k.EnqueueMsg(ctx, queuedMsg)

// emit event
Copy link
Contributor

Choose a reason for hiding this comment

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

Just noting that this comment, and the // enqueue msg below, don't add anything because it literally says the same thing as the code (.EmitEvents and .EnqueueMsg).

Comments are great to remind you of the rationale you are doing things, or to clarify some hard to read logic, and to make sure people can spot inconsistencies, but they are not needed to decorate the obvious.

In this instance, I'm not sure what method we're in from the PR diff and why we are emitting this event, or what the event is; for all that I have to carefully read all the attributes. The comment doesn't help with this, but TBH I doubt any comment would in this case.

Sorry, I'm not trying to be pedantic or obnoxious. You can leave the comment in if it helps you. I only mentioned it because I also used to get into the habit of adding comments to every line because after a while the ones without comments looked naked and cold. But it's okay not to comment as well 😌

Comment on lines 17 to 22
func() *types.MsgWrappedDelegate {
return &types.MsgWrappedDelegate{
Msg: &stakingtypes.MsgDelegate{},
}
},
false,
Copy link
Contributor

Choose a reason for hiding this comment

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

Great that you are testing individual requests, but this looks dubious. We have a completely empty delegate request, and it doesn't fail. We don't know who wants to delegate to whom and how much, but that's okay?

Do the staking messages have some validation logic that could filter this out?

Copy link
Member Author

Choose a reason for hiding this comment

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

This test case merely ensures that WrappedDelegate won't panic. Perhaps I will add another Require() to ensure that the msg is indeed enqueued.

Do the staking messages have some validation logic that could filter this out?

There is. For each sdk.Msg it has to implement a function ValidateBasic() that does some basic stateless checks, e.g., https://github.com/cosmos/cosmos-sdk/blob/v0.45.5/x/staking/types/msg.go#L89-L144. However, ValidateBasic() will be invoked only when a user uses the client to submit a message and when a validator executes runTx. If we submit the message via MsgServer then ValidateBasic() won't be invoked. The logic of ValidateBasic() is tested under x/epoching/types/msg_test.go, and the logic of MsgServer will be tested in x/epoching/keeper/msg_server_test.go.

Copy link
Contributor

Choose a reason for hiding this comment

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

Okay, maybe this is worth a comment to say even though these are not valid messages, the service does no validation.

Comment on lines 78 to 83
{"basic good", sdk.AccAddress(valAddr1), valAddr2, coinPos, true, false},
{"self bond", sdk.AccAddress(valAddr1), valAddr1, coinPos, true, false},
{"empty delegator", sdk.AccAddress(emptyAddr), valAddr1, coinPos, false, false},
{"empty validator", sdk.AccAddress(valAddr1), emptyAddr, coinPos, false, false},
{"empty bond", sdk.AccAddress(valAddr1), valAddr2, coinZero, false, false},
{"nil bold", sdk.AccAddress(valAddr1), valAddr2, sdk.Coin{}, false, false},
Copy link
Contributor

Choose a reason for hiding this comment

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

No test case in the whole file has expectErr as true. Remove?

Copy link
Contributor

Choose a reason for hiding this comment

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

And I mean all the other test cases don't hit expectErr ever.

Copy link
Contributor

@aakoshh aakoshh left a comment

Choose a reason for hiding this comment

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

Great, you obviously put in a lot of thought into capturing many things that can go wrong 👏

Base automatically changed from epoching-endblock-beginblock to main July 6, 2022 10:01
@SebastianElvis SebastianElvis changed the base branch from main to epoching-slash-panicing July 7, 2022 04:52
@SebastianElvis
Copy link
Member Author

SebastianElvis commented Jul 7, 2022

Thanks for the comments Akosh! I have fixed the comments and added fuzz tests. Feel free to review again.

A thing is that Cosmos SDK's query response with pagination is out-of-order. You can see from the log below, where txid is generated in the test and resp txid is the response from the keeper. Only the first two are consistent and the rest are out-of-order. That's why FuzzEpochMsgs checks whether a responded msg's txid is in a map or not, rather than comparing two byte matrices.

Another thing is that the Testify library does not support Golang's fuzzing at the moment, and thus I wrote fuzz tests outside the suite.

--- FAIL: FuzzEpochMsgs (0.02s)
    --- FAIL: FuzzEpochMsgs/seed#0 (0.00s)
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:240: numMsgs:  12 . limit:  6 . len(resp.Msgs):  6
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  3a 1f 69 74 2d b1 8f ed  34 56 b7 e7 ac d1 e2 1d  |:.it-...4V......|
             00000010  0b 8c 54 7a 54 36 20 60  3c 2e f9 30 87 7d 2c 83  |..TzT6 `<..0.},.|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  19 10 c6 06 5f 0b cc d1  af f3 83 71 95 f2 35 06  |...._......q..5.|
             00000010  0a 3d 57 ad 04 49 c4 ce  06 ac 01 88 91 cc 06 e9  |.=W..I..........|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  fc 8f 20 37 15 e7 b1 a5  f2 21 14 73 e4 57 08 a1  |.. 7.....!.s.W..|
             00000010  3f 3a 1a 1e 6d a7 c6 a2  4c 71 86 21 70 0f 5a 72  |?:..m...Lq.!p.Zr|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  6d a5 cb 6a c5 8f c5 80  44 26 df e4 85 02 2f cf  |m..j....D&..../.|
             00000010  c6 f9 a0 7d e1 1c 8d 3f  69 30 82 6b a1 aa c7 a3  |...}...?i0.k....|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  8f ba 30 cc 70 5b c6 07  58 c4 01 f0 39 c4 86 6b  |..0.p[..X...9..k|
             00000010  31 ba fd e2 92 8f 59 b6  18 bf e4 25 06 4d 85 a0  |1.....Y....%.M..|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  b8 bd 1d 23 46 0a e1 25  4d a6 16 a6 45 dd fc 2a  |...#F..%M...E..*|
             00000010  fb dd 03 c4 d6 18 8c 94  45 48 69 ef c8 5c 4b b7  |........EHi..\K.|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  19 cb 59 ef bb d7 d6 ab  3a 1c 27 72 8a 09 25 c6  |..Y.....:.'r..%.|
             00000010  1a ed 28 fd be 3a b7 e6  3d 41 2a 94 89 b4 f1 15  |..(..:..=A*.....|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  b8 c6 89 90 72 4b 53 c0  b2 dc d6 5c 49 35 4d c4  |....rKS....\I5M.|
             00000010  0c 63 70 32 e7 d5 a3 49  51 13 82 8c d0 cc d5 88  |.cp2...IQ.......|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  9a 16 fc 15 92 01 79 6b  52 69 fe 41 a6 94 30 52  |......ykRi.A..0R|
             00000010  82 ef 9d 98 de a0 ae c7  6a 98 71 9e 61 ce 64 52  |........j.q.a.dR|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  97 25 88 7b 9f f4 6d fd  64 1a a2 96 82 7b 68 01  |.%.{..m.d....{h.|
             00000010  40 b5 9b 11 19 c8 00 a7  56 c1 59 05 e5 aa 26 63  |@.......V.Y...&c|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  be 06 64 26 bd de b0 72  77 23 90 a4 49 da c9 72  |..d&...rw#..I..r|
             00000010  99 0e b9 21 4d 13 ba c0  10 a9 ae 35 d3 86 7a 11  |...!M......5..z.|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  18 06 73 3a f5 b9 30 bc  08 0f 81 94 1a 95 cb 8f  |..s:..0.........|
             00000010  1f 58 9e 32 f3 ca 2e c6  b1 df 76 30 70 61 3b bc  |.X.2......v0pa;.|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:246: resp txid:  ([]uint8) (len=32 cap=32) {
             00000000  3a 1f 69 74 2d b1 8f ed  34 56 b7 e7 ac d1 e2 1d  |:.it-...4V......|
             00000010  0b 8c 54 7a 54 36 20 60  3c 2e f9 30 87 7d 2c 83  |..TzT6 `<..0.},.|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:246: resp txid:  ([]uint8) (len=32 cap=32) {
             00000000  19 10 c6 06 5f 0b cc d1  af f3 83 71 95 f2 35 06  |...._......q..5.|
             00000010  0a 3d 57 ad 04 49 c4 ce  06 ac 01 88 91 cc 06 e9  |.=W..I..........|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:246: resp txid:  ([]uint8) (len=32 cap=32) {
             00000000  be 06 64 26 bd de b0 72  77 23 90 a4 49 da c9 72  |..d&...rw#..I..r|
             00000010  99 0e b9 21 4d 13 ba c0  10 a9 ae 35 d3 86 7a 11  |...!M......5..z.|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:246: resp txid:  ([]uint8) (len=32 cap=32) {
             00000000  18 06 73 3a f5 b9 30 bc  08 0f 81 94 1a 95 cb 8f  |..s:..0.........|
             00000010  1f 58 9e 32 f3 ca 2e c6  b1 df 76 30 70 61 3b bc  |.X.2......v0pa;.|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:246: resp txid:  ([]uint8) (len=32 cap=32) {
             00000000  fc 8f 20 37 15 e7 b1 a5  f2 21 14 73 e4 57 08 a1  |.. 7.....!.s.W..|
             00000010  3f 3a 1a 1e 6d a7 c6 a2  4c 71 86 21 70 0f 5a 72  |?:..m...Lq.!p.Zr|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:246: resp txid:  ([]uint8) (len=32 cap=32) {
             00000000  6d a5 cb 6a c5 8f c5 80  44 26 df e4 85 02 2f cf  |m..j....D&..../.|
             00000010  c6 f9 a0 7d e1 1c 8d 3f  69 30 82 6b a1 aa c7 a3  |...}...?i0.k....|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:250: 
            	Error Trace:	grpc_query_test.go:250
            	            				value.go:556
            	            				value.go:339
            	            				fuzz.go:337
            	Error:      	Not equal: 
            	            	expected: []byte{0xfc, 0x8f, 0x20, 0x37, 0x15, 0xe7, 0xb1, 0xa5, 0xf2, 0x21, 0x14, 0x73, 0xe4, 0x57, 0x8, 0xa1, 0x3f, 0x3a, 0x1a, 0x1e, 0x6d, 0xa7, 0xc6, 0xa2, 0x4c, 0x71, 0x86, 0x21, 0x70, 0xf, 0x5a, 0x72}
            	            	actual  : []byte{0xbe, 0x6, 0x64, 0x26, 0xbd, 0xde, 0xb0, 0x72, 0x77, 0x23, 0x90, 0xa4, 0x49, 0xda, 0xc9, 0x72, 0x99, 0xe, 0xb9, 0x21, 0x4d, 0x13, 0xba, 0xc0, 0x10, 0xa9, 0xae, 0x35, 0xd3, 0x86, 0x7a, 0x11}
            	            	
            	            	Diff:
            	            	--- Expected
            	            	+++ Actual
            	            	@@ -1,4 +1,4 @@
            	            	 ([]uint8) (len=32) {
            	            	- 00000000  fc 8f 20 37 15 e7 b1 a5  f2 21 14 73 e4 57 08 a1  |.. 7.....!.s.W..|
            	            	- 00000010  3f 3a 1a 1e 6d a7 c6 a2  4c 71 86 21 70 0f 5a 72  |?:..m...Lq.!p.Zr|
            	            	+ 00000000  be 06 64 26 bd de b0 72  77 23 90 a4 49 da c9 72  |..d&...rw#..I..r|
            	            	+ 00000010  99 0e b9 21 4d 13 ba c0  10 a9 ae 35 d3 86 7a 11  |...!M......5..z.|
            	            	 }
            	Test:       	FuzzEpochMsgs/seed#0
    --- FAIL: FuzzEpochMsgs/seed#1 (0.00s)
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:240: numMsgs:  44 . limit:  23 . len(resp.Msgs):  23
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  c4 94 0e d1 d1 2e 1a 4b  66 c8 d8 f6 06 93 dd 10  |.......Kf.......|
             00000010  cb 19 09 1b 2a 93 19 24  3e 6e dc f9 43 6e ce 82  |....*..$>n..Cn..|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  6d c0 29 52 1c 25 47 08  c8 3d 8a 67 f8 f4 87 93  |m.)R.%G..=.g....|
             00000010  69 06 c3 52 b9 62 30 e2  ee 06 61 b7 ef 13 74 f3  |i..R.b0...a...t.|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  44 f7 81 d7 d4 62 3c b4  d8 46 0d 8a 2c a8 be b7  |D....b<..F..,...|
             00000010  82 40 1b ba 95 ca 06 7e  e3 46 c6 23 18 ed e4 75  |.@.....~.F.#...u|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  1c 10 4c 06 fa 79 63 ef  75 cd 20 7b dc d0 f1 ed  |..L..yc.u. {....|
             00000010  8d 3c a7 15 76 5f c1 5b  cd ef 8e 5a e8 c9 88 d9  |.<..v_.[...Z....|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  9a 89 e0 3f 65 c2 77 70  e6 16 2f c7 0d dc 19 9a  |...?e.wp../.....|
             00000010  8d 34 4c 1a 95 f4 cc f0  5d 74 8e 76 a5 e1 0a 3c  |.4L.....]t.v...<|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  3d 59 99 ed 3a 02 8b 6e  8c 8a 74 d0 86 6e fc 4c  |=Y..:..n..t..n.L|
             00000010  da 29 78 b2 6d 20 07 9e  81 0e c8 9a 02 dc dd b5  |.)x.m ..........|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  79 e8 df 57 02 b1 01 7a  c9 8d 89 cb 2c 91 0f 80  |y..W...z....,...|
             00000010  dc d3 e8 21 81 ed fb 5a  76 d2 84 7a d0 f8 ba 17  |...!...Zv..z....|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  73 27 c3 a2 9f ac c7 83  9c 99 e7 99 e9 e1 73 4e  |s'............sN|
             00000010  d1 cc 06 08 b2 7d 63 64  68 3b 40 e7 df d3 bd 1b  |.....}cdh;@.....|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  29 c9 81 b5 70 0c 8c 0c  ee 09 e9 e7 21 56 7e d0  |)...p.......!V~.|
             00000010  c6 95 98 24 c1 6e 22 21  e4 e9 89 76 7a 34 9d 43  |...$.n"!...vz4.C|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  cf ca 84 f5 74 35 6b 59  7a 19 2d 7a 33 d0 86 17  |....t5kYz.-z3...|
             00000010  72 98 a4 13 01 15 4e 13  39 fa 95 9a 56 95 05 85  |r.....N.9...V...|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  c6 36 56 9a 3c 64 f1 a1  7d bb 77 cb 16 bf b5 fe  |.6V.<d..}.w.....|
             00000010  71 61 18 6c 74 16 bf 76  19 ee 08 65 f8 87 c6 9d  |qa.lt..v...e....|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  a6 fa ee 23 87 0d 64 9f  bd fe f7 3d 95 99 47 d3  |...#..d....=..G.|
             00000010  b5 f3 c9 6c 76 72 bc e0  01 17 5d a5 a5 e9 28 01  |...lvr....]...(.|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  1c e9 47 f6 20 61 77 3a  93 0b b0 a2 ce 71 7d ca  |..G. aw:.....q}.|
             00000010  ba ba 20 e4 46 17 6d 60  93 db 9b e6 7a da b6 da  |.. .F.m`....z...|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  aa 98 5b 27 7d 2c 36 62  71 61 5b 48 17 13 45 00  |..['},6bqa[H..E.|
             00000010  9e 0a 10 1b 5c 5f 32 ba  ca 72 45 6f af a1 c4 63  |....\_2..rEo...c|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  1a 51 90 b3 09 48 92 ea  be 10 9c 88 88 79 91 48  |.Q...H.......y.H|
             00000010  17 7d cd 67 86 01 21 6e  0c 42 4b 92 80 db 1f 19  |.}.g..!n.BK.....|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  b1 eb f4 84 fe e6 39 d2  d4 f0 11 da a7 d9 34 6b  |......9.......4k|
             00000010  0b d4 38 c3 f7 7e b9 6f  ea 13 89 4e 31 ae 88 09  |..8..~.o...N1...|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  3b b5 2d 08 55 6d 18 a7  0c 56 37 17 e0 81 55 fc  |;.-.Um...V7...U.|
             00000010  6f 77 f2 c2 88 f7 db 12  cb d6 12 99 56 bf 30 0e  |ow..........V.0.|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  c2 a0 e8 48 ba 4c cb 4c  94 76 ea 20 b7 54 22 e2  |...H.L.L.v. .T".|
             00000010  b1 76 30 34 57 bd d0 45  90 d3 39 17 79 ba 27 46  |.v04W..E..9.y.'F|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  ff 26 87 1b 13 95 39 e1  27 10 32 6f 93 c1 73 74  |.&....9.'.2o..st|
             00000010  8b 3b 43 3f b2 d3 55 1c  87 c4 c1 b8 03 6e 58 3f  |.;C?..U......nX?|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  5e 7e 9d b7 f3 03 c5 fd  5c 6f 20 97 b8 80 11 fd  |^~......\o .....|
             00000010  2a 86 e8 48 37 d3 fe 5c  15 51 9b 53 cf fd f6 3c  |*..H7..\.Q.S...<|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  0a bd 91 e6 a4 8a 27 c8  53 6c dd ea 0e 2f f8 12  |......'.Sl.../..|
             00000010  cd 99 09 20 4a dc 1f cf  ba 60 4e 0d 37 ae 6d 54  |... J....`N.7.mT|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  5d ea aa 60 81 cc c7 e3  34 e3 7a 87 b1 60 af ad  |]..`....4.z..`..|
             00000010  19 4d 5f 30 b1 5a 7d 49  51 57 a4 48 d3 bd 4d bf  |.M_0.Z}IQW.H..M.|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  98 15 d9 29 00 ae dc c2  26 2a 50 72 59 15 b3 f7  |...)....&*PrY...|
             00000010  e5 bc 99 16 4b 3c e2 52  de da 76 bc f9 cd 79 55  |....K<.R..v...yU|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  72 e7 e4 97 30 a4 34 a2  cf bd 28 5e f5 f2 b5 81  |r...0.4...(^....|
             00000010  66 65 31 fc 61 07 63 bf  28 de e6 32 42 b7 c1 55  |fe1.a.c.(..2B..U|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  ac c2 18 0c 13 57 f5 fd  bb e1 95 c2 b2 de fd d0  |.....W..........|
             00000010  69 6a ee fb 51 5c 35 23  08 e5 09 f9 55 f4 6b 69  |ij..Q\5#....U.ki|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  58 9e 19 91 79 42 ce c7  02 c8 21 a8 5b 39 71 16  |X...yB....!.[9q.|
             00000010  18 ba 51 4b cd 59 49 85  95 98 4e 0a fb d7 45 75  |..QK.YI...N...Eu|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  ea d6 13 11 de 06 38 72  7c 29 df 47 ca 33 b4 af  |......8r|).G.3..|
             00000010  b0 81 84 70 b0 d9 d1 e9  fe 76 b7 c2 df fa 16 a4  |...p.....v......|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  e8 df 8a 57 1c 55 73 33  2f c3 a2 90 1f 4e 01 7b  |...W.Us3/....N.{|
             00000010  88 9a 59 02 df 50 62 9d  0b 25 10 15 8e 2a 68 4c  |..Y..Pb..%...*hL|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  65 7a 57 d9 f6 f4 ee 58  7c 7e f3 c2 1d fe 07 70  |ezW....X|~.....p|
             00000010  6d b3 75 73 7e 5e ab 62  b9 47 c0 c1 3b fe cd d5  |m.us~^.b.G..;...|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  99 a4 c9 d8 5d 0e 05 16  0c 33 be ea 1a 38 66 21  |....]....3...8f!|
             00000010  97 11 64 72 47 5a cb b5  34 43 22 42 27 14 f3 3a  |..drGZ..4C"B'..:|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  e5 a9 49 59 af 72 f9 d7  25 61 b9 84 ef cf d1 9d  |..IY.r..%a......|
             00000010  e9 2e d8 66 ab 78 2e 23  ab 0f f2 9e 93 ed 94 d8  |...f.x.#........|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  de 0a 8b 83 65 de 98 25  4c 47 cf 83 ed b1 ab 59  |....e..%LG.....Y|
             00000010  d8 e2 90 16 82 84 4e d7  33 24 7c 93 dd 4d b7 9c  |......N.3$|..M..|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  be 1c 79 38 12 5d 1e 46  9d 13 47 aa 24 37 14 6a  |..y8.].F..G.$7.j|
             00000010  3b 85 5f 99 85 b5 6b e7  42 aa 0f 0c 79 f2 48 16  |;._...k.B...y.H.|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  9c f6 08 e9 1b 32 9e d4  0b bb 00 da 3b 16 46 d3  |.....2......;.F.|
             00000010  07 cf 1a 96 3f c9 89 77  5f 2a 4a 2a de 75 09 41  |....?..w_*J*.u.A|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  12 6c d8 63 e0 c7 9a 8c  e5 88 22 19 10 d0 28 a2  |.l.c......"...(.|
             00000010  01 3c c3 64 b8 69 6f 96  79 e0 ad 24 34 67 a7 25  |.<.d.io.y..$4g.%|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  7f 20 f5 40 f0 91 0c c2  f1 0a b8 12 d2 82 89 57  |. [email protected]|
             00000010  1b f4 e8 2c 10 b2 6c 14  a7 3b b0 46 11 f9 8b 4e  |...,..l..;.F...N|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  09 32 1a 87 78 60 37 cd  89 1f 8a 38 27 84 e7 41  |.2..x`7....8'..A|
             00000010  fd ff 01 06 28 6f 91 26  df 91 58 3d c8 d6 7d db  |....(o.&..X=..}.|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  96 5d 7b f1 de d7 58 ed  34 41 32 d0 b7 21 9f df  |.]{...X.4A2..!..|
             00000010  44 14 9d 07 34 ba 23 2e  7f 32 09 af 4d 9f 0a f4  |D...4.#..2..M...|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  89 c3 7a 25 b3 8d cf f4  0d a2 a6 c8 b3 86 e6 7a  |..z%...........z|
             00000010  70 23 78 7c fc 0a d5 8e  1f dd d0 ca 30 50 fb c2  |p#x|........0P..|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  4a 67 04 bb 0a 17 fb d0  0b df 5e 7b 92 9c 07 cd  |Jg........^{....|
             00000010  0a dc d4 2d d6 e8 0e a7  45 ef 92 b5 1f c0 93 bc  |...-....E.......|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  8b d0 65 4f a0 19 39 02  26 84 f6 0f c2 c9 5d ed  |..eO..9.&.....].|
             00000010  2b 04 ac d6 15 17 7c 1c  36 4d e5 61 65 19 a7 3e  |+.....|.6M.ae..>|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  52 e1 15 71 ac 62 33 81  f3 35 a4 1f 2e 02 98 fe  |R..q.b3..5......|
             00000010  43 ff ae ce 88 fc 6f 3e  ce 01 25 17 b1 37 80 a5  |C.....o>..%..7..|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  d2 d0 a3 8c 2b 80 4b 26  d4 67 71 f7 02 e8 72 15  |....+.K&.gq...r.|
             00000010  de 51 67 ba 49 d5 87 15  9b 9c 6f 03 2a d2 2c 3c  |.Qg.I.....o.*.,<|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:242: txid:  ([]uint8) (len=32 cap=32) {
             00000000  1e 12 67 b4 63 1a 44 d6  d4 24 ce 53 a5 d2 07 7e  |..g.c.D..$.S...~|
             00000010  f0 4b 9b 4e 10 1a 86 ac  1e ef b1 7d 66 32 25 d5  |.K.N.......}f2%.|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:246: resp txid:  ([]uint8) (len=32 cap=32) {
             00000000  c4 94 0e d1 d1 2e 1a 4b  66 c8 d8 f6 06 93 dd 10  |.......Kf.......|
             00000010  cb 19 09 1b 2a 93 19 24  3e 6e dc f9 43 6e ce 82  |....*..$>n..Cn..|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:246: resp txid:  ([]uint8) (len=32 cap=32) {
             00000000  6d c0 29 52 1c 25 47 08  c8 3d 8a 67 f8 f4 87 93  |m.)R.%G..=.g....|
             00000010  69 06 c3 52 b9 62 30 e2  ee 06 61 b7 ef 13 74 f3  |i..R.b0...a...t.|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:246: resp txid:  ([]uint8) (len=32 cap=32) {
             00000000  c6 36 56 9a 3c 64 f1 a1  7d bb 77 cb 16 bf b5 fe  |.6V.<d..}.w.....|
             00000010  71 61 18 6c 74 16 bf 76  19 ee 08 65 f8 87 c6 9d  |qa.lt..v...e....|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:246: resp txid:  ([]uint8) (len=32 cap=32) {
             00000000  a6 fa ee 23 87 0d 64 9f  bd fe f7 3d 95 99 47 d3  |...#..d....=..G.|
             00000010  b5 f3 c9 6c 76 72 bc e0  01 17 5d a5 a5 e9 28 01  |...lvr....]...(.|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:246: resp txid:  ([]uint8) (len=32 cap=32) {
             00000000  1c e9 47 f6 20 61 77 3a  93 0b b0 a2 ce 71 7d ca  |..G. aw:.....q}.|
             00000010  ba ba 20 e4 46 17 6d 60  93 db 9b e6 7a da b6 da  |.. .F.m`....z...|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:246: resp txid:  ([]uint8) (len=32 cap=32) {
             00000000  aa 98 5b 27 7d 2c 36 62  71 61 5b 48 17 13 45 00  |..['},6bqa[H..E.|
             00000010  9e 0a 10 1b 5c 5f 32 ba  ca 72 45 6f af a1 c4 63  |....\_2..rEo...c|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:246: resp txid:  ([]uint8) (len=32 cap=32) {
             00000000  1a 51 90 b3 09 48 92 ea  be 10 9c 88 88 79 91 48  |.Q...H.......y.H|
             00000010  17 7d cd 67 86 01 21 6e  0c 42 4b 92 80 db 1f 19  |.}.g..!n.BK.....|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:246: resp txid:  ([]uint8) (len=32 cap=32) {
             00000000  b1 eb f4 84 fe e6 39 d2  d4 f0 11 da a7 d9 34 6b  |......9.......4k|
             00000010  0b d4 38 c3 f7 7e b9 6f  ea 13 89 4e 31 ae 88 09  |..8..~.o...N1...|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:246: resp txid:  ([]uint8) (len=32 cap=32) {
             00000000  3b b5 2d 08 55 6d 18 a7  0c 56 37 17 e0 81 55 fc  |;.-.Um...V7...U.|
             00000010  6f 77 f2 c2 88 f7 db 12  cb d6 12 99 56 bf 30 0e  |ow..........V.0.|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:246: resp txid:  ([]uint8) (len=32 cap=32) {
             00000000  c2 a0 e8 48 ba 4c cb 4c  94 76 ea 20 b7 54 22 e2  |...H.L.L.v. .T".|
             00000010  b1 76 30 34 57 bd d0 45  90 d3 39 17 79 ba 27 46  |.v04W..E..9.y.'F|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:246: resp txid:  ([]uint8) (len=32 cap=32) {
             00000000  ff 26 87 1b 13 95 39 e1  27 10 32 6f 93 c1 73 74  |.&....9.'.2o..st|
             00000010  8b 3b 43 3f b2 d3 55 1c  87 c4 c1 b8 03 6e 58 3f  |.;C?..U......nX?|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:246: resp txid:  ([]uint8) (len=32 cap=32) {
             00000000  5e 7e 9d b7 f3 03 c5 fd  5c 6f 20 97 b8 80 11 fd  |^~......\o .....|
             00000010  2a 86 e8 48 37 d3 fe 5c  15 51 9b 53 cf fd f6 3c  |*..H7..\.Q.S...<|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:246: resp txid:  ([]uint8) (len=32 cap=32) {
             00000000  44 f7 81 d7 d4 62 3c b4  d8 46 0d 8a 2c a8 be b7  |D....b<..F..,...|
             00000010  82 40 1b ba 95 ca 06 7e  e3 46 c6 23 18 ed e4 75  |.@.....~.F.#...u|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:246: resp txid:  ([]uint8) (len=32 cap=32) {
             00000000  0a bd 91 e6 a4 8a 27 c8  53 6c dd ea 0e 2f f8 12  |......'.Sl.../..|
             00000010  cd 99 09 20 4a dc 1f cf  ba 60 4e 0d 37 ae 6d 54  |... J....`N.7.mT|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:246: resp txid:  ([]uint8) (len=32 cap=32) {
             00000000  5d ea aa 60 81 cc c7 e3  34 e3 7a 87 b1 60 af ad  |]..`....4.z..`..|
             00000010  19 4d 5f 30 b1 5a 7d 49  51 57 a4 48 d3 bd 4d bf  |.M_0.Z}IQW.H..M.|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:246: resp txid:  ([]uint8) (len=32 cap=32) {
             00000000  98 15 d9 29 00 ae dc c2  26 2a 50 72 59 15 b3 f7  |...)....&*PrY...|
             00000010  e5 bc 99 16 4b 3c e2 52  de da 76 bc f9 cd 79 55  |....K<.R..v...yU|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:246: resp txid:  ([]uint8) (len=32 cap=32) {
             00000000  72 e7 e4 97 30 a4 34 a2  cf bd 28 5e f5 f2 b5 81  |r...0.4...(^....|
             00000010  66 65 31 fc 61 07 63 bf  28 de e6 32 42 b7 c1 55  |fe1.a.c.(..2B..U|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:246: resp txid:  ([]uint8) (len=32 cap=32) {
             00000000  ac c2 18 0c 13 57 f5 fd  bb e1 95 c2 b2 de fd d0  |.....W..........|
             00000010  69 6a ee fb 51 5c 35 23  08 e5 09 f9 55 f4 6b 69  |ij..Q\5#....U.ki|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:246: resp txid:  ([]uint8) (len=32 cap=32) {
             00000000  58 9e 19 91 79 42 ce c7  02 c8 21 a8 5b 39 71 16  |X...yB....!.[9q.|
             00000010  18 ba 51 4b cd 59 49 85  95 98 4e 0a fb d7 45 75  |..QK.YI...N...Eu|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:246: resp txid:  ([]uint8) (len=32 cap=32) {
             00000000  ea d6 13 11 de 06 38 72  7c 29 df 47 ca 33 b4 af  |......8r|).G.3..|
             00000010  b0 81 84 70 b0 d9 d1 e9  fe 76 b7 c2 df fa 16 a4  |...p.....v......|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:246: resp txid:  ([]uint8) (len=32 cap=32) {
             00000000  e8 df 8a 57 1c 55 73 33  2f c3 a2 90 1f 4e 01 7b  |...W.Us3/....N.{|
             00000010  88 9a 59 02 df 50 62 9d  0b 25 10 15 8e 2a 68 4c  |..Y..Pb..%...*hL|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:246: resp txid:  ([]uint8) (len=32 cap=32) {
             00000000  65 7a 57 d9 f6 f4 ee 58  7c 7e f3 c2 1d fe 07 70  |ezW....X|~.....p|
             00000010  6d b3 75 73 7e 5e ab 62  b9 47 c0 c1 3b fe cd d5  |m.us~^.b.G..;...|
            }
            
        /Users/rhan0013/Projects/Babylon/babylon/x/epoching/keeper/grpc_query_test.go:246: resp txid:  ([]uint8) (len=32 cap=32) {
             00000000  99 a4 c9 d8 5d 0e 05 16  0c 33 be ea 1a 38 66 21  |....]....3...8f!|
             00000010  97 11 64 72 47 5a cb b5  34 43 22 42 27 14 f3 3a  |..drGZ..4C"B'..:|
            }

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! Added some comments about simplifying things

// 2. If the flag is true, set the param in the keeper
// 3. Send the query to get the current param
// 4. If the flag is true, verify if the returned param is the set one, otherwise the default one
func FuzzParamsQuery(f *testing.F) {
Copy link
Member

Choose a reason for hiding this comment

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

Do we need both a FuzzParamsQuery and a TestParamsQuery method? From my understanding, a fuzzing method can run as a normal test case which would be equivalent if the base cases (added using f.Add()) are the same. However, I can see that the TestParamsQuery uses more complex types than fuzzing allows, so I'm trying to understand whether we can replicate the behavior on FuzzParamsQuery.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not sure. I was following Akosh's comment on this one. It seems to be more versatile than TestParamsQuery given the random flag here.

f.Add(uint64(11111), true)
f.Add(uint64(22222), false)

f.Fuzz(func(t *testing.T, epochInterval uint64, flag bool) {
Copy link
Member

Choose a reason for hiding this comment

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

Instead of a flag, you can pass along a seed int64 as a parameter and inside the function do:

rand.Seed(seed)
flag := rand.Intn(2)

A seed might be more useful for other random data, while you can easily extend it to more complex stuff instead of true/false.

Copy link
Member Author

Choose a reason for hiding this comment

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

Do we need to generate such a random flag by ourselves? IIUC flag in f.Fuzz will be given a randomly generated value with the corpus as input.

req := types.QueryParamsRequest{}
resp, err := queryClient.Params(wctx, &req)
require.NoError(t, err)
// if the random flag is true, then resp.Params should be changed, otherwise default
Copy link
Member

Choose a reason for hiding this comment

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

I'm not entirely sure about the usage of the flag. Given that there's a 50% chance that the flag would be set to false, for 50% of the test cases we are testing the same thing, wasting processing power.

Maybe we could use the test case of epochInterval being 0 as the case where the default parameters should be used, since either way the epochInterval should not be allowed to be less than 1, right?

Copy link
Member Author

@SebastianElvis SebastianElvis Jul 7, 2022

Choose a reason for hiding this comment

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

Maybe we could use the test case of epochInterval being 0 as the case where the default parameters should be used, since either way the epochInterval should not be allowed to be less than 1, right?

Good catch, we definitely need to test this case! Will do.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, please, go creative with fuzzing, my flag suggestion was just to make sure that default and non-default are both tested. I usually do something like p := rand.Int() % 100 and then say if p < 10 then do something 10% of the times, etc.

true,
types.DefaultParams(),
sdk.NewUint(1),
sdk.NewUint(suite.keeper.GetParams(suite.ctx).EpochInterval * 1),
Copy link
Member

Choose a reason for hiding this comment

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

* 1?

Copy link
Member Author

Choose a reason for hiding this comment

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

I wanted to highlight that EpochBoundary == EpochInterval * <epoch_number>. It can be omitted though.

},
}

for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
tc.malleate()
wctx := sdk.WrapSDKContext(ctx)
resp, err := queryClient.CurrentEpoch(wctx, &req)
suite.NoError(err)
Copy link
Member

Choose a reason for hiding this comment

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

What would be an error condition here? Could we test that?

Copy link
Member Author

Choose a reason for hiding this comment

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

Typically no error will be returned in this query. The reason of this is that Cosmos SDK enforces each query to return a response and an error.

Limit: 100,
},
},
[]*types.QueuedMessage{},
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. You could pass the TxId as a parameter and construct inside the test case to keep things simple.

} else {
suite.NotEqual(&types.QueryParamsResponse{Params: tc.params}, resp)
resp, err := queryClient.EpochMsgs(wctx, tc.req)
suite.NoError(err)
Copy link
Member

Choose a reason for hiding this comment

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

What would be an error condition here? Can we test for it?

wctx := sdk.WrapSDKContext(ctx)
// enque a random number of msgs with random txids
for i := uint64(0); i < numMsgs; i++ {
txid := genRandomByteSlice(32)
Copy link
Member

Choose a reason for hiding this comment

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

I implemented a similar function here. Maybe we can add those functions in a global testutils space?

Copy link
Member

Choose a reason for hiding this comment

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

Also, you are generating a random slice, but you do not set a randomness seed anywhere. I would suggest that you pass a seed as a parameter like the btclightclient fuzz tests (see here)

Copy link
Member Author

Choose a reason for hiding this comment

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

In fact I was copy/pasting your implementation 🤣 perhaps I can start adding these functions to such testutils in this PR. 👍

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes it is imperative that you use a seed, otherwise these random generations are not repeatable!

I updated my comment to unify requests and state mutation, so multiple queries can be sent along the way. Note that only the seed is the input parameter. #47 (comment)

{
"MsgWrappedDelegate",
&types.MsgWrappedDelegate{
Msg: &stakingtypes.MsgDelegate{},
Copy link
Member

Choose a reason for hiding this comment

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

Maybe pass the Msg itself and construct the wrapped message in the test case?

{
"MsgWrappedDelegate",
&types.MsgWrappedUndelegate{
Msg: &stakingtypes.MsgUndelegate{},
Copy link
Member

Choose a reason for hiding this comment

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

Same

@aakoshh
Copy link
Contributor

aakoshh commented Jul 7, 2022

That is one helluva cryptic output from the fuzzer 😳

@SebastianElvis
Copy link
Member Author

SebastianElvis commented Jul 8, 2022

Thanks for the insightful comments Akosh and Vitalis! I have updated the PR w.r.t. the comments. This PR now also fixes an issue to disallow wrapped msgs that point to no inside unwrapped msgs and adds corresponding tests. Feel free to have a look again.

Same here. You could pass the TxId as a parameter and construct inside the test case to keep things simple.

After a second thought I found we will need to keep the []QueuedMessage, since {TxId: []byte{0x01}} is in fact a new object in the []QueuedMessage slice rather than a parameter of it. I have also added a new test case to make the queue have more than 1 msgs.

Copy link
Contributor

@aakoshh aakoshh 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 following up on all my comments! I don't remember any more blockers.

Glad to see we are making headways into growing our testing chops! 💪

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.

Overall LGTM! Some minor comments. Also I would suggest that you combine the unit tests and fuzz tests as there is duplication there.

}

// FuzzParamsQuery fuzzes queryClient.Params
// 1. Generate random param and a flag
Copy link
Member

Choose a reason for hiding this comment

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

A flag does not exist anymore

params.EpochInterval = epochInterval

// test the case of EpochInterval == 0
zeroIntervalFlag := rand.Intn(2)
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 this flag? Maybe you can do

if epochInterval == 0 {
     // do the check on the below if condition
     // set epoch interval into a random int
}

// 1. generate a random number of epochs to increment
// 2. query the current epoch and boundary
// 3. compare them with the correctly calculated ones
func FuzzCurrentEpoch(f *testing.F) {
Copy link
Member

Choose a reason for hiding this comment

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

They do not ignore fuzz tests, they just don't do the fuzzing if I understand correctly. In order for fuzzing to be performed you need to ask for a particular function to be fuzzed.

@SebastianElvis SebastianElvis merged commit 1808729 into epoching-slash-panicing Jul 8, 2022
@SebastianElvis SebastianElvis deleted the epoching-tests branch July 8, 2022 10:36
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