Commit 3c4f3da1 authored by Adrian Sutton's avatar Adrian Sutton Committed by GitHub

dispute-mon: Load resolved state of claims from resolvedSubgames map (#10240)

parent c38ce096
...@@ -27,6 +27,7 @@ var ( ...@@ -27,6 +27,7 @@ var (
methodClaimCount = "claimDataLen" methodClaimCount = "claimDataLen"
methodClaim = "claimData" methodClaim = "claimData"
methodL1Head = "l1Head" methodL1Head = "l1Head"
methodResolvedSubgames = "resolvedSubgames"
methodResolve = "resolve" methodResolve = "resolve"
methodResolveClaim = "resolveClaim" methodResolveClaim = "resolveClaim"
methodAttack = "attack" methodAttack = "attack"
...@@ -353,6 +354,23 @@ func (f *FaultDisputeGameContract) GetAllClaims(ctx context.Context, block rpcbl ...@@ -353,6 +354,23 @@ func (f *FaultDisputeGameContract) GetAllClaims(ctx context.Context, block rpcbl
return claims, nil return claims, nil
} }
func (f *FaultDisputeGameContract) IsResolved(ctx context.Context, block rpcblock.Block, claims ...types.Claim) ([]bool, error) {
defer f.metrics.StartContractRequest("IsResolved")()
calls := make([]batching.Call, 0, len(claims))
for _, claim := range claims {
calls = append(calls, f.contract.Call(methodResolvedSubgames, big.NewInt(int64(claim.ContractIndex))))
}
results, err := f.multiCaller.Call(ctx, block, calls...)
if err != nil {
return nil, fmt.Errorf("failed to retrieve resolved subgames: %w", err)
}
resolved := make([]bool, 0, len(claims))
for _, result := range results {
resolved = append(resolved, result.GetBool(0))
}
return resolved, nil
}
func (f *FaultDisputeGameContract) vm(ctx context.Context) (*VMContract, error) { func (f *FaultDisputeGameContract) vm(ctx context.Context) (*VMContract, error) {
result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodVM)) result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodVM))
if err != nil { if err != nil {
......
...@@ -455,6 +455,31 @@ func TestFaultDisputeGame_ClaimCreditTx(t *testing.T) { ...@@ -455,6 +455,31 @@ func TestFaultDisputeGame_ClaimCreditTx(t *testing.T) {
}) })
} }
func TestFaultDisputeGame_IsResolved(t *testing.T) {
stubRpc, game := setupFaultDisputeGameTest(t)
block := rpcblock.ByNumber(482)
claims := []faultTypes.Claim{
{ContractIndex: 1},
{ContractIndex: 5},
{ContractIndex: 13},
}
claimIdxs := []*big.Int{big.NewInt(1), big.NewInt(5), big.NewInt(13)}
expected := []bool{false, true, true}
for i, idx := range claimIdxs {
stubRpc.SetResponse(fdgAddr, methodResolvedSubgames, block, []interface{}{idx}, []interface{}{expected[i]})
}
actual, err := game.IsResolved(context.Background(), block, claims...)
require.NoError(t, err)
require.Equal(t, len(expected), len(actual))
for i := range expected {
require.Equal(t, expected[i], actual[i])
}
}
func setupFaultDisputeGameTest(t *testing.T) (*batchingTest.AbiBasedRpc, *FaultDisputeGameContract) { func setupFaultDisputeGameTest(t *testing.T) (*batchingTest.AbiBasedRpc, *FaultDisputeGameContract) {
fdgAbi, err := snapshots.LoadFaultDisputeGameABI() fdgAbi, err := snapshots.LoadFaultDisputeGameABI()
require.NoError(t, err) require.NoError(t, err)
......
...@@ -29,6 +29,7 @@ type GameCaller interface { ...@@ -29,6 +29,7 @@ type GameCaller interface {
GetAllClaims(context.Context, rpcblock.Block) ([]faultTypes.Claim, error) GetAllClaims(context.Context, rpcblock.Block) ([]faultTypes.Claim, error)
BondCaller BondCaller
BalanceCaller BalanceCaller
ClaimCaller
} }
type GameCallerCreator struct { type GameCallerCreator struct {
......
...@@ -2,27 +2,36 @@ package extract ...@@ -2,27 +2,36 @@ package extract
import ( import (
"context" "context"
"math/big" "fmt"
faultTypes "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum-optimism/optimism/op-dispute-mon/mon/types" "github.com/ethereum-optimism/optimism/op-dispute-mon/mon/types"
"github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock" "github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock"
) )
var _ Enricher = (*ClaimEnricher)(nil) var _ Enricher = (*ClaimEnricher)(nil)
type ClaimCaller interface {
IsResolved(ctx context.Context, block rpcblock.Block, claim ...faultTypes.Claim) ([]bool, error)
}
type ClaimEnricher struct{} type ClaimEnricher struct{}
func NewClaimEnricher() *ClaimEnricher { func NewClaimEnricher() *ClaimEnricher {
return &ClaimEnricher{} return &ClaimEnricher{}
} }
var resolvedBondAmount = new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 128), big.NewInt(1)) func (e *ClaimEnricher) Enrich(ctx context.Context, block rpcblock.Block, caller GameCaller, game *types.EnrichedGameData) error {
claims := make([]faultTypes.Claim, 0, len(game.Claims))
func (e *ClaimEnricher) Enrich(_ context.Context, _ rpcblock.Block, _ GameCaller, game *types.EnrichedGameData) error { for _, claim := range game.Claims {
for i, claim := range game.Claims { claims = append(claims, claim.Claim)
if claim.Bond.Cmp(resolvedBondAmount) == 0 { }
game.Claims[i].Resolved = true resolved, err := caller.IsResolved(ctx, block, claims...)
} if err != nil {
return fmt.Errorf("failed to retrieve resolved status: %w", err)
}
for i := range game.Claims {
game.Claims[i].Resolved = resolved[i]
} }
return nil return nil
} }
...@@ -2,7 +2,7 @@ package extract ...@@ -2,7 +2,7 @@ package extract
import ( import (
"context" "context"
"math/big" "errors"
"testing" "testing"
faultTypes "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types" faultTypes "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
...@@ -11,30 +11,36 @@ import ( ...@@ -11,30 +11,36 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestMaxValue(t *testing.T) {
require.Equal(t, resolvedBondAmount.String(), "340282366920938463463374607431768211455")
}
func TestClaimEnricher(t *testing.T) { func TestClaimEnricher(t *testing.T) {
caller := &mockGameCaller{resolved: make(map[int]bool)}
enricher := NewClaimEnricher() enricher := NewClaimEnricher()
expected := []bool{true, false, false, false, false}
game := &types.EnrichedGameData{ game := &types.EnrichedGameData{
Claims: []types.EnrichedClaim{ Claims: claimsWithResolvedSubgames(caller, expected...),
newClaimWithBond(resolvedBondAmount),
newClaimWithBond(big.NewInt(0)),
newClaimWithBond(big.NewInt(100)),
newClaimWithBond(new(big.Int).Sub(resolvedBondAmount, big.NewInt(1))),
newClaimWithBond(new(big.Int).Add(resolvedBondAmount, big.NewInt(1))),
},
} }
caller := &mockGameCaller{}
err := enricher.Enrich(context.Background(), rpcblock.Latest, caller, game) err := enricher.Enrich(context.Background(), rpcblock.Latest, caller, game)
require.NoError(t, err) require.NoError(t, err)
expected := []bool{true, false, false, false, false}
for i, claim := range game.Claims { for i, claim := range game.Claims {
require.Equal(t, expected[i], claim.Resolved) require.Equal(t, expected[i], claim.Resolved)
} }
} }
func newClaimWithBond(bond *big.Int) types.EnrichedClaim { func TestClaimEnricherError(t *testing.T) {
return types.EnrichedClaim{Claim: faultTypes.Claim{ClaimData: faultTypes.ClaimData{Bond: bond}}} expectedErr := errors.New("boom")
caller := &mockGameCaller{resolved: make(map[int]bool), resolvedErr: expectedErr}
enricher := NewClaimEnricher()
game := &types.EnrichedGameData{
Claims: claimsWithResolvedSubgames(caller, true, false),
}
err := enricher.Enrich(context.Background(), rpcblock.Latest, caller, game)
require.ErrorIs(t, err, expectedErr)
}
func claimsWithResolvedSubgames(caller *mockGameCaller, resolved ...bool) []types.EnrichedClaim {
claims := make([]types.EnrichedClaim, len(resolved))
for i, r := range resolved {
claims[i] = types.EnrichedClaim{Claim: faultTypes.Claim{ContractIndex: i}}
caller.resolved[i] = r
}
return claims
} }
...@@ -196,6 +196,8 @@ type mockGameCaller struct { ...@@ -196,6 +196,8 @@ type mockGameCaller struct {
withdrawalsCalls int withdrawalsCalls int
withdrawalsErr error withdrawalsErr error
withdrawals []*contracts.WithdrawalRequest withdrawals []*contracts.WithdrawalRequest
resolvedErr error
resolved map[int]bool
} }
func (m *mockGameCaller) GetRequiredBonds(ctx context.Context, block rpcblock.Block, positions ...*big.Int) ([]*big.Int, error) { func (m *mockGameCaller) GetRequiredBonds(ctx context.Context, block rpcblock.Block, positions ...*big.Int) ([]*big.Int, error) {
...@@ -266,6 +268,17 @@ func (m *mockGameCaller) GetBalance(_ context.Context, _ rpcblock.Block) (*big.I ...@@ -266,6 +268,17 @@ func (m *mockGameCaller) GetBalance(_ context.Context, _ rpcblock.Block) (*big.I
return m.balance, m.balanceAddr, nil return m.balance, m.balanceAddr, nil
} }
func (m *mockGameCaller) IsResolved(_ context.Context, _ rpcblock.Block, claims ...faultTypes.Claim) ([]bool, error) {
if m.resolvedErr != nil {
return nil, m.resolvedErr
}
resolved := make([]bool, len(claims))
for i, claim := range claims {
resolved[i] = m.resolved[claim.ContractIndex]
}
return resolved, nil
}
type mockEnricher struct { type mockEnricher struct {
err error err error
calls int calls int
......
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