mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-25 07:45:18 +00:00
435 lines
13 KiB
Go
435 lines
13 KiB
Go
|
package app_test
|
||
|
|
||
|
import (
|
||
|
"strconv"
|
||
|
"testing"
|
||
|
"time"
|
||
|
|
||
|
sdkmath "cosmossdk.io/math"
|
||
|
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
|
||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||
|
"github.com/kava-labs/kava/app"
|
||
|
evmutiltypes "github.com/kava-labs/kava/x/evmutil/types"
|
||
|
precisebankkeeper "github.com/kava-labs/kava/x/precisebank/keeper"
|
||
|
precisebanktypes "github.com/kava-labs/kava/x/precisebank/types"
|
||
|
"github.com/stretchr/testify/require"
|
||
|
)
|
||
|
|
||
|
func TestMigrateEvmutilToPrecisebank(t *testing.T) {
|
||
|
// Full test case with all components together
|
||
|
tests := []struct {
|
||
|
name string
|
||
|
initialReserve sdkmath.Int
|
||
|
fractionalBalances []sdkmath.Int
|
||
|
}{
|
||
|
{
|
||
|
"no fractional balances",
|
||
|
sdkmath.NewInt(0),
|
||
|
[]sdkmath.Int{},
|
||
|
},
|
||
|
{
|
||
|
"sufficient reserve, 0 remainder",
|
||
|
// Accounts adding up to 2 int units, same as reserve
|
||
|
sdkmath.NewInt(2),
|
||
|
[]sdkmath.Int{
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"insufficient reserve, 0 remainder",
|
||
|
// Accounts adding up to 2 int units, but only 1 int unit in reserve
|
||
|
sdkmath.NewInt(1),
|
||
|
[]sdkmath.Int{
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"excess reserve, 0 remainder",
|
||
|
// Accounts adding up to 2 int units, but 3 int unit in reserve
|
||
|
sdkmath.NewInt(3),
|
||
|
[]sdkmath.Int{
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"sufficient reserve, non-zero remainder",
|
||
|
// Accounts adding up to 1.5 int units, same as reserve
|
||
|
sdkmath.NewInt(2),
|
||
|
[]sdkmath.Int{
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"insufficient reserve, non-zero remainder",
|
||
|
// Accounts adding up to 1.5 int units, less than reserve,
|
||
|
// Reserve should be 2 and remainder 0.5
|
||
|
sdkmath.NewInt(1),
|
||
|
[]sdkmath.Int{
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"excess reserve, non-zero remainder",
|
||
|
// Accounts adding up to 1.5 int units, 3 int units in reserve
|
||
|
sdkmath.NewInt(3),
|
||
|
[]sdkmath.Int{
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for _, tt := range tests {
|
||
|
t.Run(tt.name, func(t *testing.T) {
|
||
|
tApp := app.NewTestApp()
|
||
|
tApp.InitializeFromGenesisStates()
|
||
|
ctx := tApp.NewContext(true, tmproto.Header{Height: 1, Time: time.Now()})
|
||
|
|
||
|
ak := tApp.GetAccountKeeper()
|
||
|
bk := tApp.GetBankKeeper()
|
||
|
evmuk := tApp.GetEvmutilKeeper()
|
||
|
pbk := tApp.GetPrecisebankKeeper()
|
||
|
|
||
|
reserveCoin := sdk.NewCoin(precisebanktypes.IntegerCoinDenom, tt.initialReserve)
|
||
|
err := bk.MintCoins(ctx, evmutiltypes.ModuleName, sdk.NewCoins(reserveCoin))
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
oldReserveAddr := tApp.GetAccountKeeper().GetModuleAddress(evmutiltypes.ModuleName)
|
||
|
newReserveAddr := tApp.GetAccountKeeper().GetModuleAddress(precisebanktypes.ModuleName)
|
||
|
|
||
|
// Double check balances
|
||
|
oldReserveBalance := bk.GetBalance(ctx, oldReserveAddr, precisebanktypes.IntegerCoinDenom)
|
||
|
newReserveBalance := bk.GetBalance(ctx, newReserveAddr, precisebanktypes.IntegerCoinDenom)
|
||
|
|
||
|
require.Equal(t, tt.initialReserve, oldReserveBalance.Amount, "initial x/evmutil reserve balance")
|
||
|
require.True(t, newReserveBalance.IsZero(), "empty initial new reserve")
|
||
|
|
||
|
// Set accounts
|
||
|
for i, balance := range tt.fractionalBalances {
|
||
|
addr := sdk.AccAddress([]byte(strconv.Itoa(i)))
|
||
|
|
||
|
err := evmuk.SetBalance(ctx, addr, balance)
|
||
|
require.NoError(t, err)
|
||
|
}
|
||
|
|
||
|
// Run full x/evmutil -> x/precisebank migration
|
||
|
err = app.MigrateEvmutilToPrecisebank(
|
||
|
ctx,
|
||
|
ak,
|
||
|
bk,
|
||
|
evmuk,
|
||
|
pbk,
|
||
|
)
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
// Check old reserve is empty
|
||
|
oldReserveBalanceAfter := bk.GetBalance(ctx, oldReserveAddr, precisebanktypes.IntegerCoinDenom)
|
||
|
require.True(t, oldReserveBalanceAfter.IsZero(), "old reserve should be empty")
|
||
|
|
||
|
// Check new reserve fully backs fractional balances
|
||
|
newReserveBalanceAfter := bk.GetBalance(ctx, newReserveAddr, precisebanktypes.IntegerCoinDenom)
|
||
|
fractionalBalanceTotal := pbk.GetTotalSumFractionalBalances(ctx)
|
||
|
remainder := pbk.GetRemainderAmount(ctx)
|
||
|
|
||
|
expectedReserveBal := fractionalBalanceTotal.Add(remainder)
|
||
|
require.Equal(
|
||
|
t,
|
||
|
expectedReserveBal,
|
||
|
newReserveBalanceAfter.Amount.Mul(precisebanktypes.ConversionFactor()),
|
||
|
"new reserve should equal total fractional balances",
|
||
|
)
|
||
|
|
||
|
// Check balances are deleted in evmutil and migrated to precisebank
|
||
|
for i := range tt.fractionalBalances {
|
||
|
addr := sdk.AccAddress([]byte(strconv.Itoa(i)))
|
||
|
acc := evmuk.GetAccount(ctx, addr)
|
||
|
require.Nil(t, acc, "account should be deleted")
|
||
|
|
||
|
balance := pbk.GetFractionalBalance(ctx, addr)
|
||
|
require.Equal(t, tt.fractionalBalances[i], balance, "balance should be migrated")
|
||
|
}
|
||
|
|
||
|
// Checks balances valid and remainder
|
||
|
res, stop := precisebankkeeper.AllInvariants(pbk)(ctx)
|
||
|
require.Falsef(t, stop, "invariants should pass: %s", res)
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestTransferFractionalBalances(t *testing.T) {
|
||
|
tests := []struct {
|
||
|
name string
|
||
|
fractionalBalances []sdkmath.Int
|
||
|
}{
|
||
|
{
|
||
|
"no fractional balances",
|
||
|
[]sdkmath.Int{},
|
||
|
},
|
||
|
{
|
||
|
"balanced fractional balances",
|
||
|
[]sdkmath.Int{
|
||
|
// 4 accounts
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"unbalanced balances",
|
||
|
[]sdkmath.Int{
|
||
|
// 3 accounts
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for _, tt := range tests {
|
||
|
t.Run(tt.name, func(t *testing.T) {
|
||
|
tApp := app.NewTestApp()
|
||
|
tApp.InitializeFromGenesisStates()
|
||
|
ctx := tApp.NewContext(true, tmproto.Header{Height: 1, Time: time.Now()})
|
||
|
|
||
|
evmutilk := tApp.GetEvmutilKeeper()
|
||
|
pbk := tApp.GetPrecisebankKeeper()
|
||
|
|
||
|
for i, balance := range tt.fractionalBalances {
|
||
|
addr := sdk.AccAddress([]byte(strconv.Itoa(i)))
|
||
|
|
||
|
err := evmutilk.SetBalance(ctx, addr, balance)
|
||
|
require.NoError(t, err)
|
||
|
}
|
||
|
|
||
|
// Run balance transfer
|
||
|
aggregateSum, err := app.TransferFractionalBalances(
|
||
|
ctx,
|
||
|
evmutilk,
|
||
|
pbk,
|
||
|
)
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
// Check balances are deleted in evmutil and migrated to precisebank
|
||
|
sum := sdkmath.ZeroInt()
|
||
|
for i := range tt.fractionalBalances {
|
||
|
sum = sum.Add(tt.fractionalBalances[i])
|
||
|
|
||
|
addr := sdk.AccAddress([]byte(strconv.Itoa(i)))
|
||
|
acc := evmutilk.GetAccount(ctx, addr)
|
||
|
require.Nil(t, acc, "account should be deleted")
|
||
|
|
||
|
balance := pbk.GetFractionalBalance(ctx, addr)
|
||
|
require.Equal(t, tt.fractionalBalances[i], balance, "balance should be migrated")
|
||
|
}
|
||
|
|
||
|
require.Equal(t, sum, aggregateSum, "aggregate sum should be correct")
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestInitializeRemainder(t *testing.T) {
|
||
|
tests := []struct {
|
||
|
name string
|
||
|
giveAggregateSum sdkmath.Int
|
||
|
wantRemainder sdkmath.Int
|
||
|
}{
|
||
|
{
|
||
|
"0 remainder, 1ukava",
|
||
|
precisebanktypes.ConversionFactor(),
|
||
|
sdkmath.NewInt(0),
|
||
|
},
|
||
|
{
|
||
|
"0 remainder, multiple ukava",
|
||
|
precisebanktypes.ConversionFactor().MulRaw(5),
|
||
|
sdkmath.NewInt(0),
|
||
|
},
|
||
|
{
|
||
|
"non-zero remainder, min",
|
||
|
precisebanktypes.ConversionFactor().SubRaw(1),
|
||
|
sdkmath.NewInt(1),
|
||
|
},
|
||
|
{
|
||
|
"non-zero remainder, max",
|
||
|
sdkmath.NewInt(1),
|
||
|
precisebanktypes.ConversionFactor().SubRaw(1),
|
||
|
},
|
||
|
{
|
||
|
"non-zero remainder, half",
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for _, tt := range tests {
|
||
|
t.Run(tt.name, func(t *testing.T) {
|
||
|
tApp := app.NewTestApp()
|
||
|
tApp.InitializeFromGenesisStates()
|
||
|
|
||
|
pbk := tApp.GetPrecisebankKeeper()
|
||
|
|
||
|
ctx := tApp.NewContext(true, tmproto.Header{Height: 1, Time: time.Now()})
|
||
|
|
||
|
remainder := app.InitializeRemainder(
|
||
|
ctx,
|
||
|
tApp.GetPrecisebankKeeper(),
|
||
|
tt.giveAggregateSum,
|
||
|
)
|
||
|
require.Equal(t, tt.wantRemainder, remainder)
|
||
|
|
||
|
// Check actual state
|
||
|
remainderAfter := pbk.GetRemainderAmount(ctx)
|
||
|
require.Equal(t, tt.wantRemainder, remainderAfter)
|
||
|
|
||
|
// Not checking invariants here since it requires actual balance state
|
||
|
aggregateSumWithRemainder := tt.giveAggregateSum.Add(remainder)
|
||
|
require.True(
|
||
|
t,
|
||
|
aggregateSumWithRemainder.
|
||
|
Mod(precisebanktypes.ConversionFactor()).
|
||
|
IsZero(),
|
||
|
"remainder + aggregate sum should be a multiple of the conversion factor",
|
||
|
)
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestTransferFractionalBalanceReserve(t *testing.T) {
|
||
|
tests := []struct {
|
||
|
name string
|
||
|
initialReserve sdk.Coin
|
||
|
fractionalBalances []sdkmath.Int
|
||
|
}{
|
||
|
{
|
||
|
"balanced reserve, no remainder",
|
||
|
sdk.NewCoin(precisebanktypes.IntegerCoinDenom, sdk.NewInt(1)),
|
||
|
[]sdkmath.Int{
|
||
|
// 2 accounts
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"insufficient reserve",
|
||
|
sdk.NewCoin(precisebanktypes.IntegerCoinDenom, sdk.NewInt(1)),
|
||
|
[]sdkmath.Int{
|
||
|
// 4 accounts, total 2 int units
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"extra reserve funds",
|
||
|
sdk.NewCoin(precisebanktypes.IntegerCoinDenom, sdk.NewInt(2)),
|
||
|
[]sdkmath.Int{
|
||
|
// 2 accounts, total 1 int units
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"insufficient reserve, with remainder",
|
||
|
sdk.NewCoin(precisebanktypes.IntegerCoinDenom, sdk.NewInt(1)),
|
||
|
[]sdkmath.Int{
|
||
|
// 5 accounts, total 2.5 int units
|
||
|
// Expected 3 int units in reserve, 0.5 remainder
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"extra reserve funds, with remainder",
|
||
|
sdk.NewCoin(precisebanktypes.IntegerCoinDenom, sdk.NewInt(3)),
|
||
|
[]sdkmath.Int{
|
||
|
// 3 accounts, total 1.5 int units.
|
||
|
// Expected 2 int units in reserve, 0.5 remainder
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
precisebanktypes.ConversionFactor().QuoRaw(2),
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for _, tt := range tests {
|
||
|
t.Run(tt.name, func(t *testing.T) {
|
||
|
tApp := app.NewTestApp()
|
||
|
tApp.InitializeFromGenesisStates()
|
||
|
ctx := tApp.NewContext(true, tmproto.Header{Height: 1, Time: time.Now()})
|
||
|
|
||
|
bk := tApp.GetBankKeeper()
|
||
|
pbk := tApp.GetPrecisebankKeeper()
|
||
|
err := bk.MintCoins(ctx, evmutiltypes.ModuleName, sdk.NewCoins(tt.initialReserve))
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
oldReserveAddr := tApp.GetAccountKeeper().GetModuleAddress(evmutiltypes.ModuleName)
|
||
|
newReserveAddr := tApp.GetAccountKeeper().GetModuleAddress(precisebanktypes.ModuleName)
|
||
|
|
||
|
// Double check balances
|
||
|
oldReserveBalance := bk.GetBalance(ctx, oldReserveAddr, precisebanktypes.IntegerCoinDenom)
|
||
|
newReserveBalance := bk.GetBalance(ctx, newReserveAddr, precisebanktypes.IntegerCoinDenom)
|
||
|
|
||
|
require.Equal(t, tt.initialReserve, oldReserveBalance)
|
||
|
require.True(t, newReserveBalance.IsZero(), "empty initial new reserve")
|
||
|
|
||
|
for i, balance := range tt.fractionalBalances {
|
||
|
addr := sdk.AccAddress([]byte{byte(i)})
|
||
|
|
||
|
require.NotPanics(t, func() {
|
||
|
pbk.SetFractionalBalance(ctx, addr, balance)
|
||
|
}, "given fractional balances should be valid")
|
||
|
}
|
||
|
|
||
|
// Run reserve migration
|
||
|
err = app.TransferFractionalBalanceReserve(
|
||
|
ctx,
|
||
|
tApp.GetAccountKeeper(),
|
||
|
bk,
|
||
|
tApp.GetPrecisebankKeeper(),
|
||
|
)
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
// Check old reserve is empty
|
||
|
oldReserveBalanceAfter := bk.GetBalance(ctx, oldReserveAddr, precisebanktypes.IntegerCoinDenom)
|
||
|
require.True(t, oldReserveBalanceAfter.IsZero(), "old reserve should be empty")
|
||
|
|
||
|
// Check new reserve fully backs fractional balances
|
||
|
newReserveBalanceAfter := bk.GetBalance(ctx, newReserveAddr, precisebanktypes.IntegerCoinDenom)
|
||
|
fractionalBalanceTotal := pbk.GetTotalSumFractionalBalances(ctx)
|
||
|
|
||
|
expectedReserveBal := fractionalBalanceTotal.
|
||
|
Quo(precisebanktypes.ConversionFactor())
|
||
|
|
||
|
// Check if theres a remainder
|
||
|
if fractionalBalanceTotal.Mod(precisebanktypes.ConversionFactor()).IsPositive() {
|
||
|
expectedReserveBal = expectedReserveBal.Add(sdkmath.OneInt())
|
||
|
}
|
||
|
|
||
|
require.Equal(
|
||
|
t,
|
||
|
expectedReserveBal,
|
||
|
newReserveBalanceAfter.Amount,
|
||
|
"new reserve should equal total fractional balances + remainder",
|
||
|
)
|
||
|
})
|
||
|
}
|
||
|
}
|