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

feat(dot/parachain/backing): Import statement into statement table #3966

Merged
Merged
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
13a7ed2
implement a func to get attested candidate
axaysagathiya May 4, 2024
6e3460c
unit tests
axaysagathiya May 8, 2024
471605d
Merge branch 'feat/parachain'
axaysagathiya May 15, 2024
276b6e0
remove scale tags and unexport struct
axaysagathiya May 15, 2024
d2855d7
use slices.SortFunc to sort validity attestations
axaysagathiya May 15, 2024
f8f9f6d
implement import statement
axaysagathiya May 21, 2024
9bfdfc6
change interface method argument
axaysagathiya May 21, 2024
aae30b4
add nil check in availabilty store test
edwardmack May 21, 2024
c5b1422
implement isMemberOf method of table context
axaysagathiya May 21, 2024
769fa5e
newTable func + lint
axaysagathiya May 21, 2024
c85c3a3
assign process functions before sending request message to avoid empt…
edwardmack May 21, 2024
125f81a
improve import candidate method
axaysagathiya May 21, 2024
19d2f4d
address reviews
axaysagathiya May 22, 2024
7778110
Merge branch 'axay/feat/backing/statement-table/attested-candidate' o…
axaysagathiya May 22, 2024
f7c3361
Merge branch 'axay/feat/backing/statement-table/attested-candidate' i…
axaysagathiya May 22, 2024
b085602
improve
axaysagathiya May 22, 2024
d565b67
unit test(WIP)
axaysagathiya May 22, 2024
ad766c3
unit test for import statement method
axaysagathiya May 23, 2024
fae1814
unit test importCandidate (WIP)
axaysagathiya May 24, 2024
3062620
unit tests
axaysagathiya May 29, 2024
e640b3e
Merge branch 'feat/parachain' into axay/feat/backing/statement-table/…
axaysagathiya May 29, 2024
289ae56
Merge branch 'feat/parachain' into axay/feat/backing/statement-table/…
axaysagathiya May 29, 2024
ad9d533
address reviews
axaysagathiya Jun 3, 2024
d0c6a98
Merge branch 'axay/feat/backing/statement-table/import-statement' of …
axaysagathiya Jun 3, 2024
19b1ec3
improve
axaysagathiya Jun 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
implement a func to get attested candidate
axaysagathiya committed May 4, 2024
commit 13a7ed279713696605230a6dbf773b04d8cd53fb
11 changes: 11 additions & 0 deletions dot/parachain/backing/candidate_backing_test.go
Original file line number Diff line number Diff line change
@@ -448,6 +448,7 @@ func rpStateWhenPpmDisabled(t *testing.T) perRelayParentState {
mockTable.EXPECT().attestedCandidate(
gomock.AssignableToTypeOf(parachaintypes.CandidateHash{}),
gomock.AssignableToTypeOf(new(TableContext)),
gomock.AssignableToTypeOf(uint32(0)),
).Return(&attestedToReturn, nil)

return perRelayParentState{
@@ -498,6 +499,7 @@ func TestPostImportStatement(t *testing.T) {
mockTable.EXPECT().attestedCandidate(
gomock.AssignableToTypeOf(parachaintypes.CandidateHash{}),
gomock.AssignableToTypeOf(new(TableContext)),
gomock.AssignableToTypeOf(uint32(0)),
).Return(nil, errors.New("could not get attested candidate from table"))

return perRelayParentState{
@@ -523,6 +525,7 @@ func TestPostImportStatement(t *testing.T) {
mockTable.EXPECT().attestedCandidate(
gomock.AssignableToTypeOf(parachaintypes.CandidateHash{}),
gomock.AssignableToTypeOf(new(TableContext)),
gomock.AssignableToTypeOf(uint32(0)),
).Return(&AttestedCandidate{
GroupID: 4,
Candidate: candidate,
@@ -548,6 +551,7 @@ func TestPostImportStatement(t *testing.T) {
mockTable.EXPECT().attestedCandidate(
gomock.AssignableToTypeOf(parachaintypes.CandidateHash{}),
gomock.AssignableToTypeOf(new(TableContext)),
gomock.AssignableToTypeOf(uint32(0)),
).Return(&AttestedCandidate{
GroupID: 3,
Candidate: getDummyCommittedCandidateReceipt(t),
@@ -942,6 +946,7 @@ func TestHandleStatementMessage(t *testing.T) {
mockTable.EXPECT().attestedCandidate(
gomock.AssignableToTypeOf(parachaintypes.CandidateHash{}),
gomock.AssignableToTypeOf(new(TableContext)),
gomock.AssignableToTypeOf(uint32(0)),
).Return(nil, errors.New("could not get attested candidate from table"))

return map[common.Hash]*perRelayParentState{
@@ -977,6 +982,7 @@ func TestHandleStatementMessage(t *testing.T) {
mockTable.EXPECT().attestedCandidate(
gomock.AssignableToTypeOf(parachaintypes.CandidateHash{}),
gomock.AssignableToTypeOf(new(TableContext)),
gomock.AssignableToTypeOf(uint32(0)),
).Return(new(AttestedCandidate), nil)

return map[common.Hash]*perRelayParentState{
@@ -1014,6 +1020,7 @@ func TestHandleStatementMessage(t *testing.T) {
mockTable.EXPECT().attestedCandidate(
gomock.AssignableToTypeOf(parachaintypes.CandidateHash{}),
gomock.AssignableToTypeOf(new(TableContext)),
gomock.AssignableToTypeOf(uint32(0)),
).Return(new(AttestedCandidate), nil)

return map[common.Hash]*perRelayParentState{
@@ -1054,6 +1061,7 @@ func TestHandleStatementMessage(t *testing.T) {
mockTable.EXPECT().attestedCandidate(
gomock.AssignableToTypeOf(parachaintypes.CandidateHash{}),
gomock.AssignableToTypeOf(new(TableContext)),
gomock.AssignableToTypeOf(uint32(0)),
).Return(new(AttestedCandidate), nil)

return map[common.Hash]*perRelayParentState{
@@ -1097,6 +1105,7 @@ func TestHandleStatementMessage(t *testing.T) {
mockTable.EXPECT().attestedCandidate(
gomock.AssignableToTypeOf(parachaintypes.CandidateHash{}),
gomock.AssignableToTypeOf(new(TableContext)),
gomock.AssignableToTypeOf(uint32(0)),
).Return(new(AttestedCandidate), nil)

return map[common.Hash]*perRelayParentState{
@@ -1147,6 +1156,7 @@ func TestHandleStatementMessage(t *testing.T) {
mockTable.EXPECT().attestedCandidate(
gomock.AssignableToTypeOf(parachaintypes.CandidateHash{}),
gomock.AssignableToTypeOf(new(TableContext)),
gomock.AssignableToTypeOf(uint32(0)),
).Return(new(AttestedCandidate), nil)
mockTable.EXPECT().getCandidate(
gomock.AssignableToTypeOf(parachaintypes.CandidateHash{}),
@@ -1190,6 +1200,7 @@ func TestHandleStatementMessage(t *testing.T) {
mockTable.EXPECT().attestedCandidate(
gomock.AssignableToTypeOf(parachaintypes.CandidateHash{}),
gomock.AssignableToTypeOf(new(TableContext)),
gomock.AssignableToTypeOf(uint32(0)),
).Return(new(AttestedCandidate), nil)
mockTable.EXPECT().getCandidate(
gomock.AssignableToTypeOf(parachaintypes.CandidateHash{}),
3 changes: 2 additions & 1 deletion dot/parachain/backing/get_backed_candidates.go
Original file line number Diff line number Diff line change
@@ -22,7 +22,8 @@ func (cb *CandidateBacking) handleGetBackedCandidatesMessage(requestedCandidates
continue
}

attested, err := rpState.table.attestedCandidate(candidate.CandidateHash, &rpState.tableContext)
attested, err := rpState.table.attestedCandidate(
candidate.CandidateHash, &rpState.tableContext, rpState.minBackingVotes)
if err != nil {
logger.Debugf("getting attested candidate: %w", err)
continue
3 changes: 3 additions & 0 deletions dot/parachain/backing/get_backed_candidates_test.go
Original file line number Diff line number Diff line change
@@ -42,6 +42,7 @@ func TestHandleGetBackedCandidatesMessage(t *testing.T) {
mockTable.EXPECT().attestedCandidate(
gomock.AssignableToTypeOf(parachaintypes.CandidateHash{}),
gomock.AssignableToTypeOf(new(TableContext)),
gomock.AssignableToTypeOf(uint32(0)),
).Return(nil, errors.New("could not get attested candidate from table"))

return map[common.Hash]*perRelayParentState{
@@ -60,6 +61,7 @@ func TestHandleGetBackedCandidatesMessage(t *testing.T) {
mockTable.EXPECT().attestedCandidate(
gomock.AssignableToTypeOf(parachaintypes.CandidateHash{}),
gomock.AssignableToTypeOf(new(TableContext)),
gomock.AssignableToTypeOf(uint32(0)),
).Return(nil, nil)

return map[common.Hash]*perRelayParentState{
@@ -78,6 +80,7 @@ func TestHandleGetBackedCandidatesMessage(t *testing.T) {
mockTable.EXPECT().attestedCandidate(
gomock.AssignableToTypeOf(parachaintypes.CandidateHash{}),
gomock.AssignableToTypeOf(new(TableContext)),
gomock.AssignableToTypeOf(uint32(0)),
).Return(new(AttestedCandidate), nil)

return map[common.Hash]*perRelayParentState{
8 changes: 4 additions & 4 deletions dot/parachain/backing/mocks_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dot/parachain/backing/per_relay_parent_state.go
Original file line number Diff line number Diff line change
@@ -120,7 +120,7 @@ func (rpState *perRelayParentState) postImportStatement(subSystemToOverseer chan
return
}

attested, err := rpState.table.attestedCandidate(summary.Candidate, &rpState.tableContext)
attested, err := rpState.table.attestedCandidate(summary.Candidate, &rpState.tableContext, rpState.minBackingVotes)
if err != nil {
logger.Error(err.Error())
}
81 changes: 76 additions & 5 deletions dot/parachain/backing/statement_table.go
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@ package backing
import (
"errors"
"fmt"
"math"

parachaintypes "github.com/ChainSafe/gossamer/dot/parachain/types"
)
@@ -35,9 +36,54 @@ type candidateData struct { //nolint:unused
validityVotes map[parachaintypes.ValidatorIndex]validityVoteWithSign
}

// attested yields a full attestation for a candidate.
// If the candidate can be included, it will return attested candidate.
func (data candidateData) attested(validityThreshold uint) (*AttestedCandidate, error) { //nolint:unused
numOfValidityVotes := uint(len(data.validityVotes))
if numOfValidityVotes < validityThreshold {
return nil, fmt.Errorf("not enough validity votes: %d < %d", numOfValidityVotes, validityThreshold)
}

validityAttestations := make([]validityAttestation, numOfValidityVotes)
for validatorIndex, voteWithSign := range data.validityVotes {
switch voteWithSign.validityVote {
case valid:
attestation := parachaintypes.NewValidityAttestation()
err := attestation.Set(parachaintypes.Explicit(voteWithSign.signature))
if err != nil {
return nil, fmt.Errorf("failed to set validity attestation: %w", err)
}

validityAttestations = append(validityAttestations, validityAttestation{
ValidatorIndex: validatorIndex,
ValidityAttestation: attestation,
})
case issued:
attestation := parachaintypes.NewValidityAttestation()
err := attestation.Set(parachaintypes.Implicit(voteWithSign.signature))
if err != nil {
return nil, fmt.Errorf("failed to set validity attestation: %w", err)
}

validityAttestations = append(validityAttestations, validityAttestation{
ValidatorIndex: validatorIndex,
ValidityAttestation: attestation,
})
default:
return nil, fmt.Errorf("unknown validity vote: %d", voteWithSign.validityVote)
}
}

return &AttestedCandidate{
GroupID: data.groupID,
Candidate: data.candidate,
ValidityAttestations: validityAttestations,
}, nil
}

type validityVoteWithSign struct { //nolint:unused
validityVote validityVote
signature parachaintypes.Signature
signature parachaintypes.ValidatorSignature
}

type validityVote byte //nolint:unused
@@ -67,10 +113,35 @@ func (statementTable) importStatement( //nolint:unused
return nil, nil
}

func (statementTable) attestedCandidate(candidateHash parachaintypes.CandidateHash, ctx *TableContext, //nolint:unused
// attestedCandidate retrieves the attested candidate for the given candidate hash.
// returns attested candidate if the candidate exists and is includable.
func (table statementTable) attestedCandidate( //nolint:unused
candidateHash parachaintypes.CandidateHash, tableContext *TableContext, minimumBackingVotes uint32,
) (*AttestedCandidate, error) {
// TODO: Implement this method
return nil, nil
// size of the backing group.
var groupLen uint

data, ok := table.candidateVotes[candidateHash]
if !ok {
return nil, fmt.Errorf("%w for candidate-hash: %s", errCandidateDataNotFound, candidateHash)
}

group, ok := tableContext.groups[data.groupID]
if ok {
groupLen = uint(len(group))
} else {
groupLen = math.MaxUint
}

validityThreshold := effectiveMinimumBackingVotes(groupLen, minimumBackingVotes)
return data.attested(validityThreshold)
}

// effectiveMinimumBackingVotes adjusts the configured needed backing votes with the size of the backing group.
//
// groupLen is the size of the backing group.
func effectiveMinimumBackingVotes(groupLen uint, configuredMinimumBackingVotes uint32) uint { //nolint:unused
return min(groupLen, uint(configuredMinimumBackingVotes))
}

func (statementTable) drainMisbehaviors() []parachaintypes.ProvisionableDataMisbehaviorReport { //nolint:unused
@@ -81,7 +152,7 @@ func (statementTable) drainMisbehaviors() []parachaintypes.ProvisionableDataMisb
type Table interface {
getCandidate(parachaintypes.CandidateHash) (parachaintypes.CommittedCandidateReceipt, error)
importStatement(*TableContext, parachaintypes.SignedFullStatementWithPVD) (*Summary, error)
attestedCandidate(parachaintypes.CandidateHash, *TableContext) (*AttestedCandidate, error)
attestedCandidate(parachaintypes.CandidateHash, *TableContext, uint32) (*AttestedCandidate, error)
drainMisbehaviors() []parachaintypes.ProvisionableDataMisbehaviorReport
}