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

Sync Potentially Completed Challenges With a Max Lookback for Refund Purposes #705

Merged
merged 17 commits into from
Nov 26, 2024
34 changes: 21 additions & 13 deletions challenge-manager/chain-watcher/watcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,15 @@ type Watcher struct {
// Only track challenges for these parent assertion hashes.
// Track all if empty / nil.
trackChallengeParentAssertionHashes []protocol.AssertionHash
maxLookbackBlocks uint64
}

type WatcherOpt func(w *Watcher)

func WithSyncMaxLookbackBlocks(maxLookback uint64) WatcherOpt {
return func(w *Watcher) {
w.maxLookbackBlocks = maxLookback
}
}

// New initializes a watcher service for frequently scanning the chain
Expand All @@ -99,8 +108,9 @@ func New(
assertionConfirmingInterval time.Duration,
averageTimeForBlockCreation time.Duration,
trackChallengeParentAssertionHashes []protocol.AssertionHash,
opts ...WatcherOpt,
) (*Watcher, error) {
return &Watcher{
w := &Watcher{
chain: chain,
edgeManager: nil, // Must be set after construction.
pollEventsInterval: time.Millisecond * 500,
Expand All @@ -114,7 +124,12 @@ func New(
averageTimeForBlockCreation: averageTimeForBlockCreation,
evilEdgesByLevel: threadsafe.NewMap(threadsafe.MapWithMetric[protocol.ChallengeLevel, *threadsafe.Set[protocol.EdgeId]]("evilEdgesByLevel")),
trackChallengeParentAssertionHashes: trackChallengeParentAssertionHashes,
}, nil
maxLookbackBlocks: daysToBlocks(averageTimeForBlockCreation, 21), // Default to 3 weeks worth of blocks.
}
for _, opt := range opts {
opt(w)
}
return w, nil
}

// SetEdgeManager sets the EdgeManager that will track the royal edges.
Expand Down Expand Up @@ -580,19 +595,8 @@ func (w *Watcher) AddEdge(ctx context.Context, edge protocol.SpecEdge) (bool, er
if err != nil {
return false, err
}
challengeComplete, err := w.chain.IsChallengeComplete(ctx, challengeParentAssertionHash)
if err != nil {
return false, errors.Wrapf(
err,
"could not check if edge with parent assertion hash %#x is part of a completed challenge",
challengeParentAssertionHash.Hash,
)
}
start, startRoot := edge.StartCommitment()
end, endRoot := edge.EndCommitment()
if challengeComplete {
return false, nil
}
chal, ok := w.challenges.TryGet(challengeParentAssertionHash)
if !ok {
tree := challengetree.New(
Expand Down Expand Up @@ -1056,3 +1060,7 @@ func (w *Watcher) saveEdgeToDB(
HasLengthOneRival: hasLengthOneRival,
})
}

func daysToBlocks(avgBlockCreationTime time.Duration, days uint64) uint64 {
rauljordan marked this conversation as resolved.
Show resolved Hide resolved
return uint64(math.Round(float64(days) * 24 * 60 * 60 / avgBlockCreationTime.Seconds()))
}
7 changes: 7 additions & 0 deletions testing/endtoend/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,13 @@ func runEndToEndTest(t *testing.T, cfg *e2eConfig) {
require.NoError(t, g.Wait())
}

func TestEndToEnd_HonestValidatorCrashes_ConfirmsEssentialEdgesAfterChallengeCompletion(t *testing.T) {
// This test ensures that an honest validator can crash after a challenge has completed, can resync
// the completed challenge and continue playing the game until all essential edges are confirmed.
// This is to ensure that even if a challenge is completed, we can still resync it and continue
// playing for the sake of refunding honest stakes.
}

type seqMessage struct {
dataHash common.Hash
afterDelayedMessagesRead *big.Int
Expand Down
Loading