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

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

parent 90552788
package bonds
import (
"context"
"fmt"
"math/big"
faultTypes "github.com/ethereum-optimism/optimism/op-challenger/game/fault/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"
"golang.org/x/exp/maps"
)
type BondContract interface {
GetCredits(ctx context.Context, block rpcblock.Block, recipients ...common.Address) ([]*big.Int, error)
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 a fault dispute game contract in order
// to pay the outstanding bonds and credits.
// It returns the sum of unpaid bonds from claims, plus the sum of allocated but unclaimed credits.
func CalculateRequiredCollateral(ctx context.Context, contract BondContract, blockHash common.Hash, claims []faultTypes.Claim) (*big.Int, error) {
unpaidBonds := big.NewInt(0)
recipients := make(map[common.Address]bool)
for _, claim := range claims {
if monTypes.ResolvedBondAmount.Cmp(claim.Bond) != 0 {
unpaidBonds = new(big.Int).Add(unpaidBonds, claim.Bond)
}
recipients[claim.Claimant] = true
if claim.CounteredBy != (common.Address{}) {
recipients[claim.CounteredBy] = true
// 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
}
credits, err := contract.GetCredits(ctx, rpcblock.ByHash(blockHash), maps.Keys(recipients)...)
if err != nil {
return nil, fmt.Errorf("failed to load credits: %w", err)
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 _, 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
import (
"context"
"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-optimism/optimism/op-service/sources/batching/rpcblock"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
func TestCalculateRequiredCollateral(t *testing.T) {
claims := []types.Claim{
{
ClaimData: types.ClaimData{
Bond: monTypes.ResolvedBondAmount,
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},
},
Claimant: common.Address{0x01},
CounteredBy: common.Address{0x02},
},
{
ClaimData: types.ClaimData{
Bond: big.NewInt(5),
{
ClaimData: types.ClaimData{
Bond: big.NewInt(5),
},
Claimant: common.Address{0x03},
CounteredBy: common.Address{},
},
Claimant: common.Address{0x03},
CounteredBy: common.Address{},
},
{
ClaimData: types.ClaimData{
Bond: big.NewInt(7),
{
ClaimData: types.ClaimData{
Bond: big.NewInt(7),
},
Claimant: common.Address{0x03},
CounteredBy: common.Address{},
},
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,
}
contract := &stubBondContract{
credits: map[common.Address]*big.Int{
{0x01}: big.NewInt(3),
{0x03}: big.NewInt(8),
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,
}
collateral, err := CalculateRequiredCollateral(context.Background(), contract, common.Hash{0xab}, claims)
require.NoError(t, err)
require.Equal(t, collateral.Int64(), int64(5+7+3+8))
}
type stubBondContract struct {
credits map[common.Address]*big.Int
}
func (s *stubBondContract) GetCredits(_ context.Context, _ rpcblock.Block, recipients ...common.Address) ([]*big.Int, error) {
results := make([]*big.Int, len(recipients))
for i, recipient := range recipients {
credit, ok := s.credits[recipient]
if !ok {
credit = big.NewInt(0)
}
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
import (
"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/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
......@@ -26,7 +25,7 @@ func NewBonds(logger log.Logger, metrics BondMetrics) *Bonds {
}
func (b *Bonds) CheckBonds(games []*types.EnrichedGameData) {
data := transform.CalculateRequiredCollateral(games)
data := CalculateRequiredCollateral(games)
for addr, collateral := range data {
b.metrics.RecordBondCollateral(addr, collateral.Required, collateral.Actual)
}
......
......@@ -4,7 +4,6 @@ import (
"math/big"
"testing"
"github.com/ethereum-optimism/optimism/op-dispute-mon/mon/transform"
monTypes "github.com/ethereum-optimism/optimism/op-dispute-mon/mon/types"
"github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/ethereum/go-ethereum/common"
......@@ -33,7 +32,7 @@ func TestCheckBonds(t *testing.T) {
}
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.CheckBonds([]*monTypes.EnrichedGameData{game1, game2})
......@@ -48,11 +47,11 @@ func TestCheckBonds(t *testing.T) {
}
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) {
s.recorded[addr] = transform.Collateral{
s.recorded[addr] = Collateral{
Required: required,
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