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

Honest Strategy Revamp to Consider Path Weights #634

Open
wants to merge 1 commit into
base: is-essential-confirmable
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
38 changes: 38 additions & 0 deletions challenge-manager/chain-watcher/watcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,44 @@ func (w *Watcher) ComputeAncestors(
return chal.honestEdgeTree.ComputeAncestors(ctx, edgeId, blockHeader.Number.Uint64())
}

func (w *Watcher) IsConfirmableEssentialNode(
ctx context.Context,
challengedAssertionHash protocol.AssertionHash,
essentialNodeId protocol.EdgeId,
confirmationThreshold uint64,
) (confirmable bool, essentialPaths []challengetree.EssentialPath, timer uint64, err error) {
chal, ok := w.challenges.TryGet(challengedAssertionHash)
if !ok {
err = fmt.Errorf(
"could not get challenge for top level assertion %#x",
challengedAssertionHash,
)
return
}
blockHeader, err := w.chain.Backend().HeaderByNumber(ctx, util.GetSafeBlockNumber())
if err != nil {
return
}
if !blockHeader.Number.IsUint64() {
err = errors.New("block number is not uint64")
return
}
essentialNode, ok := chal.honestEdgeTree.GetEdge(essentialNodeId)
if !ok {
err = fmt.Errorf("could not get essential node with id %#x", essentialNodeId.Hash)
return
}
confirmable, essentialPaths, timer, err = chal.honestEdgeTree.IsConfirmableEssentialNode(
ctx,
challengetree.IsConfirmableArgs{
EssentialNode: essentialNode.Id(),
BlockNum: blockHeader.Number.Uint64(),
ConfirmationThreshold: confirmationThreshold,
},
)
return
}

