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

[WIP] feat/parachain: disputes coordinator #3347

Closed
wants to merge 42 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
1f1367e
add queue
kanishkatn Jun 13, 2023
8847198
use rwmutex
kanishkatn Jul 5, 2023
3e99781
add tests
kanishkatn Aug 21, 2023
6ea2c83
add backend
kanishkatn Jun 19, 2023
94e6d14
resolve rebase issues
kanishkatn Aug 2, 2023
90b3cf0
cleanup
kanishkatn Aug 18, 2023
f1811e1
cleanup
kanishkatn Aug 23, 2023
115463a
add imports
kanishkatn Jun 21, 2023
466a526
resolve rebase issues
kanishkatn Aug 2, 2023
c4820ea
fix rebase issues
kanishkatn Sep 18, 2023
c253c9d
add queue
kanishkatn Jun 13, 2023
5bf6f08
add tests
kanishkatn Aug 21, 2023
f0e3d0a
add backend
kanishkatn Jun 19, 2023
ddcee28
resolve rebase issues
kanishkatn Aug 2, 2023
018af5f
cleanup
kanishkatn Aug 18, 2023
9b5ec4a
cleanup
kanishkatn Aug 23, 2023
b36b7e4
add lru cache
kanishkatn Jul 31, 2023
04b61b1
add candidates
kanishkatn Jul 31, 2023
d07ad8d
add scrapper
kanishkatn Aug 1, 2023
8e4b832
use lrucache from lib
kanishkatn Aug 4, 2023
dca5889
init scraper
kanishkatn Aug 10, 2023
0ccd628
replace google btree
kanishkatn Aug 11, 2023
64e8cb1
resolve rebase issues
kanishkatn Aug 23, 2023
42db003
handle todos
kanishkatn Aug 28, 2023
78a3a63
add tests
kanishkatn Aug 29, 2023
ec48cc9
cleanup
kanishkatn Sep 14, 2023
f1b2e72
add queue
kanishkatn Jun 13, 2023
f3f5794
add backend
kanishkatn Jun 19, 2023
203333b
resolve rebase issues
kanishkatn Aug 2, 2023
ce83314
add lru cache
kanishkatn Jul 31, 2023
d316c18
use lrucache from lib
kanishkatn Aug 4, 2023
b558f8d
add spam slots
kanishkatn Jun 21, 2023
968d248
make thread safe, add tests
kanishkatn Jun 27, 2023
8e7aeb5
add benchmark
kanishkatn Jun 28, 2023
af73bb3
review suggestions
kanishkatn Jul 3, 2023
ae41f35
lint
kanishkatn Jul 5, 2023
137ede1
lint, review suggestions
kanishkatn Jul 5, 2023
9e7b234
add disputes coordinator
kanishkatn Jun 20, 2023
b4c444f
resolve rebase issues
kanishkatn Sep 19, 2023
b97f834
process onchain votes
kanishkatn Sep 28, 2023
84845cc
handle incoming
kanishkatn Sep 28, 2023
c327608
finish processors
kanishkatn Oct 5, 2023
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
2 changes: 1 addition & 1 deletion dot/parachain/available_data_fetching.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
// AvailableDataFetchingRequest represents a request to retrieve all available data for a specific candidate.
type AvailableDataFetchingRequest struct {
// Hash of the candidate for which the available data is requested.
CandidateHash CandidateHash
CandidateHash parachaintypes.CandidateHash
}

// Encode returns the SCALE encoding of the AvailableDataFetchingRequest
Expand Down
2 changes: 1 addition & 1 deletion dot/parachain/available_data_fetching_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (

func TestEncodeAvailableDataFetchingRequest(t *testing.T) {
availableDataFetchingRequest := AvailableDataFetchingRequest{
CandidateHash: CandidateHash{
CandidateHash: parachaintypes.CandidateHash{
common.MustHexToHash("0x677811d2f3ded2489685468dbdb2e4fa280a249fba9356acceb2e823820e2c19"),
},
}
Expand Down
2 changes: 1 addition & 1 deletion dot/parachain/chunk_fetching.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
// ChunkFetchingRequest represents a request to retrieve chunks of a parachain candidate
type ChunkFetchingRequest struct {
// Hash of candidate we want a chunk for.
CandidateHash CandidateHash `scale:"1"`
CandidateHash parachaintypes.CandidateHash `scale:"1"`

// The index of the chunk to fetch.
Index parachaintypes.ValidatorIndex `scale:"2"`
Expand Down
2 changes: 1 addition & 1 deletion dot/parachain/chunk_fetching_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (

func TestEncodeChunkFetchingRequest(t *testing.T) {
chunkFetchingRequest := ChunkFetchingRequest{
CandidateHash: CandidateHash{
CandidateHash: parachaintypes.CandidateHash{
common.MustHexToHash("0x677811d2f3ded2489685468dbdb2e4fa280a249fba9356acceb2e823820e2c19"),
},
Index: parachaintypes.ValidatorIndex(8),
Expand Down
68 changes: 60 additions & 8 deletions dot/parachain/dispute/backend.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package dispute

import (
"fmt"
"sync"
"time"

"github.com/ChainSafe/gossamer/dot/parachain/dispute/types"
parachainTypes "github.com/ChainSafe/gossamer/dot/parachain/types"
"github.com/ChainSafe/gossamer/lib/common"
"github.com/dgraph-io/badger/v4"
"github.com/tidwall/btree"
)

Expand All @@ -32,10 +32,14 @@ type Backend interface {
type OverlayBackend interface {
Backend

// IsEmpty returns true if the overlay backend is empty.
IsEmpty() bool
// WriteToDB writes the given dispute to the database.
WriteToDB() error
// GetActiveDisputes returns the active disputes.
GetActiveDisputes(now int64) (*btree.BTree, error)
GetActiveDisputes(now uint64) (*btree.BTree, error)
// NoteEarliestSession prunes data in the DB based on the provided session index.
NoteEarliestSession(session parachainTypes.SessionIndex) error
}

// DBBackend is the backend for the dispute coordinator module that uses a database.
Expand Down Expand Up @@ -64,7 +68,7 @@ type syncedRecentDisputes struct {

func newSyncedRecentDisputes() syncedRecentDisputes {
return syncedRecentDisputes{
BTree: btree.New(types.DisputeComparator),
BTree: btree.New(types.CompareDisputes),
}
}

Expand Down Expand Up @@ -157,12 +161,12 @@ func (b *overlayBackend) SetCandidateVotes(session parachainTypes.SessionIndex,
const ActiveDuration = 180 * time.Second

// GetActiveDisputes returns the active disputes, if any.
func (b *overlayBackend) GetActiveDisputes(now int64) (*btree.BTree, error) {
func (b *overlayBackend) GetActiveDisputes(now uint64) (*btree.BTree, error) {
b.recentDisputes.RLock()
recentDisputes := b.recentDisputes.Copy()
b.recentDisputes.RUnlock()

activeDisputes := btree.New(types.DisputeComparator)
activeDisputes := btree.New(types.CompareDisputes)
recentDisputes.Ascend(nil, func(i interface{}) bool {
dispute, ok := i.(*types.Dispute)
if !ok {
Expand All @@ -176,7 +180,7 @@ func (b *overlayBackend) GetActiveDisputes(now int64) (*btree.BTree, error) {
return true
}

if concludedAt != nil && *concludedAt+uint64(ActiveDuration.Seconds()) > uint64(now) {
if concludedAt != nil && *concludedAt+uint64(ActiveDuration.Seconds()) > now {
activeDisputes.Set(dispute)
}

Expand All @@ -186,16 +190,64 @@ func (b *overlayBackend) GetActiveDisputes(now int64) (*btree.BTree, error) {
return activeDisputes, nil
}

func (b *overlayBackend) IsEmpty() bool {
return b.earliestSession.SessionIndex == nil && b.recentDisputes.Len() == 0 && len(b.candidateVotes.votes) == 0
}

func (b *overlayBackend) WriteToDB() error {
return b.inner.Write(b.earliestSession.SessionIndex, b.recentDisputes.BTree.Copy(), b.candidateVotes.votes)
}

func (b *overlayBackend) NoteEarliestSession(session parachainTypes.SessionIndex) error {
if b.earliestSession.SessionIndex == nil {
b.earliestSession.SessionIndex = &session
return nil
}

if *b.earliestSession.SessionIndex > session {
b.earliestSession.SessionIndex = &session
// clear recent disputes metadata
recentDisputes, err := b.GetRecentDisputes()
if err != nil {
return fmt.Errorf("get recent disputes: %w", err)
}

// determine new recent disputes
newRecentDisputes := btree.New(types.CompareDisputes)
recentDisputes.Ascend(nil, func(item interface{}) bool {
dispute := item.(*types.Dispute)
if dispute.Comparator.SessionIndex >= session {
newRecentDisputes.Set(dispute)
}
return true
})

// prune obsolete disputes
recentDisputes.Ascend(nil, func(item interface{}) bool {
dispute := item.(*types.Dispute)
if dispute.Comparator.SessionIndex < session {
recentDisputes.Delete(dispute)
}
return true
})

// update db
if recentDisputes.Len() > 0 {
if err = b.SetRecentDisputes(newRecentDisputes); err != nil {
return fmt.Errorf("set recent disputes: %w", err)
}
}
}

return nil
}

var _ OverlayBackend = (*overlayBackend)(nil)

// newOverlayBackend creates a new overlayBackend.
func newOverlayBackend(db *badger.DB) *overlayBackend {
func newOverlayBackend(dbBackend DBBackend) *overlayBackend {
return &overlayBackend{
inner: NewDBBackend(db),
inner: dbBackend,
earliestSession: newSyncedEarliestSession(),
recentDisputes: newSyncedRecentDisputes(),
candidateVotes: newSyncedCandidateVotes(),
Expand Down
23 changes: 14 additions & 9 deletions dot/parachain/dispute/backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ func TestOverlayBackend_EarliestSession(t *testing.T) {
require.NoError(t, err)

// when
backend := newOverlayBackend(db)
dbBackend := NewDBBackend(db)
backend := newOverlayBackend(dbBackend)
err = backend.SetEarliestSession(getSessionIndex(1))
require.NoError(t, err)

Expand All @@ -39,7 +40,7 @@ func TestOverlayBackend_RecentDisputes(t *testing.T) {
// with
db, err := badger.Open(badger.DefaultOptions(t.TempDir()))
require.NoError(t, err)
disputes := btree.New(types.DisputeComparator)
disputes := btree.New(types.CompareDisputes)

dispute1, err := types.DummyDispute(1, common.Hash{1}, types.DisputeStatusActive)
require.NoError(t, err)
Expand All @@ -50,7 +51,8 @@ func TestOverlayBackend_RecentDisputes(t *testing.T) {
disputes.Set(dispute2)

// when
backend := newOverlayBackend(db)
dbBackend := NewDBBackend(db)
backend := newOverlayBackend(dbBackend)
err = backend.SetRecentDisputes(disputes)
require.NoError(t, err)

Expand All @@ -69,7 +71,8 @@ func TestOverlayBackend_CandidateVotes(t *testing.T) {
candidateVotes1 := types.DummyCandidateVotes(t)

// when
backend := newOverlayBackend(db)
dbBackend := NewDBBackend(db)
backend := newOverlayBackend(dbBackend)
err = backend.SetCandidateVotes(1, common.Hash{1}, candidateVotes1)
require.NoError(t, err)

Expand All @@ -85,7 +88,7 @@ func TestOverlayBackend_GetActiveDisputes(t *testing.T) {
// with
db, err := badger.Open(badger.DefaultOptions(t.TempDir()))
require.NoError(t, err)
disputes := btree.New(types.DisputeComparator)
disputes := btree.New(types.CompareDisputes)

dispute1, err := types.DummyDispute(1, common.Hash{1}, types.DisputeStatusActive)
require.NoError(t, err)
Expand All @@ -96,12 +99,13 @@ func TestOverlayBackend_GetActiveDisputes(t *testing.T) {
disputes.Set(dispute2)

// when
backend := newOverlayBackend(db)
dbBackend := NewDBBackend(db)
backend := newOverlayBackend(dbBackend)
err = backend.SetRecentDisputes(disputes)
require.NoError(t, err)

// then
activeDisputes, err := backend.GetActiveDisputes(time.Now().Unix())
activeDisputes, err := backend.GetActiveDisputes(uint64(time.Now().Unix()))
require.NoError(t, err)
require.True(t, compareBTrees(disputes, activeDisputes))
}
Expand All @@ -112,7 +116,8 @@ func TestOverlayBackend_Concurrency(t *testing.T) {
// with
db, err := badger.Open(badger.DefaultOptions(t.TempDir()))
require.NoError(t, err)
backend := newOverlayBackend(db)
dbBackend := NewDBBackend(db)
backend := newOverlayBackend(dbBackend)

numGoroutines := 10
numIterations := 1000
Expand Down Expand Up @@ -155,7 +160,7 @@ func TestOverlayBackend_Concurrency(t *testing.T) {
defer wg.Done()

for j := 0; j < numIterations; j++ {
disputes := btree.New(types.DisputeComparator)
disputes := btree.New(types.CompareDisputes)

dispute1, err := types.DummyDispute(parachainTypes.SessionIndex(j),
common.Hash{byte(j)},
Expand Down
Loading