Skip to content

Commit

Permalink
test(dot/parachain/backing): ensure new lead view doesn't clobber the…
Browse files Browse the repository at this point in the history
… old view (#4148)
  • Loading branch information
axaysagathiya authored Aug 29, 2024
1 parent baea974 commit cd5a2bf
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 0 deletions.
124 changes: 124 additions & 0 deletions dot/parachain/backing/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -910,3 +910,127 @@ func TestCanNotSecondMultipleCandidatesPerRelayParent(t *testing.T) {

time.Sleep(1 * time.Second)
}

// The new leaf view doesn't clobber the old view when we update active leaves.
func TestNewLeafDoesNotClobberOld(t *testing.T) {
candidateBacking, overseer := initBackingAndOverseerMock(t)
defer stopOverseerAndWaitForCompletion(overseer)

paraValidators := parachainValidators(t, candidateBacking.Keystore)
numOfValidators := uint(len(paraValidators))
relayParent1 := getDummyHash(t, 5)
relayParent2 := getDummyHash(t, 6)
paraID := uint32(1)
validationCode := parachaintypes.ValidationCode{1, 2, 3}

ctrl := gomock.NewController(t)
mockBlockState := backing.NewMockBlockState(ctrl)
mockRuntime := backing.NewMockInstance(ctrl)
mockImplicitView := backing.NewMockImplicitView(ctrl)

candidateBacking.BlockState = mockBlockState
candidateBacking.ImplicitView = mockImplicitView

// mock BlockState methods
mockBlockState.EXPECT().GetRuntime(gomock.AssignableToTypeOf(common.Hash{})).
Return(mockRuntime, nil).Times(5)

// mock Runtime Instance methods
mockRuntime.EXPECT().ParachainHostAsyncBackingParams().
Return(nil, wazero_runtime.ErrExportFunctionNotFound).Times(2)
mockRuntime.EXPECT().ParachainHostSessionIndexForChild().
Return(parachaintypes.SessionIndex(1), nil).Times(3)
mockRuntime.EXPECT().ParachainHostValidators().
Return(paraValidators, nil).Times(2)
mockRuntime.EXPECT().ParachainHostValidatorGroups().
Return(validatorGroups(t), nil).Times(2)
mockRuntime.EXPECT().ParachainHostAvailabilityCores().
Return(availabilityCores(t), nil).Times(2)
mockRuntime.EXPECT().ParachainHostMinimumBackingVotes().
Return(backing.LEGACY_MIN_BACKING_VOTES, nil).Times(2)
mockRuntime.EXPECT().ParachainHostValidationCodeByHash(gomock.AssignableToTypeOf(common.Hash{})).
Return(&validationCode, nil)
mockRuntime.EXPECT().
ParachainHostSessionExecutorParams(gomock.AssignableToTypeOf(parachaintypes.SessionIndex(0))).
Return(nil, wazero_runtime.ErrExportFunctionNotFound).Times(1)

//mock ImplicitView
mockImplicitView.EXPECT().AllAllowedRelayParents().
Return([]common.Hash{}).Times(2)

// add relay parent 1 to active leaves
overseer.ReceiveMessage(parachaintypes.ActiveLeavesUpdateSignal{
Activated: &parachaintypes.ActivatedLeaf{Hash: relayParent1, Number: 1},
})
time.Sleep(500 * time.Millisecond)

// add relay parent 2 to active leaves that does not clobber relay parent 1
// and still allows seconding of candidates for relay parent 1
overseer.ReceiveMessage(parachaintypes.ActiveLeavesUpdateSignal{
Activated: &parachaintypes.ActivatedLeaf{Hash: relayParent2, Number: 1},
})
time.Sleep(500 * time.Millisecond)

headData := parachaintypes.HeadData{Data: []byte{4, 5, 6}}

pov := parachaintypes.PoV{BlockData: []byte{1, 2, 3}}
povHash, err := pov.Hash()
require.NoError(t, err)

pvd := dummyPVD(t)
pvdHash, err := pvd.Hash()
require.NoError(t, err)

// candidate with relay parent 1
candidate := newCommittedCandidate(t,
paraID,
headData,
povHash,
relayParent1,
makeErasureRoot(t, numOfValidators, pov, pvd),
pvdHash,
validationCode,
)

validate := validResponseForValidateFromExhaustive(headData, pvd)

distribute := func(msg any) bool {
// we have seconded a candidate and shared the statement to peers
share, ok := msg.(parachaintypes.StatementDistributionMessageShare)
if !ok {
return false
}

statement, err := share.SignedFullStatementWithPVD.SignedFullStatement.Payload.Value()
require.NoError(t, err)

require.Equal(t, statement, parachaintypes.Seconded(candidate))
require.Equal(t, *share.SignedFullStatementWithPVD.PersistedValidationData, pvd)
require.Equal(t, share.RelayParent, relayParent1)

return true
}

informSeconded := func(msg any) bool {
// informed collator protocol that we have seconded the candidate
_, ok := msg.(collatorprotocolmessages.Seconded)
return ok
}

// If the old leaf view is clobbered, the candidate will be ignored and in that case,
// overseer does not expect `StatementDistributionMessageShare` and `collatorprotocolmessages.Seconded`
// overseer messages. So, test will fail.
//
// But, when the old leaf view is not clobbered, the candidate will be seconded.
// so, oversee expects all four overseer messages.
overseer.ExpectActions(validate, storeAvailableData, distribute, informSeconded)

overseer.ReceiveMessage(backing.SecondMessage{
RelayParent: relayParent1,
CandidateReceipt: candidate.ToPlain(),
PersistedValidationData: pvd,
PoV: pov,
})

time.Sleep(1 * time.Second)
}
4 changes: 4 additions & 0 deletions dot/parachain/overseer/mockable_overseer.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ func (m *MockableOverseer) processMessages() {
return
}
case <-m.ctx.Done():
if actionIndex < len(m.actionsForExpectedMessages) {
m.t.Errorf("expected %d overseer actions, but got only %d", len(m.actionsForExpectedMessages), actionIndex)
}

if err := m.ctx.Err(); err != nil {
m.t.Logf("ctx error: %v\n", err)
}
Expand Down

0 comments on commit cd5a2bf

Please sign in to comment.