Commit dc7aebc9 authored by refcell's avatar refcell Committed by GitHub

feat(op-e2e): Bond Claiming Tests (#9762)

* feat(op-e2e): test reclaiming bonds by the challenger

* fix(op-e2e): review
parent c95a2229
......@@ -445,7 +445,7 @@ func TestGameWindow(t *testing.T) {
})
t.Run("ParsesDefault", func(t *testing.T) {
cfg := configForArgs(t, addRequiredArgs(config.TraceTypeAlphabet, "--game-window=264h"))
cfg := configForArgs(t, addRequiredArgs(config.TraceTypeAlphabet, "--game-window=360h"))
require.Equal(t, config.DefaultGameWindow, cfg.GameWindow)
})
}
......
......@@ -79,9 +79,9 @@ const (
DefaultCannonInfoFreq = uint(10_000_000)
// DefaultGameWindow is the default maximum time duration in the past
// that the challenger will look for games to progress.
// The default value is 11 days, which is a 4 day resolution buffer
// The default value is 15 days, which is an 8 day resolution buffer
// and bond claiming buffer plus the 7 day game finalization window.
DefaultGameWindow = time.Duration(11 * 24 * time.Hour)
DefaultGameWindow = time.Duration(15 * 24 * time.Hour)
DefaultMaxPendingTx = 10
)
......
......@@ -250,6 +250,7 @@ func (s *Service) initMonitor(cfg *config.Config) {
func (s *Service) Start(ctx context.Context) error {
s.logger.Info("starting scheduler")
s.sched.Start(ctx)
s.claimer.Start(ctx)
s.preimages.Start(ctx)
s.logger.Info("starting monitoring")
s.monitor.StartMonitoring()
......
......@@ -71,6 +71,12 @@ func (g *OutputGameHelper) Addr() common.Address {
return g.addr
}
func (g *OutputGameHelper) Balance(ctx context.Context, addr common.Address) *big.Int {
balance, err := g.client.BalanceAt(ctx, addr, nil)
g.require.NoError(err, "Failed to get balance")
return balance
}
func (g *OutputGameHelper) SplitDepth(ctx context.Context) types.Depth {
splitDepth, err := g.game.SplitDepth(&bind.CallOpts{Context: ctx})
g.require.NoError(err, "failed to load split depth")
......@@ -166,6 +172,50 @@ func (g *OutputGameHelper) GameDuration(ctx context.Context) time.Duration {
return time.Duration(duration) * time.Second
}
func (g *OutputGameHelper) WaitForNoAvailableCredit(ctx context.Context, addr common.Address) {
timedCtx, cancel := context.WithTimeout(ctx, defaultTimeout)
defer cancel()
err := wait.For(timedCtx, time.Second, func() (bool, error) {
bal, err := g.game.Credit(&bind.CallOpts{Context: timedCtx}, addr)
if err != nil {
return false, err
}
g.t.Log("Waiting for zero available credit", "current", bal, "addr", addr)
return bal.Cmp(big.NewInt(0)) == 0, nil
})
if err != nil {
g.LogGameData(ctx)
g.require.NoError(err, "Failed to wait for zero available credit")
}
}
func (g *OutputGameHelper) AvailableCredit(ctx context.Context, addr common.Address) *big.Int {
credit, err := g.game.Credit(&bind.CallOpts{Context: ctx}, addr)
g.require.NoErrorf(err, "Failed to fetch available credit for %v", addr)
return credit
}
func (g *OutputGameHelper) CreditUnlockDuration(ctx context.Context) time.Duration {
weth, err := g.game.Weth(&bind.CallOpts{Context: ctx})
g.require.NoError(err, "Failed to get WETH contract")
contract, err := bindings.NewDelayedWETH(weth, g.client)
g.require.NoError(err)
period, err := contract.Delay(&bind.CallOpts{Context: ctx})
g.require.NoError(err, "Failed to get WETH unlock period")
float, _ := period.Float64()
return time.Duration(float) * time.Second
}
func (g *OutputGameHelper) WethBalance(ctx context.Context, addr common.Address) *big.Int {
weth, err := g.game.Weth(&bind.CallOpts{Context: ctx})
g.require.NoError(err, "Failed to get WETH contract")
contract, err := bindings.NewDelayedWETH(weth, g.client)
g.require.NoError(err)
balance, err := contract.BalanceOf(&bind.CallOpts{Context: ctx}, addr)
g.require.NoError(err, "Failed to get WETH balance")
return balance
}
// WaitForClaimCount waits until there are at least count claims in the game.
// This does not check that the number of claims is exactly the specified count to avoid intermittent failures
// where a challenger posts an additional claim before this method sees the number of claims it was waiting for.
......
......@@ -6,6 +6,7 @@ import (
"math/big"
"testing"
"github.com/ethereum-optimism/optimism/op-chain-ops/deployer"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/cannon"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
......@@ -73,6 +74,70 @@ func TestOutputCannonGame(t *testing.T) {
game.WaitForGameStatus(ctx, disputegame.StatusChallengerWins)
}
func TestOutputCannon_ReclaimBond(t *testing.T) {
// The dishonest actor always posts claims with all zeros.
op_e2e.InitParallel(t, op_e2e.UsesCannon)
ctx := context.Background()
sys, l1Client := startFaultDisputeSystem(t)
t.Cleanup(sys.Close)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
game := disputeGameFactory.StartOutputCannonGame(ctx, "sequencer", 3, common.Hash{})
game.LogGameData(ctx)
// The dispute game should have a zero balance
balance := game.WethBalance(ctx, game.Addr())
require.Zero(t, balance.Uint64())
alice := sys.Cfg.Secrets.Addresses().Alice
bal, _ := big.NewInt(0).SetString("1000000000000000000000", 10)
require.Equal(t, bal, game.Balance(ctx, alice))
// Grab the root claim
claim := game.RootClaim(ctx)
game.StartChallenger(ctx, "sequencer", "Challenger", challenger.WithPrivKey(sys.Cfg.Secrets.Alice))
// Perform a few moves
claim = claim.WaitForCounterClaim(ctx)
game.LogGameData(ctx)
claim = claim.Attack(ctx, common.Hash{})
claim = claim.WaitForCounterClaim(ctx)
game.LogGameData(ctx)
claim = claim.Attack(ctx, common.Hash{})
game.LogGameData(ctx)
_ = claim.WaitForCounterClaim(ctx)
// Expect posted claims so the game balance is non-zero
balance = game.WethBalance(ctx, game.Addr())
expectedBalance, _ := big.NewInt(0).SetString("589772600000000000", 10)
require.Equal(t, expectedBalance, balance)
sys.TimeTravelClock.AdvanceTime(game.GameDuration(ctx))
require.NoError(t, wait.ForNextBlock(ctx, l1Client))
game.WaitForGameStatus(ctx, disputegame.StatusChallengerWins)
game.LogGameData(ctx)
// Expect Alice's credit to be non-zero
// But it can't be claimed right now since there is a delay on the weth unlock
expectedCredit, _ := big.NewInt(0).SetString("589772600000000000", 10)
require.Equal(t, expectedCredit, game.AvailableCredit(ctx, alice))
// The actor should have a small credit available to claim
actorCredit := game.AvailableCredit(ctx, deployer.TestAddress)
require.True(t, actorCredit.Cmp(big.NewInt(0)) == 0)
// Advance the time past the weth unlock delay
sys.TimeTravelClock.AdvanceTime(game.CreditUnlockDuration(ctx))
require.NoError(t, wait.ForNextBlock(ctx, l1Client))
// Wait for alice to have no available credit
// aka, wait for the challenger to claim its credit
game.WaitForNoAvailableCredit(ctx, alice)
// The dispute game delayed weth balance should be zero since it's all claimed
require.True(t, game.WethBalance(ctx, game.Addr()).Cmp(big.NewInt(0)) == 0)
}
func TestOutputCannon_ChallengeAllZeroClaim(t *testing.T) {
// The dishonest actor always posts claims with all zeros.
op_e2e.InitParallel(t, op_e2e.UsesCannon)
......
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