-
Notifications
You must be signed in to change notification settings - Fork 129
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ee86336
commit f5f40ac
Showing
1 changed file
with
143 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
package dispute | ||
|
||
import ( | ||
"fmt" | ||
"github.com/ChainSafe/gossamer/dot/parachain/dispute/types" | ||
"github.com/ChainSafe/gossamer/dot/state" | ||
"github.com/ChainSafe/gossamer/lib/parachain" | ||
"github.com/dgraph-io/badger/v4" | ||
"github.com/google/btree" | ||
"time" | ||
) | ||
|
||
// CoordinatorSubsystem is the dispute coordinator subsystem interface. | ||
type CoordinatorSubsystem interface { | ||
// Run runs the dispute coordinator subsystem. | ||
Run() error | ||
} | ||
|
||
// disputeCoordinator implements the CoordinatorSubsystem interface. | ||
type disputeCoordinator struct { | ||
store *OverlayBackend | ||
blockState state.BlockState | ||
} | ||
|
||
func (d *disputeCoordinator) Run() error { | ||
if err := d.initialize(); err != nil { | ||
return fmt.Errorf("initialize dispute coordinator: %w", err) | ||
} | ||
|
||
// TODO: run the subsystem | ||
|
||
return nil | ||
} | ||
|
||
func (d *disputeCoordinator) initialize() error { | ||
// TODO: wait for the first leaf | ||
|
||
if err := d.handleStartup(); err != nil { | ||
return fmt.Errorf("handle startup: %w", err) | ||
} | ||
|
||
// TODO: update db on disk | ||
|
||
//TODO implement me | ||
panic("implement me") | ||
} | ||
|
||
func (d *disputeCoordinator) handleStartup() error { | ||
var now = time.Now().Unix() | ||
activeDisputes, err := d.store.GetActiveDisputes(now) | ||
if err != nil { | ||
return fmt.Errorf("get active disputes: %w", err) | ||
} | ||
|
||
// get the highest session | ||
bestBlockHash := d.blockState.BestBlockHash() | ||
runtime, err := d.blockState.GetRuntime(bestBlockHash) | ||
if err != nil { | ||
return fmt.Errorf("getting runtime: %w", err) | ||
} | ||
|
||
highestSession, err := runtime.ParachainHostSessionIndexForChild() | ||
if err != nil { | ||
return fmt.Errorf("getting highest session: %w", err) | ||
} | ||
|
||
// TODO: check if there is a gap in cache | ||
|
||
// prune obsolete disputes | ||
if err := d.noteEarliestSession(highestSession); err != nil { | ||
return fmt.Errorf("note earliest session: %w", err) | ||
} | ||
|
||
// TODO: for every dispute in activeDisputes | ||
// get candidate votes | ||
// check if it is a potential spam | ||
// participate if needed, if not distribute the own vote | ||
activeDisputes.Descend(func(i btree.Item) bool { | ||
return true | ||
}) | ||
|
||
return nil | ||
} | ||
|
||
func (d *disputeCoordinator) noteEarliestSession(session parachain.SessionIndex) error { | ||
if d.store.earliestSession == nil { | ||
d.store.earliestSession = &session | ||
return nil | ||
} | ||
|
||
if *d.store.earliestSession > session { | ||
d.store.earliestSession = &session | ||
// clear recent disputes metadata | ||
recentDisputes, err := d.store.GetRecentDisputes() | ||
if err != nil { | ||
return fmt.Errorf("get recent disputes: %w", err) | ||
} | ||
|
||
// determine new recent disputes | ||
newRecentDisputes := btree.New(32) | ||
recentDisputes.Ascend(func(item btree.Item) bool { | ||
dispute := item.(*types.Dispute) | ||
if dispute.Comparator.SessionIndex >= session { | ||
newRecentDisputes.ReplaceOrInsert(dispute) | ||
return true | ||
} | ||
return false | ||
}) | ||
|
||
// prune obsolete disputes | ||
recentDisputes.Ascend(func(item btree.Item) bool { | ||
dispute := item.(*types.Dispute) | ||
if dispute.Comparator.SessionIndex < session { | ||
recentDisputes.Delete(dispute) | ||
return true | ||
} | ||
return false | ||
}) | ||
|
||
// update db | ||
if recentDisputes.Len() > 0 { | ||
if err = d.store.SetRecentDisputes(newRecentDisputes); err != nil { | ||
return fmt.Errorf("set recent disputes: %w", err) | ||
} | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func NewDisputeCoordinator() (CoordinatorSubsystem, error) { | ||
// TODO: figure out where to store the db | ||
path := "" | ||
db, err := badger.Open(badger.DefaultOptions(path)) | ||
if err != nil { | ||
return nil, fmt.Errorf("open badger db: %w", err) | ||
} | ||
backend := NewOverlayBackend(db) | ||
|
||
return &disputeCoordinator{ | ||
store: backend, | ||
}, nil | ||
} |