From f5f40acf7b867ae7b689c41f7003f549287e8f0c Mon Sep 17 00:00:00 2001 From: kanishka Date: Tue, 20 Jun 2023 23:46:11 +0530 Subject: [PATCH] add disputes coordinator --- dot/parachain/dispute/coordinator.go | 143 +++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 dot/parachain/dispute/coordinator.go diff --git a/dot/parachain/dispute/coordinator.go b/dot/parachain/dispute/coordinator.go new file mode 100644 index 0000000000..6b68ce9f51 --- /dev/null +++ b/dot/parachain/dispute/coordinator.go @@ -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 +}