Skip to content

Commit

Permalink
Fixing a bug in eval and TestOnSwitchToUnSupportedProtocol (#2220)
Browse files Browse the repository at this point in the history
estOnSwitchToUnSupportedProtocol had multiple segments. This test is separated into multiple tests.

This PR fixes two issues:

Fix for a bug in eval: in the event of an error and early termination of the eval, the loading of accounts in a separate go routine was not terminated. loadAccounts will be terminated when eval returns.
TestOnSwitchToUnSupportedProtocol1 had a bug in setting the blocks for protocol switch. The first block was not getting the NextProtocolSwitchOn set to 1. Despite the bug, the test was passing most of the time, and failing some of the time.
TestOnSwitchToUnSupportedProtocol3 had a bug in setting the blocks for protocol switch. AddBlocks starts adding from the next round of the passed block. NextProtocolSwitchOn was getting set one round late.
  • Loading branch information
algonautshant authored Jun 3, 2021
1 parent 3a4a37f commit 7e2f656
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 95 deletions.
188 changes: 94 additions & 94 deletions catchup/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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]
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++
}
Expand Down
10 changes: 9 additions & 1 deletion ledger/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
for range paysetgroupsCh {
}
}()

var txvalidator evalTxValidator
if validate {
Expand Down

0 comments on commit 7e2f656

Please sign in to comment.