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

fix(op-dispute-mon): remove unused collateral calculator (#9926)

parent 90552788
package bonds package bonds
import ( import (
"context"
"fmt"
"math/big" "math/big"
faultTypes "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
monTypes "github.com/ethereum-optimism/optimism/op-dispute-mon/mon/types" monTypes "github.com/ethereum-optimism/optimism/op-dispute-mon/mon/types"
"github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"golang.org/x/exp/maps"
) )
type BondContract interface { type Collateral struct {
GetCredits(ctx context.Context, block rpcblock.Block, recipients ...common.Address) ([]*big.Int, error) // Required is the amount of collateral required to pay out bonds.
Required *big.Int
// Actual is the amount of collateral actually head by the DelayedWETH contract
Actual *big.Int
} }
// CalculateRequiredCollateral determines the minimum balance required for a fault dispute game contract in order // CalculateRequiredCollateral determines the minimum balance required for each DelayedWETH contract used by a set
// to pay the outstanding bonds and credits. // of dispute games.
// It returns the sum of unpaid bonds from claims, plus the sum of allocated but unclaimed credits. // Returns a map of DelayedWETH contract address to collateral data (required and actual amounts)
func CalculateRequiredCollateral(ctx context.Context, contract BondContract, blockHash common.Hash, claims []faultTypes.Claim) (*big.Int, error) { func CalculateRequiredCollateral(games []*monTypes.EnrichedGameData) map[common.Address]Collateral {
unpaidBonds := big.NewInt(0) result := make(map[common.Address]Collateral)
recipients := make(map[common.Address]bool) for _, game := range games {
for _, claim := range claims { collateral, ok := result[game.WETHContract]
if monTypes.ResolvedBondAmount.Cmp(claim.Bond) != 0 { if !ok {
unpaidBonds = new(big.Int).Add(unpaidBonds, claim.Bond) collateral = Collateral{
Required: big.NewInt(0),
Actual: game.ETHCollateral,
} }
recipients[claim.Claimant] = true
if claim.CounteredBy != (common.Address{}) {
recipients[claim.CounteredBy] = true
} }
gameRequired := requiredCollateralForGame(game)
collateral.Required = new(big.Int).Add(collateral.Required, gameRequired)
result[game.WETHContract] = collateral
} }
return result
}
credits, err := contract.GetCredits(ctx, rpcblock.ByHash(blockHash), maps.Keys(recipients)...) func requiredCollateralForGame(game *monTypes.EnrichedGameData) *big.Int {
if err != nil { required := big.NewInt(0)
return nil, fmt.Errorf("failed to load credits: %w", err) for _, claim := range game.Claims {
if monTypes.ResolvedBondAmount.Cmp(claim.Bond) != 0 {
required = new(big.Int).Add(required, claim.Bond)
}
} }
for _, credit := range credits {
unpaidBonds = new(big.Int).Add(unpaidBonds, credit) for _, unclaimedCredit := range game.Credits {
required = new(big.Int).Add(required, unclaimedCredit)
} }
return unpaidBonds, nil return required
} }
package bonds package bonds
import ( import (
"context"
"math/big" "math/big"
"testing" "testing"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
monTypes "github.com/ethereum-optimism/optimism/op-dispute-mon/mon/types" monTypes "github.com/ethereum-optimism/optimism/op-dispute-mon/mon/types"
"github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestCalculateRequiredCollateral(t *testing.T) { func TestCalculateRequiredCollateral(t *testing.T) {
claims := []types.Claim{ weth1 := common.Address{0x1a}
weth1Balance := big.NewInt(4200)
weth2 := common.Address{0x2b}
weth2Balance := big.NewInt(6000)
game1 := &monTypes.EnrichedGameData{
Claims: []types.Claim{
{ {
ClaimData: types.ClaimData{ ClaimData: types.ClaimData{
Bond: monTypes.ResolvedBondAmount, Bond: monTypes.ResolvedBondAmount,
...@@ -35,30 +38,67 @@ func TestCalculateRequiredCollateral(t *testing.T) { ...@@ -35,30 +38,67 @@ func TestCalculateRequiredCollateral(t *testing.T) {
Claimant: common.Address{0x03}, Claimant: common.Address{0x03},
CounteredBy: common.Address{}, CounteredBy: common.Address{},
}, },
}
contract := &stubBondContract{
credits: map[common.Address]*big.Int{
{0x01}: big.NewInt(3),
{0x03}: big.NewInt(8),
}, },
Credits: map[common.Address]*big.Int{
common.Address{0x01}: big.NewInt(2),
common.Address{0x04}: big.NewInt(3),
},
WETHContract: weth1,
ETHCollateral: weth1Balance,
} }
collateral, err := CalculateRequiredCollateral(context.Background(), contract, common.Hash{0xab}, claims) game2 := &monTypes.EnrichedGameData{
require.NoError(t, err) Claims: []types.Claim{
require.Equal(t, collateral.Int64(), int64(5+7+3+8)) {
} ClaimData: types.ClaimData{
Bond: monTypes.ResolvedBondAmount,
type stubBondContract struct { },
credits map[common.Address]*big.Int Claimant: common.Address{0x01},
} CounteredBy: common.Address{0x02},
},
func (s *stubBondContract) GetCredits(_ context.Context, _ rpcblock.Block, recipients ...common.Address) ([]*big.Int, error) { {
results := make([]*big.Int, len(recipients)) ClaimData: types.ClaimData{
for i, recipient := range recipients { Bond: big.NewInt(6),
credit, ok := s.credits[recipient] },
if !ok { Claimant: common.Address{0x03},
credit = big.NewInt(0) CounteredBy: common.Address{},
},
{
ClaimData: types.ClaimData{
Bond: big.NewInt(9),
},
Claimant: common.Address{0x03},
CounteredBy: common.Address{},
},
},
Credits: map[common.Address]*big.Int{
common.Address{0x01}: big.NewInt(4),
common.Address{0x04}: big.NewInt(1),
},
WETHContract: weth1,
ETHCollateral: weth1Balance,
} }
results[i] = credit game3 := &monTypes.EnrichedGameData{
Claims: []types.Claim{
{
ClaimData: types.ClaimData{
Bond: big.NewInt(23),
},
Claimant: common.Address{0x03},
CounteredBy: common.Address{},
},
},
Credits: map[common.Address]*big.Int{
common.Address{0x01}: big.NewInt(46),
},
WETHContract: weth2,
ETHCollateral: weth2Balance,
} }
return results, nil actual := CalculateRequiredCollateral([]*monTypes.EnrichedGameData{game1, game2, game3})
require.Len(t, actual, 2)
require.Contains(t, actual, weth1)
require.Contains(t, actual, weth2)
require.Equal(t, actual[weth1].Required.Uint64(), uint64(5+7+2+3+6+9+4+1))
require.Equal(t, actual[weth1].Actual.Uint64(), weth1Balance.Uint64())
require.Equal(t, actual[weth2].Required.Uint64(), uint64(23+46))
require.Equal(t, actual[weth2].Actual.Uint64(), weth2Balance.Uint64())
} }
...@@ -3,7 +3,6 @@ package bonds ...@@ -3,7 +3,6 @@ package bonds
import ( import (
"math/big" "math/big"
"github.com/ethereum-optimism/optimism/op-dispute-mon/mon/transform"
"github.com/ethereum-optimism/optimism/op-dispute-mon/mon/types" "github.com/ethereum-optimism/optimism/op-dispute-mon/mon/types"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
...@@ -26,7 +25,7 @@ func NewBonds(logger log.Logger, metrics BondMetrics) *Bonds { ...@@ -26,7 +25,7 @@ func NewBonds(logger log.Logger, metrics BondMetrics) *Bonds {
} }
func (b *Bonds) CheckBonds(games []*types.EnrichedGameData) { func (b *Bonds) CheckBonds(games []*types.EnrichedGameData) {
data := transform.CalculateRequiredCollateral(games) data := CalculateRequiredCollateral(games)
for addr, collateral := range data { for addr, collateral := range data {
b.metrics.RecordBondCollateral(addr, collateral.Required, collateral.Actual) b.metrics.RecordBondCollateral(addr, collateral.Required, collateral.Actual)
} }
......
...@@ -4,7 +4,6 @@ import ( ...@@ -4,7 +4,6 @@ import (
"math/big" "math/big"
"testing" "testing"
"github.com/ethereum-optimism/optimism/op-dispute-mon/mon/transform"
monTypes "github.com/ethereum-optimism/optimism/op-dispute-mon/mon/types" monTypes "github.com/ethereum-optimism/optimism/op-dispute-mon/mon/types"
"github.com/ethereum-optimism/optimism/op-service/testlog" "github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
...@@ -33,7 +32,7 @@ func TestCheckBonds(t *testing.T) { ...@@ -33,7 +32,7 @@ func TestCheckBonds(t *testing.T) {
} }
logger := testlog.Logger(t, log.LvlInfo) logger := testlog.Logger(t, log.LvlInfo)
metrics := &stubBondMetrics{recorded: make(map[common.Address]transform.Collateral)} metrics := &stubBondMetrics{recorded: make(map[common.Address]Collateral)}
bonds := NewBonds(logger, metrics) bonds := NewBonds(logger, metrics)
bonds.CheckBonds([]*monTypes.EnrichedGameData{game1, game2}) bonds.CheckBonds([]*monTypes.EnrichedGameData{game1, game2})
...@@ -48,11 +47,11 @@ func TestCheckBonds(t *testing.T) { ...@@ -48,11 +47,11 @@ func TestCheckBonds(t *testing.T) {
} }
type stubBondMetrics struct { type stubBondMetrics struct {
recorded map[common.Address]transform.Collateral recorded map[common.Address]Collateral
} }
func (s *stubBondMetrics) RecordBondCollateral(addr common.Address, required *big.Int, available *big.Int) { func (s *stubBondMetrics) RecordBondCollateral(addr common.Address, required *big.Int, available *big.Int) {
s.recorded[addr] = transform.Collateral{ s.recorded[addr] = Collateral{
Required: required, Required: required,
Actual: available, Actual: available,
} }
......
package transform
import (
"math/big"
monTypes "github.com/ethereum-optimism/optimism/op-dispute-mon/mon/types"
"github.com/ethereum/go-ethereum/common"
)
type Collateral struct {
// Required is the amount of collateral required to pay out bonds.
Required *big.Int
// Actual is the amount of collateral actually head by the DelayedWETH contract
Actual *big.Int
}
// CalculateRequiredCollateral determines the minimum balance required for each DelayedWETH contract used by a set
// of dispute games.
// Returns a map of DelayedWETH contract address to collateral data (required and actual amounts)
func CalculateRequiredCollateral(games []*monTypes.EnrichedGameData) map[common.Address]Collateral {
result := make(map[common.Address]Collateral)
for _, game := range games {
collateral, ok := result[game.WETHContract]
if !ok {
collateral = Collateral{
Required: big.NewInt(0),
Actual: game.ETHCollateral,
}
}
gameRequired := requiredCollateralForGame(game)
collateral.Required = new(big.Int).Add(collateral.Required, gameRequired)
result[game.WETHContract] = collateral
}
return result
}
func requiredCollateralForGame(game *monTypes.EnrichedGameData) *big.Int {
required := big.NewInt(0)
for _, claim := range game.Claims {
if monTypes.ResolvedBondAmount.Cmp(claim.Bond) != 0 {
required = new(big.Int).Add(required, claim.Bond)
}
}
for _, unclaimedCredit := range game.Credits {
required = new(big.Int).Add(required, unclaimedCredit)
}
return required
}
package transform
import (
"math/big"
"testing"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
monTypes "github.com/ethereum-optimism/optimism/op-dispute-mon/mon/types"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
func TestCalculateRequiredCollateral(t *testing.T) {
weth1 := common.Address{0x1a}
weth1Balance := big.NewInt(4200)
weth2 := common.Address{0x2b}
weth2Balance := big.NewInt(6000)
game1 := &monTypes.EnrichedGameData{
Claims: []types.Claim{
{
ClaimData: types.ClaimData{
Bond: monTypes.ResolvedBondAmount,
},
Claimant: common.Address{0x01},
CounteredBy: common.Address{0x02},
},
{
ClaimData: types.ClaimData{
Bond: big.NewInt(5),
},
Claimant: common.Address{0x03},
CounteredBy: common.Address{},
},
{
ClaimData: types.ClaimData{
Bond: big.NewInt(7),
},
Claimant: common.Address{0x03},
CounteredBy: common.Address{},
},
},
Credits: map[common.Address]*big.Int{
common.Address{0x01}: big.NewInt(2),
common.Address{0x04}: big.NewInt(3),
},
WETHContract: weth1,
ETHCollateral: weth1Balance,
}
game2 := &monTypes.EnrichedGameData{
Claims: []types.Claim{
{
ClaimData: types.ClaimData{
Bond: monTypes.ResolvedBondAmount,
},
Claimant: common.Address{0x01},
CounteredBy: common.Address{0x02},
},
{
ClaimData: types.ClaimData{
Bond: big.NewInt(6),
},
Claimant: common.Address{0x03},
CounteredBy: common.Address{},
},
{
ClaimData: types.ClaimData{
Bond: big.NewInt(9),
},
Claimant: common.Address{0x03},
CounteredBy: common.Address{},
},
},
Credits: map[common.Address]*big.Int{
common.Address{0x01}: big.NewInt(4),
common.Address{0x04}: big.NewInt(1),
},
WETHContract: weth1,
ETHCollateral: weth1Balance,
}
game3 := &monTypes.EnrichedGameData{
Claims: []types.Claim{
{
ClaimData: types.ClaimData{
Bond: big.NewInt(23),
},
Claimant: common.Address{0x03},
CounteredBy: common.Address{},
},
},
Credits: map[common.Address]*big.Int{
common.Address{0x01}: big.NewInt(46),
},
WETHContract: weth2,
ETHCollateral: weth2Balance,
}
actual := CalculateRequiredCollateral([]*monTypes.EnrichedGameData{game1, game2, game3})
require.Len(t, actual, 2)
require.Contains(t, actual, weth1)
require.Contains(t, actual, weth2)
require.Equal(t, actual[weth1].Required.Uint64(), uint64(5+7+2+3+6+9+4+1))
require.Equal(t, actual[weth1].Actual.Uint64(), weth1Balance.Uint64())
require.Equal(t, actual[weth2].Required.Uint64(), uint64(23+46))
require.Equal(t, actual[weth2].Actual.Uint64(), weth2Balance.Uint64())
}
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