0g-chain/x/evmutil/keeper/keeper_test.go
2024-08-03 15:03:23 +08:00

440 lines
10 KiB
Go

package keeper_test
import (
"testing"
sdkmath "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/suite"
"github.com/0glabs/0g-chain/x/evmutil/testutil"
"github.com/0glabs/0g-chain/x/evmutil/types"
)
type keeperTestSuite struct {
testutil.Suite
}
func (suite *keeperTestSuite) SetupTest() {
suite.Suite.SetupTest()
}
func (suite *keeperTestSuite) TestGetAllAccounts() {
tests := []struct {
name string
expAccounts []types.Account
}{
{
"no accounts",
[]types.Account{},
},
{
"with accounts",
[]types.Account{
{Address: suite.Addrs[0], Balance: sdkmath.NewInt(100)},
{Address: suite.Addrs[1], Balance: sdkmath.NewInt(200)},
},
},
}
for _, tt := range tests {
suite.Run(tt.name, func() {
suite.SetupTest()
for _, account := range tt.expAccounts {
suite.Keeper.SetBalance(suite.Ctx, account.Address, account.Balance)
}
accounts := suite.Suite.Keeper.GetAllAccounts(suite.Ctx)
if len(tt.expAccounts) == 0 {
suite.Require().Len(tt.expAccounts, 0)
} else {
suite.Require().Equal(tt.expAccounts, accounts)
}
})
}
}
func (suite *keeperTestSuite) TestSetAccount_ZeroBalance() {
existingAccount := types.Account{
Address: suite.Addrs[0],
Balance: sdkmath.NewInt(100),
}
err := suite.Keeper.SetAccount(suite.Ctx, existingAccount)
suite.Require().NoError(err)
err = suite.Keeper.SetAccount(suite.Ctx, types.Account{
Address: suite.Addrs[0],
Balance: sdk.ZeroInt(),
})
suite.Require().NoError(err)
bal := suite.Keeper.GetBalance(suite.Ctx, suite.Addrs[0])
suite.Require().Equal(sdk.ZeroInt(), bal)
expAcct := suite.Keeper.GetAccount(suite.Ctx, suite.Addrs[0])
suite.Require().Nil(expAcct)
}
func (suite *keeperTestSuite) TestSetAccount() {
existingAccount := types.Account{
Address: suite.Addrs[0],
Balance: sdkmath.NewInt(100),
}
tests := []struct {
name string
account types.Account
success bool
}{
{
"invalid address",
types.Account{Address: nil, Balance: sdkmath.NewInt(100)},
false,
},
{
"invalid balance",
types.Account{Address: suite.Addrs[0], Balance: sdkmath.NewInt(-100)},
false,
},
{
"empty account",
types.Account{},
false,
},
{
"valid account",
types.Account{Address: suite.Addrs[1], Balance: sdkmath.NewInt(100)},
true,
},
{
"replaces account",
types.Account{Address: suite.Addrs[0], Balance: sdkmath.NewInt(50)},
true,
},
}
for _, tt := range tests {
suite.Run(tt.name, func() {
suite.SetupTest()
err := suite.Keeper.SetAccount(suite.Ctx, existingAccount)
suite.Require().NoError(err)
err = suite.Keeper.SetAccount(suite.Ctx, tt.account)
if tt.success {
suite.Require().NoError(err)
expAcct := suite.Keeper.GetAccount(suite.Ctx, tt.account.Address)
suite.Require().Equal(tt.account, *expAcct)
} else {
suite.Require().Error(err)
suite.Require().Nil(suite.Keeper.GetAccount(suite.Ctx, suite.Addrs[1]))
}
})
}
}
func (suite *keeperTestSuite) TestSendBalance() {
startingSenderBal := sdkmath.NewInt(100)
startingRecipientBal := sdkmath.NewInt(50)
tests := []struct {
name string
amt sdkmath.Int
expSenderBal sdkmath.Int
expRecipientBal sdkmath.Int
success bool
}{
{
"fails when sending negative amount",
sdkmath.NewInt(-5),
sdk.ZeroInt(),
sdk.ZeroInt(),
false,
},
{
"send zero amount",
sdk.ZeroInt(),
startingSenderBal,
startingRecipientBal,
true,
},
{
"fails when sender does not have enough balance",
sdkmath.NewInt(101),
sdk.ZeroInt(),
sdk.ZeroInt(),
false,
},
{
"send valid amount",
sdkmath.NewInt(80),
sdkmath.NewInt(20),
sdkmath.NewInt(130),
true,
},
}
for _, tt := range tests {
suite.Run(tt.name, func() {
suite.SetupTest()
err := suite.Keeper.SetBalance(suite.Ctx, suite.Addrs[0], startingSenderBal)
suite.Require().NoError(err)
err = suite.Keeper.SetBalance(suite.Ctx, suite.Addrs[1], startingRecipientBal)
suite.Require().NoError(err)
err = suite.Keeper.SendBalance(suite.Ctx, suite.Addrs[0], suite.Addrs[1], tt.amt)
if tt.success {
suite.Require().NoError(err)
suite.Require().Equal(tt.expSenderBal, suite.Keeper.GetBalance(suite.Ctx, suite.Addrs[0]))
suite.Require().Equal(tt.expRecipientBal, suite.Keeper.GetBalance(suite.Ctx, suite.Addrs[1]))
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *keeperTestSuite) TestSetBalance() {
existingAccount := types.Account{
Address: suite.Addrs[0],
Balance: sdkmath.NewInt(100),
}
tests := []struct {
name string
address sdk.AccAddress
balance sdkmath.Int
success bool
}{
{
"invalid balance",
suite.Addrs[0],
sdkmath.NewInt(-100),
false,
},
{
"set new account balance",
suite.Addrs[1],
sdkmath.NewInt(100),
true,
},
{
"replace account balance",
suite.Addrs[0],
sdkmath.NewInt(50),
true,
},
{
"invalid address",
nil,
sdkmath.NewInt(100),
false,
},
{
"zero balance",
suite.Addrs[0],
sdk.ZeroInt(),
true,
},
}
for _, tt := range tests {
suite.Run(tt.name, func() {
suite.SetupTest()
err := suite.Keeper.SetAccount(suite.Ctx, existingAccount)
suite.Require().NoError(err)
err = suite.Keeper.SetBalance(suite.Ctx, tt.address, tt.balance)
if tt.success {
suite.Require().NoError(err)
expBal := suite.Keeper.GetBalance(suite.Ctx, tt.address)
suite.Require().Equal(expBal, tt.balance)
if tt.balance.IsZero() {
account := suite.Keeper.GetAccount(suite.Ctx, tt.address)
suite.Require().Nil(account)
}
} else {
suite.Require().Error(err)
expBal := suite.Keeper.GetBalance(suite.Ctx, existingAccount.Address)
suite.Require().Equal(expBal, existingAccount.Balance)
}
})
}
}
func (suite *keeperTestSuite) TestRemoveBalance() {
existingAccount := types.Account{
Address: suite.Addrs[0],
Balance: sdkmath.NewInt(100),
}
tests := []struct {
name string
amt sdkmath.Int
expBal sdkmath.Int
success bool
}{
{
"fails if amount is negative",
sdkmath.NewInt(-10),
sdk.ZeroInt(),
false,
},
{
"remove zero amount",
sdk.ZeroInt(),
existingAccount.Balance,
true,
},
{
"not enough balance",
sdkmath.NewInt(101),
sdk.ZeroInt(),
false,
},
{
"remove full balance",
sdkmath.NewInt(100),
sdk.ZeroInt(),
true,
},
{
"remove some balance",
sdkmath.NewInt(10),
sdkmath.NewInt(90),
true,
},
}
for _, tt := range tests {
suite.Run(tt.name, func() {
suite.SetupTest()
err := suite.Keeper.SetAccount(suite.Ctx, existingAccount)
suite.Require().NoError(err)
err = suite.Keeper.RemoveBalance(suite.Ctx, existingAccount.Address, tt.amt)
if tt.success {
suite.Require().NoError(err)
expBal := suite.Keeper.GetBalance(suite.Ctx, existingAccount.Address)
suite.Require().Equal(expBal, tt.expBal)
} else {
suite.Require().Error(err)
expBal := suite.Keeper.GetBalance(suite.Ctx, existingAccount.Address)
suite.Require().Equal(expBal, existingAccount.Balance)
}
})
}
}
func (suite *keeperTestSuite) TestGetBalance() {
existingAccount := types.Account{
Address: suite.Addrs[0],
Balance: sdkmath.NewInt(100),
}
tests := []struct {
name string
addr sdk.AccAddress
expBal sdkmath.Int
}{
{
"returns 0 balance if account does not exist",
suite.Addrs[1],
sdk.ZeroInt(),
},
{
"returns account balance",
suite.Addrs[0],
sdkmath.NewInt(100),
},
}
for _, tt := range tests {
suite.Run(tt.name, func() {
suite.SetupTest()
err := suite.Keeper.SetAccount(suite.Ctx, existingAccount)
suite.Require().NoError(err)
balance := suite.Keeper.GetBalance(suite.Ctx, tt.addr)
suite.Require().Equal(tt.expBal, balance)
})
}
}
func (suite *keeperTestSuite) TestDeployedCosmosCoinContractStoreState() {
suite.Run("returns nil for nonexistent denom", func() {
suite.SetupTest()
addr, found := suite.Keeper.GetDeployedCosmosCoinContract(suite.Ctx, "undeployed-denom")
suite.False(found)
suite.Equal(addr, types.InternalEVMAddress{})
})
suite.Run("handles setting & getting a contract address", func() {
suite.SetupTest()
denom := "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2"
address := testutil.RandomInternalEVMAddress()
err := suite.Keeper.SetDeployedCosmosCoinContract(suite.Ctx, denom, address)
suite.NoError(err)
stored, found := suite.Keeper.GetDeployedCosmosCoinContract(suite.Ctx, denom)
suite.True(found)
suite.Equal(address, stored)
})
suite.Run("fails when setting an invalid denom", func() {
suite.SetupTest()
invalidDenom := ""
err := suite.Keeper.SetDeployedCosmosCoinContract(suite.Ctx, invalidDenom, testutil.RandomInternalEVMAddress())
suite.ErrorContains(err, "invalid cosmos denom")
})
suite.Run("fails when setting 0 address", func() {
suite.SetupTest()
invalidAddr := types.InternalEVMAddress{}
err := suite.Keeper.SetDeployedCosmosCoinContract(suite.Ctx, "denom", invalidAddr)
suite.ErrorContains(err, "attempting to register empty contract address")
})
}
func (suite *keeperTestSuite) TestIterateAllDeployedCosmosCoinContracts() {
suite.SetupTest()
address := testutil.RandomInternalEVMAddress()
denoms := []string{}
register := func(denom string) {
addr := testutil.RandomInternalEVMAddress()
if denom == "waldo" {
addr = address
}
err := suite.Keeper.SetDeployedCosmosCoinContract(suite.Ctx, denom, addr)
suite.NoError(err)
denoms = append(denoms, denom)
}
// register some contracts
register("magic")
register("popcorn")
register("waldo")
register("zzz")
register("ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2")
suite.Run("stops when told", func() {
// test out stopping the iteration
// NOTE: don't actually look for a single contract this way. the keys are deterministic by denom.
var contract types.DeployedCosmosCoinContract
suite.Keeper.IterateAllDeployedCosmosCoinContracts(suite.Ctx, func(c types.DeployedCosmosCoinContract) bool {
contract = c
return c.CosmosDenom == "waldo"
})
suite.Equal(types.NewDeployedCosmosCoinContract("waldo", address), contract)
})
suite.Run("iterates all contracts", func() {
foundDenoms := make([]string, 0, len(denoms))
suite.Keeper.IterateAllDeployedCosmosCoinContracts(suite.Ctx, func(c types.DeployedCosmosCoinContract) bool {
foundDenoms = append(foundDenoms, c.CosmosDenom)
return false
})
suite.Len(foundDenoms, len(denoms))
suite.ElementsMatch(denoms, foundDenoms)
})
}
func TestKeeperTestSuite(t *testing.T) {
suite.Run(t, new(keeperTestSuite))
}