laconicd/x/evm/keeper/invariants.go
Federico Kunze a1386eec09
evm: balance and nonce invariants (#661)
* evm: balance and nonce invariants

* nonce invariant

* changelog

* use iterator on export
2020-12-15 19:43:06 +01:00

101 lines
2.5 KiB
Go

package keeper
import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
ethermint "github.com/cosmos/ethermint/types"
"github.com/cosmos/ethermint/x/evm/types"
)
const (
balanceInvariant = "balance"
nonceInvariant = "nonce"
)
// RegisterInvariants registers the evm module invariants
func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper) {
ir.RegisterRoute(types.ModuleName, balanceInvariant, k.BalanceInvariant())
ir.RegisterRoute(types.ModuleName, nonceInvariant, k.NonceInvariant())
}
// BalanceInvariant checks that all auth module's EthAccounts in the application have the same balance
// as the EVM one.
func (k Keeper) BalanceInvariant() sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
var (
msg string
count int
)
k.accountKeeper.IterateAccounts(ctx, func(account authexported.Account) bool {
ethAccount, ok := account.(*ethermint.EthAccount)
if !ok {
// ignore non EthAccounts
return false
}
evmDenom := k.GetParams(ctx).EvmDenom
accountBalance := ethAccount.GetCoins().AmountOf(evmDenom)
evmBalance := k.GetBalance(ctx, ethAccount.EthAddress())
if evmBalance.Cmp(accountBalance.BigInt()) != 0 {
count++
msg += fmt.Sprintf(
"\tbalance mismatch for address %s: account balance %s, evm balance %s\n",
account.GetAddress(), accountBalance.String(), evmBalance.String(),
)
}
return false
})
broken := count != 0
return sdk.FormatInvariant(
types.ModuleName, balanceInvariant,
fmt.Sprintf("account balances mismatches found %d\n%s", count, msg),
), broken
}
}
// NonceInvariant checks that all auth module's EthAccounts in the application have the same nonce
// sequence as the EVM.
func (k Keeper) NonceInvariant() sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
var (
msg string
count int
)
k.accountKeeper.IterateAccounts(ctx, func(account authexported.Account) bool {
ethAccount, ok := account.(*ethermint.EthAccount)
if !ok {
// ignore non EthAccounts
return false
}
evmNonce := k.GetNonce(ctx, ethAccount.EthAddress())
if evmNonce != ethAccount.Sequence {
count++
msg += fmt.Sprintf(
"\nonce mismatch for address %s: account nonce %d, evm nonce %d\n",
account.GetAddress(), ethAccount.Sequence, evmNonce,
)
}
return false
})
broken := count != 0
return sdk.FormatInvariant(
types.ModuleName, nonceInvariant,
fmt.Sprintf("account nonces mismatches found %d\n%s", count, msg),
), broken
}
}