func (w *Watcher) ComputeRootInheritedTimer(
ctx context.Context,
challengedAssertionHash protocol.AssertionHash,
Expand Down
28 changes: 14 additions & 14 deletions challenge-manager/challenge-tree/paths.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ import (
"github.com/OffchainLabs/bold/containers/option"
)

type essentialPath []protocol.EdgeId
type EssentialPath []protocol.EdgeId

type isConfirmableArgs struct {
essentialNode protocol.EdgeId
confirmationThreshold uint64
blockNum uint64
type IsConfirmableArgs struct {
EssentialNode protocol.EdgeId
ConfirmationThreshold uint64
BlockNum uint64
}

// Find all the paths down from an essential node, and
Expand All @@ -32,16 +32,16 @@ type isConfirmableArgs struct {
// essential node is then confirmable.
func (ht *RoyalChallengeTree) IsConfirmableEssentialNode(
ctx context.Context,
args isConfirmableArgs,
) (bool, []essentialPath, uint64, error) {
essentialNode, ok := ht.edges.TryGet(args.essentialNode)
args IsConfirmableArgs,
) (bool, []EssentialPath, uint64, error) {
essentialNode, ok := ht.edges.TryGet(args.EssentialNode)
if !ok {
return false, nil, 0, fmt.Errorf("essential node not found")
}
essentialPaths, essentialTimers, err := ht.findEssentialPaths(
ctx,
essentialNode,
args.blockNum,
args.BlockNum,
)
if err != nil {
return false, nil, 0, err
Expand All @@ -66,7 +66,7 @@ func (ht *RoyalChallengeTree) IsConfirmableEssentialNode(
return false, nil, 0, fmt.Errorf("no path weights computed")
}
minWeight := pathWeights.Pop()
allEssentialPathsConfirmable := minWeight >= args.confirmationThreshold
allEssentialPathsConfirmable := minWeight >= args.ConfirmationThreshold
return allEssentialPathsConfirmable, essentialPaths, minWeight, nil
}

Expand All @@ -81,13 +81,13 @@ func (ht *RoyalChallengeTree) findEssentialPaths(
ctx context.Context,
essentialNode protocol.ReadOnlyEdge,
blockNum uint64,
) ([]essentialPath, []essentialLocalTimers, error) {
allPaths := make([]essentialPath, 0)
) ([]EssentialPath, []essentialLocalTimers, error) {
allPaths := make([]EssentialPath, 0)
allTimers := make([]essentialLocalTimers, 0)

type visited struct {
essentialNode protocol.ReadOnlyEdge
path essentialPath
path EssentialPath
localTimers essentialLocalTimers
}
stack := newStack[*visited]()
Expand All @@ -99,7 +99,7 @@ func (ht *RoyalChallengeTree) findEssentialPaths(

stack.push(&visited{
essentialNode: essentialNode,
path: essentialPath{essentialNode.Id()},
path: EssentialPath{essentialNode.Id()},
localTimers: essentialLocalTimers{localTimer},
})

Expand Down
20 changes: 10 additions & 10 deletions challenge-manager/challenge-tree/paths_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
// understand the setup of the challenge tree.
_, _, _, err := tree.IsConfirmableEssentialNode(
ctx,
isConfirmableArgs{
essentialNode: protocol.EdgeId{},
IsConfirmableArgs{
EssentialNode: protocol.EdgeId{},
},
)
require.ErrorContains(t, err, "essential node not found")
Expand All @@ -32,10 +32,10 @@
blockNum := uint64(10)
isConfirmable, _, minPathWeight, err := tree.IsConfirmableEssentialNode(
ctx,
isConfirmableArgs{
confirmationThreshold: 10,
essentialNode: essentialHonestRoot.Id(),
blockNum: blockNum,
IsConfirmableArgs{
ConfirmationThreshold: 10,
EssentialNode: essentialHonestRoot.Id(),
BlockNum: blockNum,
},
)
require.NoError(t, err)
Expand All @@ -47,10 +47,10 @@
blockNum = uint64(14)
isConfirmable, _, minPathWeight, err = tree.IsConfirmableEssentialNode(
ctx,
isConfirmableArgs{
confirmationThreshold: 10,
essentialNode: essentialHonestRoot.Id(),
blockNum: blockNum,
IsConfirmableArgs{
ConfirmationThreshold: 10,
EssentialNode: essentialHonestRoot.Id(),
BlockNum: blockNum,
},
)
require.NoError(t, err)
Expand Down Expand Up @@ -93,7 +93,7 @@
require.Equal(t, 3, len(paths))
require.Equal(t, 3, len(pathLocalTimers))

wantPathA := essentialPath{

Check failure on line 96 in challenge-manager/challenge-tree/paths_test.go

View workflow job for this annotation

GitHub Actions / Build and Test

undefined: essentialPath

Check failure on line 96 in challenge-manager/challenge-tree/paths_test.go

View workflow job for this annotation

GitHub Actions / Lint

undefined: essentialPath

Check failure on line 96 in challenge-manager/challenge-tree/paths_test.go

View workflow job for this annotation

GitHub Actions / Build and Test

undefined: essentialPath

Check failure on line 96 in challenge-manager/challenge-tree/paths_test.go

View workflow job for this annotation

GitHub Actions / Lint

undefined: essentialPath
honestEdges["blk-3.a-4.a"].Id(),
honestEdges["blk-2.a-4.a"].Id(),
honestEdges["blk-0.a-4.a"].Id(),
Expand All @@ -102,7 +102,7 @@
require.Equal(t, wantPathA, paths[0])
require.Equal(t, wantATimers, pathLocalTimers[0])

wantPathB := essentialPath{

Check failure on line 105 in challenge-manager/challenge-tree/paths_test.go

View workflow job for this annotation

GitHub Actions / Build and Test

undefined: essentialPath

Check failure on line 105 in challenge-manager/challenge-tree/paths_test.go

View workflow job for this annotation

GitHub Actions / Lint

undefined: essentialPath

Check failure on line 105 in challenge-manager/challenge-tree/paths_test.go

View workflow job for this annotation

GitHub Actions / Build and Test

undefined: essentialPath

Check failure on line 105 in challenge-manager/challenge-tree/paths_test.go

View workflow job for this annotation

GitHub Actions / Lint

undefined: essentialPath
honestEdges["big-0.a-4.a"].Id(),
honestEdges["blk-2.a-3.a"].Id(),
honestEdges["blk-2.a-4.a"].Id(),
Expand All @@ -112,7 +112,7 @@
require.Equal(t, wantPathB, paths[1])
require.Equal(t, wantBTimers, pathLocalTimers[1])

wantPathC := essentialPath{

Check failure on line 115 in challenge-manager/challenge-tree/paths_test.go

View workflow job for this annotation

GitHub Actions / Build and Test

undefined: essentialPath

Check failure on line 115 in challenge-manager/challenge-tree/paths_test.go

View workflow job for this annotation

GitHub Actions / Lint

undefined: essentialPath (typecheck)

Check failure on line 115 in challenge-manager/challenge-tree/paths_test.go

View workflow job for this annotation

GitHub Actions / Build and Test

undefined: essentialPath

Check failure on line 115 in challenge-manager/challenge-tree/paths_test.go

View workflow job for this annotation

GitHub Actions / Lint

undefined: essentialPath (typecheck)
honestEdges["blk-0.a-2.a"].Id(),
honestEdges["blk-0.a-4.a"].Id(),
}
Expand Down
4 changes: 4 additions & 0 deletions challenge-manager/challenge-tree/tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ func (ht *RoyalChallengeTree) GetEdges() *threadsafe.Map[protocol.EdgeId, protoc
return ht.edges
}

func (ht *RoyalChallengeTree) GetEdge(edgeId protocol.EdgeId) (protocol.SpecEdge, bool) {
return ht.edges.TryGet(edgeId)
}

func (ht *RoyalChallengeTree) HasRoyalEdge(edgeId protocol.EdgeId) bool {
return ht.edges.Has(edgeId)
}
Expand Down
81 changes: 21 additions & 60 deletions challenge-manager/edge-tracker/tracker.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"time"

protocol "github.com/OffchainLabs/bold/chain-abstraction"
challengetree "github.com/OffchainLabs/bold/challenge-manager/challenge-tree"
"github.com/OffchainLabs/bold/containers"
"github.com/OffchainLabs/bold/containers/fsm"
"github.com/OffchainLabs/bold/containers/option"
Expand Down Expand Up @@ -49,10 +50,12 @@ type RoyalChallengeWriter interface {
AddVerifiedHonestEdge(
ctx context.Context, verifiedHonest protocol.VerifiedRoyalEdge,
) error
ComputeRootInheritedTimer(
IsConfirmableEssentialNode(
ctx context.Context,
challengedAssertionHash protocol.AssertionHash,
) (protocol.InheritedTimer, error)
essentialNodeId protocol.EdgeId,
confirmationThreshold uint64,
) (confirmable bool, essentialPaths []challengetree.EssentialPath, timer uint64, err error)
}

type ChallengeTracker interface {
Expand Down Expand Up @@ -426,18 +429,6 @@ func (et *Tracker) tryToConfirmEdge(ctx context.Context) (bool, error) {
return false, err
}
fields := et.uniqueTrackerLogFields()
start := time.Now()
computedTimer, err := et.chainWatcher.ComputeRootInheritedTimer(ctx, assertionHash)
if err != nil {
fields["error"] = err
srvlog.Error("Could not update time cache")
return false, errors.Wrap(err, "could not update edge inherited timer")
}
end := time.Since(start)
onchainTimer, err := et.edge.SafeHeadInheritedTimer(ctx)
if err != nil {
return false, errors.Wrap(err, "could not get edge onchain inherited timer")
}
manager, err := et.chain.SpecChallengeManager(ctx)
if err != nil {
return false, errors.Wrap(err, "could not get challenge manager")
Expand All @@ -446,53 +437,23 @@ func (et *Tracker) tryToConfirmEdge(ctx context.Context) (bool, error) {
if err != nil {
return false, errors.Wrap(err, "could not check the challenge period length")
}
localFields := log.Ctx{
"localTimer": computedTimer,
"onchainTimer": onchainTimer,
"confirmableAfter": chalPeriod,
"edgeId": fmt.Sprintf("%#x", et.edge.Id().Bytes()[:4]),
"took": end,
"fromBatch": et.associatedAssertionMetadata.FromBatch,
"toBatch": et.associatedAssertionMetadata.ToBatch,
"claimedAssertion": fmt.Sprintf("%#x", et.associatedAssertionMetadata.ClaimedAssertionHash[:4]),
}
srvlog.Info("Updated edge timer", localFields)
// Short circuit early if the edge is confirmable.
// We have a few things to check here:
// First, if the edge's onchain timer is greater than a challenge period, then we can
// immediately confirm by time by sending a transaction.
if onchainTimer >= protocol.InheritedTimer(chalPeriod) {
srvlog.Info("Onchain timer is greater than challenge period, now confirming edge by time", localFields)
if _, err := et.edge.ConfirmByTimer(ctx); err != nil {
return false, errors.Wrapf(
err,
"could not confirm by timer: got timer %d, chal period %d",
onchainTimer,
chalPeriod,
)
}
srvlog.Info("Confirmed edge by time", fields)
confirmedCounter.Inc(1)
return true, nil
start := time.Now()
isConfirmable, essentialPaths, timer, err := et.chainWatcher.IsConfirmableEssentialNode(
ctx,
assertionHash,
et.edge.Id(),
chalPeriod,
)
if err != nil {
fields["error"] = err
srvlog.Error("Could not check if essential node is confirmable")
return false, errors.Wrap(err, "not check if essential node is confirmable")
}
// Otherwise, if the locally cached timer is greater than a challenge period, it means
// we need to trigger a confirmation job that will propagate updates to the whole royal
// challenge tree onchain until the edge has an onchain timer >= a challenge period.
// We let our confirmer dependency take care of this confirmatin job.
if uint64(computedTimer) >= chalPeriod {
srvlog.Info("Local computed timer big enough to confirm edge", localFields)
if err := et.challengeConfirmer.beginConfirmationJob(
ctx,
assertionHash,
et.edge,
chalPeriod,
); err != nil {
return false, errors.Wrap(
err,
"could not complete confirmation job for royal, block challenge edge",
)
}
// The edge is now confirmed.
end := time.Since(start)
_ = end
_ = essentialPaths
_ = timer
if isConfirmable {
return true, nil
}
return false, nil
Expand Down
Loading