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 (
methodClaimCount = "claimDataLen"
methodClaim = "claimData"
methodL1Head = "l1Head"
methodResolvedSubgames = "resolvedSubgames"
methodResolve = "resolve"
methodResolveClaim = "resolveClaim"
methodAttack = "attack"
......@@ -353,6 +354,23 @@ func (f *FaultDisputeGameContract) GetAllClaims(ctx context.Context, block rpcbl
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) {
result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodVM))
if err != nil {
......
......@@ -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) {
fdgAbi, err := snapshots.LoadFaultDisputeGameABI()
require.NoError(t, err)
......
......@@ -29,6 +29,7 @@ type GameCaller interface {
GetAllClaims(context.Context, rpcblock.Block) ([]faultTypes.Claim, error)
BondCaller
BalanceCaller
ClaimCaller
}
type GameCallerCreator struct {
......
......@@ -2,27 +2,36 @@ package extract
import (
"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-service/sources/batching/rpcblock"
)
var _ Enricher = (*ClaimEnricher)(nil)
type ClaimCaller interface {
IsResolved(ctx context.Context, block rpcblock.Block, claim ...faultTypes.Claim) ([]bool, error)
}
type ClaimEnricher struct{}
func NewClaimEnricher() *ClaimEnricher {
return &ClaimEnricher{}
}
var resolvedBondAmount = new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 128), big.NewInt(1))
func (e *ClaimEnricher) Enrich(_ context.Context, _ rpcblock.Block, _ GameCaller, game *types.EnrichedGameData) error {
for i, claim := range game.Claims {
if claim.Bond.Cmp(resolvedBondAmount) == 0 {
game.Claims[i].Resolved = true
func (e *ClaimEnricher) Enrich(ctx context.Context, block rpcblock.Block, caller GameCaller, game *types.EnrichedGameData) error {
claims := make([]faultTypes.Claim, 0, len(game.Claims))
for _, claim := range game.Claims {
claims = append(claims, claim.Claim)
}
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
}
......@@ -2,7 +2,7 @@ package extract
import (
"context"
"math/big"
"errors"
"testing"
faultTypes "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
......@@ -11,30 +11,36 @@ import (
"github.com/stretchr/testify/require"
)
func TestMaxValue(t *testing.T) {
require.Equal(t, resolvedBondAmount.String(), "340282366920938463463374607431768211455")
}
func TestClaimEnricher(t *testing.T) {
caller := &mockGameCaller{resolved: make(map[int]bool)}
enricher := NewClaimEnricher()
expected := []bool{true, false, false, false, false}
game := &types.EnrichedGameData{
Claims: []types.EnrichedClaim{
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))),
},
Claims: claimsWithResolvedSubgames(caller, expected...),
}
caller := &mockGameCaller{}
err := enricher.Enrich(context.Background(), rpcblock.Latest, caller, game)
require.NoError(t, err)
expected := []bool{true, false, false, false, false}
for i, claim := range game.Claims {
require.Equal(t, expected[i], claim.Resolved)
}
}
func newClaimWithBond(bond *big.Int) types.EnrichedClaim {
return types.EnrichedClaim{Claim: faultTypes.Claim{ClaimData: faultTypes.ClaimData{Bond: bond}}}
func TestClaimEnricherError(t *testing.T) {
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 {
withdrawalsCalls int
withdrawalsErr error
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) {
......@@ -266,6 +268,17 @@ func (m *mockGameCaller) GetBalance(_ context.Context, _ rpcblock.Block) (*big.I
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 {
err error
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