-
Notifications
You must be signed in to change notification settings - Fork 524
Fixing a bug in eval and TestOnSwitchToUnSupportedProtocol #2220
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -421,98 +421,96 @@ func TestServiceFetchBlocksMalformed(t *testing.T) { | |
| //require.True(t, s.fetcherFactory.(*MockedFetcherFactory).fetcher.client.closed) | ||
| } | ||
|
|
||
| func TestOnSwitchToUnSupportedProtocol(t *testing.T) { | ||
| t.Skip("This test is flacky and need to be fixed.") | ||
|
|
||
| // Test the interruption in the initial loop | ||
| // This cannot happen in practice, but is used to test the code. | ||
| { | ||
| lastRoundRemote := 5 | ||
| lastRoundLocal := 0 | ||
| roundWithSwitchOn := 0 | ||
| local, remote := helperTestOnSwitchToUnSupportedProtocol(t, lastRoundRemote, lastRoundLocal, roundWithSwitchOn, 0) | ||
|
|
||
| // Last supported round is 0, but is guaranteed | ||
| // to stop after 2 rounds. | ||
|
|
||
| // SeedLookback is 2, which allows two parallel fetches. | ||
| // i.e. rounds 1 and 2 may be simultaneously fetched. | ||
| require.Less(t, int(local.LastRound()), 3) | ||
| require.Equal(t, lastRoundRemote, int(remote.LastRound())) | ||
| remote.Ledger.Close() | ||
| } | ||
|
|
||
| // Test the interruption in "the rest" loop | ||
| { | ||
| lastRoundRemote := 10 | ||
| lastRoundLocal := 7 | ||
| roundWithSwitchOn := 5 | ||
| local, remote := helperTestOnSwitchToUnSupportedProtocol(t, lastRoundRemote, lastRoundLocal, roundWithSwitchOn, 0) | ||
| for r := 1; r <= lastRoundLocal; r++ { | ||
| blk, err := local.Block(basics.Round(r)) | ||
| require.NoError(t, err) | ||
| require.Equal(t, r, int(blk.Round())) | ||
| } | ||
| require.Equal(t, lastRoundLocal, int(local.LastRound())) | ||
| require.Equal(t, lastRoundRemote, int(remote.LastRound())) | ||
| remote.Ledger.Close() | ||
| } | ||
|
|
||
| // Test the interruption with short notice (less than | ||
| // SeedLookback or the number of parallel fetches which in the | ||
| // test is the same: 2) | ||
|
|
||
| // This can not happen in practice, because there will be | ||
| // enough rounds for the protocol upgrade notice. | ||
| { | ||
| lastRoundRemote := 14 | ||
| lastRoundLocal := 7 | ||
| roundWithSwitchOn := 7 | ||
| local, remote := helperTestOnSwitchToUnSupportedProtocol(t, lastRoundRemote, lastRoundLocal, roundWithSwitchOn, 0) | ||
| for r := 1; r <= lastRoundLocal; r = r + 1 { | ||
| blk, err := local.Block(basics.Round(r)) | ||
| require.NoError(t, err) | ||
| require.Equal(t, r, int(blk.Round())) | ||
| } | ||
| // Since round with switch on (7) can be fetched | ||
| // Simultaneously with round 8, round 8 might also be | ||
| // fetched. | ||
| require.Less(t, int(local.LastRound()), lastRoundLocal+2) | ||
| require.Equal(t, lastRoundRemote, int(remote.LastRound())) | ||
| remote.Ledger.Close() | ||
| } | ||
|
|
||
| // Test the interruption with short notice (less than | ||
| // SeedLookback or the number of parallel fetches which in the | ||
| // test is the same: 2) | ||
|
|
||
| // This case is a variation of the previous case. This may | ||
| // happen when the catchup service restart at the round when | ||
| // an upgrade happens. | ||
| { | ||
| lastRoundRemote := 14 | ||
| lastRoundLocal := 7 | ||
| roundWithSwitchOn := 7 | ||
| roundsAlreadyInLocal := 8 // round 0 -> 7 | ||
|
|
||
| local, remote := helperTestOnSwitchToUnSupportedProtocol( | ||
| t, | ||
| lastRoundRemote, | ||
| lastRoundLocal, | ||
| roundWithSwitchOn, | ||
| roundsAlreadyInLocal) | ||
|
|
||
| for r := 1; r <= lastRoundLocal; r = r + 1 { | ||
| blk, err := local.Block(basics.Round(r)) | ||
| require.NoError(t, err) | ||
| require.Equal(t, r, int(blk.Round())) | ||
| } | ||
| // Since round with switch on (7) is already in the | ||
| // ledger, round 8 will not be fetched. | ||
| require.Equal(t, int(local.LastRound()), lastRoundLocal) | ||
| require.Equal(t, lastRoundRemote, int(remote.LastRound())) | ||
| remote.Ledger.Close() | ||
| // Test the interruption in the initial loop | ||
| // This cannot happen in practice, but is used to test the code. | ||
| func TestOnSwitchToUnSupportedProtocol1(t *testing.T) { | ||
|
|
||
| lastRoundRemote := 5 | ||
| lastRoundLocal := 0 | ||
| roundWithSwitchOn := 0 | ||
| local, remote := helperTestOnSwitchToUnSupportedProtocol(t, lastRoundRemote, lastRoundLocal, roundWithSwitchOn, 0) | ||
|
|
||
| // Last supported round is 0, but is guaranteed | ||
| // to stop after 2 rounds. | ||
|
|
||
| // SeedLookback is 2, which allows two parallel fetches. | ||
| // i.e. rounds 1 and 2 may be simultaneously fetched. | ||
| require.Less(t, int(local.LastRound()), 3) | ||
| require.Equal(t, lastRoundRemote, int(remote.LastRound())) | ||
| remote.Ledger.Close() | ||
| } | ||
|
|
||
| // Test the interruption in "the rest" loop | ||
| func TestOnSwitchToUnSupportedProtocol2(t *testing.T) { | ||
|
|
||
| lastRoundRemote := 10 | ||
| lastRoundLocal := 7 | ||
| roundWithSwitchOn := 5 | ||
| local, remote := helperTestOnSwitchToUnSupportedProtocol(t, lastRoundRemote, lastRoundLocal, roundWithSwitchOn, 0) | ||
| for r := 1; r <= lastRoundLocal; r++ { | ||
| blk, err := local.Block(basics.Round(r)) | ||
| require.NoError(t, err) | ||
| require.Equal(t, r, int(blk.Round())) | ||
| } | ||
| require.Equal(t, lastRoundLocal, int(local.LastRound())) | ||
| require.Equal(t, lastRoundRemote, int(remote.LastRound())) | ||
| remote.Ledger.Close() | ||
| } | ||
|
|
||
| // Test the interruption with short notice (less than | ||
| // SeedLookback or the number of parallel fetches which in the | ||
| // test is the same: 2) | ||
| // This can not happen in practice, because there will be | ||
| // enough rounds for the protocol upgrade notice. | ||
| func TestOnSwitchToUnSupportedProtocol3(t *testing.T) { | ||
|
|
||
| lastRoundRemote := 14 | ||
| lastRoundLocal := 7 | ||
| roundWithSwitchOn := 7 | ||
| local, remote := helperTestOnSwitchToUnSupportedProtocol(t, lastRoundRemote, lastRoundLocal, roundWithSwitchOn, 0) | ||
| for r := 1; r <= lastRoundLocal; r = r + 1 { | ||
| blk, err := local.Block(basics.Round(r)) | ||
| require.NoError(t, err) | ||
| require.Equal(t, r, int(blk.Round())) | ||
| } | ||
| // Since round with switch on (7) can be fetched | ||
| // Simultaneously with round 8, round 8 might also be | ||
| // fetched. | ||
| require.Less(t, int(local.LastRound()), lastRoundLocal+2) | ||
| require.Equal(t, lastRoundRemote, int(remote.LastRound())) | ||
| remote.Ledger.Close() | ||
| } | ||
|
|
||
| // Test the interruption with short notice (less than | ||
| // SeedLookback or the number of parallel fetches which in the | ||
| // test is the same: 2) | ||
| // This case is a variation of the previous case. This may | ||
| // happen when the catchup service restart at the round when | ||
| // an upgrade happens. | ||
| func TestOnSwitchToUnSupportedProtocol4(t *testing.T) { | ||
|
|
||
| lastRoundRemote := 14 | ||
| lastRoundLocal := 7 | ||
| roundWithSwitchOn := 7 | ||
| roundsAlreadyInLocal := 8 // round 0 -> 7 | ||
|
|
||
| local, remote := helperTestOnSwitchToUnSupportedProtocol( | ||
| t, | ||
| lastRoundRemote, | ||
| lastRoundLocal, | ||
| roundWithSwitchOn, | ||
| roundsAlreadyInLocal) | ||
|
|
||
| for r := 1; r <= lastRoundLocal; r = r + 1 { | ||
| blk, err := local.Block(basics.Round(r)) | ||
| require.NoError(t, err) | ||
| require.Equal(t, r, int(blk.Round())) | ||
| } | ||
| // Since round with switch on (7) is already in the | ||
| // ledger, round 8 will not be fetched. | ||
| require.Equal(t, int(local.LastRound()), lastRoundLocal) | ||
| require.Equal(t, lastRoundRemote, int(remote.LastRound())) | ||
| remote.Ledger.Close() | ||
| } | ||
|
|
||
| func helperTestOnSwitchToUnSupportedProtocol( | ||
|
|
@@ -535,14 +533,16 @@ func helperTestOnSwitchToUnSupportedProtocol( | |
| config := defaultConfig | ||
| config.CatchupParallelBlocks = 2 | ||
|
|
||
| remote, _, blk, err := buildTestLedger(t, bookkeeping.Block{}) //mRemote.blocks[0]) | ||
| block1 := mRemote.blocks[1] | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like this the previous way because in this way it could erroneously use block1 or mRemote.blocks[1] after buildTestLedger, but it's pass by value not pass by reference. I want to avoid trying to use the unmodified blank block and thinking we're getting something else.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you mean by?
mRemote.blocks[1] will have the NextProtocolSwitchOn set according to the parameters passed to NextProtocolSwitchOn. That is why it is important to pick mRemote.blocks[1] instead of bookkeeping.Block{}.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Your other comment said no change in behavior, just reorg, but this line is a change in behavior of what
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh I see. sorry for the confusion I caused with that comment. |
||
| remote, _, blk, err := buildTestLedger(t, block1) | ||
| if err != nil { | ||
| t.Fatal(err) | ||
| return local, remote | ||
| } | ||
| for i := 1; i < lastRoundRemote; i++ { | ||
| blk.NextProtocolSwitchOn = mRemote.blocks[i].NextProtocolSwitchOn | ||
| blk.NextProtocol = mRemote.blocks[i].NextProtocol | ||
| blk.NextProtocolSwitchOn = mRemote.blocks[i+1].NextProtocolSwitchOn | ||
| blk.NextProtocol = mRemote.blocks[i+1].NextProtocol | ||
| // Adds blk.BlockHeader.Round + 1 | ||
| addBlocks(t, remote, blk, 1) | ||
| blk.BlockHeader.Round++ | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -1174,7 +1174,15 @@ func eval(ctx context.Context, l ledgerForEvaluator, blk bookkeeping.Block, vali | |||||
| return ledgercore.StateDelta{}, err | ||||||
| } | ||||||
|
|
||||||
| paysetgroupsCh := loadAccounts(ctx, l, blk.Round()-1, paysetgroups, blk.BlockHeader.FeeSink, blk.ConsensusProtocol()) | ||||||
| accountLoadingCtx, accountLoadingCancel := context.WithCancel(ctx) | ||||||
| paysetgroupsCh := loadAccounts(accountLoadingCtx, l, blk.Round()-1, paysetgroups, blk.BlockHeader.FeeSink, blk.ConsensusProtocol()) | ||||||
| // ensure that before we exit from this method, the account loading is no longer active. | ||||||
| defer func() { | ||||||
| accountLoadingCancel() | ||||||
| // wait for the paysetgroupsCh to get closed. | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will this stop waiting if the channel is emptied? I think it has to get closed.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The channel being closed is an indication that the go-routine is done.. removing the accounts from the channel is not really interesting here, but rather a way to detect that the channel got closed ( which ensures that no database actions would be taken place ).
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're right, "and/or" was wrong. I thought it was interesting to mention that if there were unprocessed accounts (i.e. if there was an error) they would be released. |
||||||
| for range paysetgroupsCh { | ||||||
| } | ||||||
| }() | ||||||
|
|
||||||
| var txvalidator evalTxValidator | ||||||
| if validate { | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No changes in TestOnSwitchToUnSupportedProtocol except for dividing it into TestOnSwitchToUnSupportedProtocol1, TestOnSwitchToUnSupportedProtocol2, TestOnSwitchToUnSupportedProtocol3 and TestOnSwitchToUnSupportedProtocol4.