Skip to content

Commit

Permalink
feat(halo/evmstaking2): unit test for delegate event delivery (#2573)
Browse files Browse the repository at this point in the history
Implements the unit test for the delegate event delivery. At the end of
the test, we assert that the staking message server actually received
the message of the expected type.

issue: #2525
  • Loading branch information
chmllr authored Nov 27, 2024
1 parent cb1b529 commit 3612b46
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 36 deletions.
32 changes: 16 additions & 16 deletions halo/evmstaking2/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ import (
"cosmossdk.io/math"
"cosmossdk.io/orm/model/ormdb"
sdk "github.com/cosmos/cosmos-sdk/types"
akeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
bkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
skeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
stypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)

Expand All @@ -38,19 +35,21 @@ type Keeper struct {
ethCl ethclient.Client
address common.Address
contract *bindings.Staking
aKeeper akeeper.AccountKeeperI
bKeeper bkeeper.Keeper
sKeeper *skeeper.Keeper
submissionDelay int64
aKeeper types.AuthKeeper
bKeeper types.BankKeeper
sKeeper types.StakingKeeper
sServer types.StakingMsgServer
deliverInterval int64
}

func NewKeeper(
storeService store.KVStoreService,
ethCl ethclient.Client,
aKeeper akeeper.AccountKeeperI,
bKeeper bkeeper.Keeper,
sKeeper *skeeper.Keeper,
submissionDelay int64,
aKeeper types.AuthKeeper,
bKeeper types.BankKeeper,
sKeeper types.StakingKeeper,
sServer types.StakingMsgServer,
deliverInterval int64,
) (*Keeper, error) {
schema := &ormv1alpha1.ModuleSchemaDescriptor{SchemaFile: []*ormv1alpha1.ModuleSchemaDescriptor_FileEntry{
{Id: 1, ProtoFileName: File_halo_evmstaking2_keeper_evmstaking_proto.Path()},
Expand Down Expand Up @@ -78,17 +77,18 @@ func NewKeeper(
aKeeper: aKeeper,
bKeeper: bKeeper,
sKeeper: sKeeper,
sServer: sServer,
address: address,
contract: contract,
submissionDelay: submissionDelay,
deliverInterval: deliverInterval,
}, nil
}

// EndBlock delivers all pending EVM events on every `k.submissionDelay`'th block.
// EndBlock delivers all pending EVM events on every `k.deliverInterval`'th block.
func (k *Keeper) EndBlock(ctx context.Context) error {
blockHeight := sdk.UnwrapSDKContext(ctx).BlockHeight()

if blockHeight%k.submissionDelay != 0 {
if blockHeight%k.deliverInterval != 0 {
return nil
}

Expand Down Expand Up @@ -259,7 +259,7 @@ func (k Keeper) deliverDelegate(ctx context.Context, ev *bindings.StakingDelegat

// Validator already exists, add deposit to self delegation
msg := stypes.NewMsgDelegate(delAddr.String(), valAddr.String(), amountCoin)
_, err := skeeper.NewMsgServerImpl(k.sKeeper).Delegate(ctx, msg)
_, err := k.sServer.Delegate(ctx, msg)
if err != nil {
return errors.Wrap(err, "delegate")
}
Expand Down Expand Up @@ -320,7 +320,7 @@ func (k Keeper) deliverCreateValidator(ctx context.Context, ev *bindings.Staking
return errors.Wrap(err, "create validator message")
}

_, err = skeeper.NewMsgServerImpl(k.sKeeper).CreateValidator(ctx, msg)
_, err = k.sServer.CreateValidator(ctx, msg)
if err != nil {
return errors.Wrap(err, "create validator")
}
Expand Down
145 changes: 129 additions & 16 deletions halo/evmstaking2/keeper/keeper_internal_test.go
Original file line number Diff line number Diff line change
@@ -1,49 +1,56 @@
package keeper

import (
context "context"
"strings"
"testing"

"github.com/omni-network/omni/halo/evmstaking2/types"
"github.com/omni-network/omni/lib/ethclient"
"github.com/omni-network/omni/lib/netconf"
types "github.com/omni-network/omni/octane/evmengine/types"
etypes "github.com/omni-network/omni/octane/evmengine/types"

k1 "github.com/cometbft/cometbft/crypto/secp256k1"

"github.com/ethereum/go-ethereum/common"

storetypes "cosmossdk.io/store/types"
"github.com/cosmos/cosmos-sdk/runtime"
sdktestutil "github.com/cosmos/cosmos-sdk/testutil"
sdk "github.com/cosmos/cosmos-sdk/types"
stypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/stretchr/testify/require"
)

//nolint:paralleltest // Asserting insertion ids of sequential writes
func TestInsertEVMEvents(t *testing.T) {
func TestInsertAndDeleteEVMEvents(t *testing.T) {
tests := []struct {
name string
event types.EVMEvent
event etypes.EVMEvent
insertedID uint64
height int64
}{
{
name: "Insert event with address [1,2,3]",
event: types.EVMEvent{
event: etypes.EVMEvent{
Address: []byte{1, 2, 3},
},
insertedID: 1,
height: 0,
},
{
name: "Insert event with address [2,3,4]",
event: types.EVMEvent{
event: etypes.EVMEvent{
Address: []byte{2, 3, 4},
},
insertedID: 2,
height: 1,
},
}

submissionDelay := int64(5)
deliverInterval := int64(5)

keeper, ctx := setupKeeper(t, submissionDelay)
keeper, ctx := setupKeeper(t, deliverInterval, nil, nil, nil, nil, nil)

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
Expand All @@ -59,7 +66,7 @@ func TestInsertEVMEvents(t *testing.T) {
}

// Make sure no submission happens for heights in the range 2 to 4
for h := int64(2); h < keeper.submissionDelay; h++ {
for h := int64(2); h < keeper.deliverInterval; h++ {
ctx = ctx.WithBlockHeight(h)
err := keeper.EndBlock(ctx)
require.NoError(t, err)
Expand All @@ -72,8 +79,8 @@ func TestInsertEVMEvents(t *testing.T) {
require.True(t, found)
}

// Now "execute" block number `submissionDelay`
err := keeper.EndBlock(ctx.WithBlockHeight(submissionDelay))
// Now "execute" block number `deliverInterval`
err := keeper.EndBlock(ctx.WithBlockHeight(deliverInterval))
require.NoError(t, err)

// All events are deleted now
Expand All @@ -84,7 +91,69 @@ func TestInsertEVMEvents(t *testing.T) {
}
}

func setupKeeper(t *testing.T, submissionDelay int64) (*Keeper, sdk.Context) {
func TestDeliverDelegate(t *testing.T) {
t.Parallel()

deliverInterval := int64(3)
ethStake := int64(7)

ethClientMock, err := ethclient.NewEngineMock(
ethclient.WithPortalRegister(netconf.SimnetNetwork()),
ethclient.WithMockSelfDelegation(k1.GenPrivKey().PubKey(), ethStake),
)
require.NoError(t, err)

sServer := new(msgServerStub)

keeper, ctx := setupKeeper(t, deliverInterval, ethClientMock, new(authKeeperStub), new(bankKeeperStub), new(stakingKeeperStub), sServer)

var hash common.Hash
events, err := keeper.Prepare(ctx, hash)
require.NoError(t, err)

require.Len(t, events, 1)

for _, event := range events {
err := keeper.Deliver(ctx, hash, event)
require.NoError(t, err)
}

// Make sure the event was persisted.
insertedID := uint64(1)
found, err := keeper.eventsTable.Has(ctx, insertedID)
require.NoError(t, err)
require.True(t, found)

ctx = ctx.WithBlockHeight(deliverInterval)
err = keeper.EndBlock(ctx)
require.NoError(t, err)

// Make sure the event was deleted.
found, err = keeper.eventsTable.Has(ctx, insertedID)
require.NoError(t, err)
require.False(t, found)

// Assert that the message was delivered to the msg server.
require.Len(t, sServer.delegateMsgBuffer, 1)
msg := sServer.delegateMsgBuffer[0]
// Sanity check of addresses
require.Len(t, msg.DelegatorAddress, 45)
require.Len(t, msg.ValidatorAddress, 52)
require.True(t, strings.HasPrefix(msg.DelegatorAddress, "cosmos"), msg.DelegatorAddress)
require.True(t, strings.HasPrefix(msg.ValidatorAddress, "cosmosvaloper"), msg.ValidatorAddress)
oneEth := sdk.NewInt64Coin("stake", ethStake*1000000000000000000)
require.Equal(t, msg.Amount, oneEth)
}

func setupKeeper(
t *testing.T,
deliverInterval int64,
ethCl ethclient.EngineClient,
aKeeper types.AuthKeeper,
bKeeper types.BankKeeper,
sKeeper types.StakingKeeper,
sServer types.StakingMsgServer,
) (*Keeper, sdk.Context) {
t.Helper()

key := storetypes.NewKVStoreKey(types.ModuleName)
Expand All @@ -95,13 +164,57 @@ func setupKeeper(t *testing.T, submissionDelay int64) (*Keeper, sdk.Context) {

k, err := NewKeeper(
storeSvc,
nil,
nil,
nil,
nil,
submissionDelay,
ethCl,
aKeeper,
bKeeper,
sKeeper,
sServer,
deliverInterval,
)
require.NoError(t, err, "new keeper")

return k, ctx
}

type stakingKeeperStub struct{}

func (stakingKeeperStub) GetValidator(context.Context, sdk.ValAddress) (stypes.Validator, error) {
return stypes.Validator{}, nil
}

type authKeeperStub struct{}

func (authKeeperStub) HasAccount(context.Context, sdk.AccAddress) bool {
return true
}

func (authKeeperStub) NewAccountWithAddress(context.Context, sdk.AccAddress) sdk.AccountI {
return nil
}

func (authKeeperStub) SetAccount(context.Context, sdk.AccountI) {}

type bankKeeperStub struct{}

func (bankKeeperStub) MintCoins(context.Context, string, sdk.Coins) error {
return nil
}

func (bankKeeperStub) SendCoinsFromModuleToAccount(context.Context, string, sdk.AccAddress, sdk.Coins) error {
return nil
}

type msgServerStub struct {
createValidatorMsgBuffer []*stypes.MsgCreateValidator
delegateMsgBuffer []*stypes.MsgDelegate
}

func (s *msgServerStub) CreateValidator(_ context.Context, msg *stypes.MsgCreateValidator) (*stypes.MsgCreateValidatorResponse, error) {
s.createValidatorMsgBuffer = append(s.createValidatorMsgBuffer, msg)
return new(stypes.MsgCreateValidatorResponse), nil
}

func (s *msgServerStub) Delegate(_ context.Context, msg *stypes.MsgDelegate) (*stypes.MsgDelegateResponse, error) {
s.delegateMsgBuffer = append(s.delegateMsgBuffer, msg)
return new(stypes.MsgDelegateResponse), nil
}
7 changes: 3 additions & 4 deletions halo/evmstaking2/module/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ import (
"github.com/cosmos/cosmos-sdk/codec"
cdctypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/types/module"
accountkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
)
Expand Down Expand Up @@ -116,8 +114,8 @@ type ModuleInputs struct {

StoreService store.KVStoreService
EthCl ethclient.Client
AKeeper accountkeeper.AccountKeeperI
BKeeper bankkeeper.Keeper
AKeeper types.AuthKeeper
BKeeper types.BankKeeper
SKeeper *stakingkeeper.Keeper
Cdc codec.Codec
Config *Module
Expand All @@ -137,6 +135,7 @@ func ProvideModule(in ModuleInputs) (ModuleOutputs, error) {
in.AKeeper,
in.BKeeper,
in.SKeeper,
stakingkeeper.NewMsgServerImpl(in.SKeeper),
in.Config.GetDeliverInterval(),
)
if err != nil {
Expand Down
28 changes: 28 additions & 0 deletions halo/evmstaking2/types/interfaces.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package types

import (
"context"

sdk "github.com/cosmos/cosmos-sdk/types"
stypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)

type AuthKeeper interface {
HasAccount(ctx context.Context, addr sdk.AccAddress) bool
NewAccountWithAddress(ctx context.Context, addr sdk.AccAddress) sdk.AccountI
SetAccount(ctx context.Context, acc sdk.AccountI)
}

type BankKeeper interface {
MintCoins(ctx context.Context, moduleName string, amt sdk.Coins) error
SendCoinsFromModuleToAccount(ctx context.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error
}

type StakingKeeper interface {
GetValidator(ctx context.Context, addr sdk.ValAddress) (stypes.Validator, error)
}

type StakingMsgServer interface {
CreateValidator(ctx context.Context, msg *stypes.MsgCreateValidator) (*stypes.MsgCreateValidatorResponse, error)
Delegate(ctx context.Context, msg *stypes.MsgDelegate) (*stypes.MsgDelegateResponse, error)
}

0 comments on commit 3612b46

Please sign in to comment.