Commit 4cc747bd authored by OptimismBot's avatar OptimismBot Committed by GitHub

Merge pull request #5842 from ethereum-optimism/refcell/challenger/dgfwatcher

feat(op-challenger): DisputeGameFactory Watcher
parents e635fdd3 c8a82e8e
......@@ -72,6 +72,15 @@ func (c *Challenger) NewOracleSubscription() (*Subscription, error) {
return NewSubscription(query, c.Client(), c.log), nil
}
// NewFactorySubscription creates a new [Subscription] listening to the DisputeGameFactory contract.
func (c *Challenger) NewFactorySubscription() (*Subscription, error) {
query, err := BuildDisputeGameLogFilter(c.dgfABI)
if err != nil {
return nil, err
}
return NewSubscription(query, c.Client(), c.log), nil
}
// NewChallenger creates a new Challenger
func NewChallenger(cfg config.Config, l log.Logger, m metrics.Metricer) (*Challenger, error) {
ctx, cancel := context.WithCancel(context.Background())
......
package challenger
import (
"errors"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
)
var ErrMissingFactoryEvent = errors.New("missing factory event")
// BuildDisputeGameLogFilter creates a filter query for the DisputeGameFactory contract.
//
// The `DisputeGameCreated` event is encoded as:
// 0: address indexed disputeProxy,
// 1: GameType indexed gameType,
// 2: Claim indexed rootClaim,
func BuildDisputeGameLogFilter(contract *abi.ABI) (ethereum.FilterQuery, error) {
event := contract.Events["DisputeGameCreated"]
if event.ID == (common.Hash{}) {
return ethereum.FilterQuery{}, ErrMissingFactoryEvent
}
query := ethereum.FilterQuery{
Topics: [][]common.Hash{
{event.ID},
},
}
return query, nil
}
package challenger
import (
"testing"
"github.com/stretchr/testify/require"
eth "github.com/ethereum/go-ethereum"
abi "github.com/ethereum/go-ethereum/accounts/abi"
common "github.com/ethereum/go-ethereum/common"
)
// TestBuildDisputeGameLogFilter_Succeeds tests that the DisputeGame
// Log Filter is built correctly.
func TestBuildDisputeGameLogFilter_Succeeds(t *testing.T) {
event := abi.Event{
ID: [32]byte{0x01},
}
filterQuery := eth.FilterQuery{
Topics: [][]common.Hash{
{event.ID},
},
}
dgfABI := abi.ABI{
Events: map[string]abi.Event{
"DisputeGameCreated": event,
},
}
query, err := BuildDisputeGameLogFilter(&dgfABI)
require.Equal(t, filterQuery, query)
require.NoError(t, err)
}
// TestBuildDisputeGameLogFilter_Fails tests that the DisputeGame
// Log Filter fails when the event definition is missing.
func TestBuildDisputeGameLogFilter_Fails(t *testing.T) {
dgfABI := abi.ABI{
Events: map[string]abi.Event{},
}
_, err := BuildDisputeGameLogFilter(&dgfABI)
require.ErrorIs(t, ErrMissingFactoryEvent, err)
}
......@@ -25,4 +25,22 @@ var Subcommands = cli.Commands{
return Oracle(logger, cfg)
},
},
{
Name: "factory",
Usage: "Watches the DisputeGameFactory for new dispute games",
Action: func(ctx *cli.Context) error {
logger, err := config.LoggerFromCLI(ctx)
if err != nil {
return err
}
logger.Info("Listening for new dispute games")
cfg, err := config.NewConfigFromCLI(ctx)
if err != nil {
return err
}
return Factory(logger, cfg)
},
},
}
package watch
import (
"fmt"
"os"
"os/signal"
"syscall"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum-optimism/optimism/op-challenger/challenger"
"github.com/ethereum-optimism/optimism/op-challenger/config"
"github.com/ethereum-optimism/optimism/op-challenger/metrics"
)
// Factory listens to the DisputeGameFactory for newly created dispute games.
func Factory(logger log.Logger, cfg *config.Config) error {
if err := cfg.Check(); err != nil {
return fmt.Errorf("invalid config: %w", err)
}
m := metrics.NewMetrics("default")
service, err := challenger.NewChallenger(*cfg, logger, m)
if err != nil {
logger.Error("Unable to create the Challenger", "error", err)
return err
}
logger.Info("Listening for DisputeGameCreated events from the DisputeGameFactory contract", "dgf", cfg.DGFAddress.String())
subscription, err := service.NewFactorySubscription()
if err != nil {
logger.Error("Unable to create the subscription", "error", err)
return err
}
err = subscription.Subscribe()
if err != nil {
logger.Error("Unable to subscribe to the DisputeGameFactory contract", "error", err)
return err
}
defer subscription.Quit()
interruptChannel := make(chan os.Signal, 1)
signal.Notify(interruptChannel, []os.Signal{
os.Interrupt,
os.Kill,
syscall.SIGTERM,
syscall.SIGQUIT,
}...)
for {
select {
case log := <-subscription.Logs():
logger.Info("Received log", "log", log)
case <-interruptChannel:
logger.Info("Received interrupt signal, exiting...")
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment