Skip to content

Commit

Permalink
parachain/disputes: add scraping module for disputes-coordinator (clo…
Browse files Browse the repository at this point in the history
…ne) (#3552)
  • Loading branch information
kanishkatn committed Nov 1, 2023
1 parent fb9f8d8 commit 44982e1
Show file tree
Hide file tree
Showing 25 changed files with 2,072 additions and 51 deletions.
249 changes: 249 additions & 0 deletions dot/parachain/dispute/import.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
package dispute

import (
"fmt"

"github.com/ChainSafe/gossamer/dot/parachain/dispute/types"
parachainTypes "github.com/ChainSafe/gossamer/dot/parachain/types"
"github.com/ChainSafe/gossamer/lib/babe/inherents"
)

// ImportResult is an ongoing statement/vote import
type ImportResult interface {
// VotesChanged returns true if any votes were changed during the import
VotesChanged() bool
// DisputeStateChanged returns true if the dispute state changed during the import
DisputeStateChanged() (bool, error)
// IsFreshlyDisputed returns true if the dispute state changed from undisputed to disputed during the import
IsFreshlyDisputed() bool
// IsFreshlyConfirmed returns true if the dispute state changed to confirmed during the import
IsFreshlyConfirmed() (bool, error)
// IsFreshlyConcludedFor returns true if the dispute state changed to concluded for during the import
IsFreshlyConcludedFor() (bool, error)
// IsFreshlyConcludedAgainst returns true if the dispute state changed to concluded against during the import
IsFreshlyConcludedAgainst() (bool, error)
// IsFreshlyConcluded returns true if the dispute state changed to concluded during the import
IsFreshlyConcluded() (bool, error)
// ImportApprovalVotes imports the given approval votes into the current import
ImportApprovalVotes(approvalVotes []types.Vote, now uint64) (ImportResult, error)
// IntoUpdatedVotes returns the updated votes after the import
IntoUpdatedVotes() types.CandidateVotes
}

// ImportResultHandler implements ImportResult interface
type ImportResultHandler struct {
// oldState the state before the import
oldState types.CandidateVoteState
// newState the state after the importing new statements
newState types.CandidateVoteState
// newInvalidVoters the new invalid voters as of this import
newInvalidVoters []parachainTypes.ValidatorIndex
// importedInvalidVotes number of invalid voters
importedInvalidVotes uint32
// importedValidVotes number of valid voters
importedValidVotes uint32
// importedApprovalVotes number of approval votes imported via ImportApprovalVotes()
importedApprovalVotes uint32
}

func (i ImportResultHandler) VotesChanged() bool {
return i.importedValidVotes != 0 || i.importedInvalidVotes != 0
}

func (i ImportResultHandler) DisputeStateChanged() (bool, error) {
isFreshlyConfirmed, err := i.IsFreshlyConfirmed()
if err != nil {
return false, fmt.Errorf("checking if freshly confirmed: %w", err)
}

isFreshlyConcluded, err := i.IsFreshlyConcluded()
if err != nil {
return false, fmt.Errorf("checking if freshly concluded: %w", err)
}

return i.IsFreshlyDisputed() || isFreshlyConfirmed || isFreshlyConcluded, nil
}

func (i ImportResultHandler) IsFreshlyDisputed() bool {
return !i.oldState.IsDisputed() && i.newState.IsDisputed()
}

func (i ImportResultHandler) IsFreshlyConfirmed() (bool, error) {
isOldStateConfirmed, err := i.oldState.IsConfirmed()
if err != nil {
return false, fmt.Errorf("checking if old state is confirmed: %w", err)
}

isNewStateConfirmed, err := i.newState.IsConfirmed()
if err != nil {
return false, fmt.Errorf("checking if new state is confirmed: %w", err)
}

return !isOldStateConfirmed && isNewStateConfirmed, nil
}

func (i ImportResultHandler) IsFreshlyConcludedFor() (bool, error) {
isOldStateConcludedFor, err := i.oldState.IsConcludedFor()
if err != nil {
return false, fmt.Errorf("checking if old state is concluded for: %w", err)
}

isNewStateConcludedFor, err := i.newState.IsConcludedFor()
if err != nil {
return false, fmt.Errorf("checking if new state is concluded for: %w", err)
}

return !isOldStateConcludedFor && isNewStateConcludedFor, nil
}

func (i ImportResultHandler) IsFreshlyConcludedAgainst() (bool, error) {
isOldStateConcludedAgainst, err := i.oldState.IsConcludedAgainst()
if err != nil {
return false, fmt.Errorf("checking if old state is concluded against: %w", err)
}

isNewStateConcludedAgainst, err := i.newState.IsConcludedAgainst()
if err != nil {
return false, fmt.Errorf("checking if new state is concluded against: %w", err)
}

return !isOldStateConcludedAgainst && isNewStateConcludedAgainst, nil
}

func (i ImportResultHandler) IsFreshlyConcluded() (bool, error) {
isFreshlyConcludedFor, err := i.IsFreshlyConcludedFor()
if err != nil {
return false, fmt.Errorf("checking if freshly concluded for: %w", err)
}

isFreshlyConcludedAgainst, err := i.IsFreshlyConcludedAgainst()
if err != nil {
return false, fmt.Errorf("checking if freshly concluded against: %w", err)
}

return isFreshlyConcludedFor || isFreshlyConcludedAgainst, nil
}

func (i ImportResultHandler) ImportApprovalVotes(approvalVotes []types.Vote, now uint64) (ImportResult, error) {
votes := i.newState.Votes

for _, approvalVote := range approvalVotes {
// TODO: validate signature

if _, ok := votes.Valid[approvalVote.ValidatorIndex]; !ok {
votes.Valid[approvalVote.ValidatorIndex] = approvalVote
i.importedValidVotes++
i.importedApprovalVotes++
}
}

newState, err := types.NewCandidateVoteState(votes, now)
if err != nil {
return nil, fmt.Errorf("creating new candidate vote state: %w", err)
}

if newState == nil {
return nil, fmt.Errorf("new state is nil")
}

return &ImportResultHandler{
oldState: i.oldState,
newState: *newState,
newInvalidVoters: i.newInvalidVoters,
importedInvalidVotes: i.importedInvalidVotes,
importedValidVotes: i.importedValidVotes,
importedApprovalVotes: i.importedApprovalVotes,
}, nil
}

func (i ImportResultHandler) IntoUpdatedVotes() types.CandidateVotes {
if !i.VotesChanged() {
return types.CandidateVotes{}
}

return i.newState.Votes
}

var _ ImportResult = (*ImportResultHandler)(nil)

func NewImportResultFromStatements(env types.CandidateEnvironment,
statements []types.Statement,
candidateVoteState types.CandidateVoteState,
now uint64,
) (*ImportResultHandler, error) {
votes, oldState := candidateVoteState.IntoOldState()

var (
newInvalidVoters []parachainTypes.ValidatorIndex
importedInvalidVotes uint32
importedValidVotes uint32
)
expectedCandidateHash, err := votes.CandidateReceipt.Hash()
if err != nil {
return nil, fmt.Errorf("get candidate receipt hash: %w", err)
}

for _, statement := range statements {
if statement.ValidatorIndex < parachainTypes.ValidatorIndex(len(env.Session.Validators)) {
validator := env.Session.Validators[statement.ValidatorIndex]
if statement.SignedDisputeStatement.ValidatorPublic != validator {
continue
}
}

if statement.SignedDisputeStatement.CandidateHash != expectedCandidateHash {
continue
}

if statement.SignedDisputeStatement.SessionIndex != env.SessionIndex {
continue
}

disputeStatement, err := statement.SignedDisputeStatement.DisputeStatement.Value()
if err != nil {
logger.Warnf("get dispute statement value: %s", err)
continue
}
switch disputeStatement.(type) {
case inherents.ValidDisputeStatementKind:
vote := types.Vote{
ValidatorIndex: statement.ValidatorIndex,
ValidatorSignature: statement.SignedDisputeStatement.ValidatorSignature,
DisputeStatement: statement.SignedDisputeStatement.DisputeStatement,
}
fresh, err := votes.Valid.InsertVote(vote)
if err != nil {
return nil, fmt.Errorf("inserting valid vote: %w", err)
}

if fresh {
importedValidVotes++
}
case inherents.InvalidDisputeStatementKind:
_, ok := votes.Invalid[statement.ValidatorIndex]
if !ok {
votes.Invalid[statement.ValidatorIndex] = types.Vote{
ValidatorIndex: statement.ValidatorIndex,
ValidatorSignature: statement.SignedDisputeStatement.ValidatorSignature,
DisputeStatement: statement.SignedDisputeStatement.DisputeStatement,
}
importedInvalidVotes++
newInvalidVoters = append(newInvalidVoters, statement.ValidatorIndex)
}
}
}

newState, err := types.NewCandidateVoteState(votes, now)
if err != nil {
return nil, fmt.Errorf("creating new candidate vote state: %w", err)
}

return &ImportResultHandler{
oldState: oldState,
newState: *newState,
newInvalidVoters: newInvalidVoters,
importedInvalidVotes: importedInvalidVotes,
importedValidVotes: importedValidVotes,
importedApprovalVotes: 0,
}, nil
}
33 changes: 32 additions & 1 deletion dot/parachain/dispute/mock_runtime_test.go

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

1 change: 0 additions & 1 deletion dot/parachain/dispute/mocks_generate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,4 @@

package dispute

//go:generate mockgen -destination=mocks_test.go -package=$GOPACKAGE . PoVRequestor
//go:generate mockgen -destination=mock_runtime_test.go -package $GOPACKAGE github.com/ChainSafe/gossamer/dot/parachain/runtime RuntimeInstance
20 changes: 20 additions & 0 deletions dot/parachain/dispute/overseer/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,23 @@ type ValidationResult struct {
ValidResult *ValidValidationResult
InvalidResult *InvalidValidationResult
}

type FinalizedBlockNumberResponse struct {
Number uint32
Err error
}

type FinalizedBlockNumberRequest struct {
ResponseChannel chan FinalizedBlockNumberResponse
}

type AncestorsResponse struct {
Ancestors []common.Hash
Error error
}

type AncestorsRequest struct {
Hash common.Hash
K uint32
ResponseChannel chan AncestorsResponse
}
Loading

0 comments on commit 44982e1

Please sign in to comment.