Skip to content

Commit

Permalink
feat(evmstaking): support edit validator events (#2923)
Browse files Browse the repository at this point in the history
Support edit validator events in evmstaking2 module.

issue: #2884
  • Loading branch information
corverroos authored Jan 28, 2025
1 parent e2d7892 commit b7e1159
Show file tree
Hide file tree
Showing 13 changed files with 180 additions and 21 deletions.
2 changes: 1 addition & 1 deletion contracts/allocs/devnet.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion contracts/allocs/staging.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion contracts/bindings/admin.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion contracts/bindings/allocpredeploys.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion contracts/bindings/staking.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion contracts/core/.gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Admin_Test:test_pause_unpause_bridge() (gas: 29328538)
Admin_Test:test_pause_unpause_xcall() (gas: 34252759)
Admin_Test:test_pause_unpause_xsubmit() (gas: 34252466)
Admin_Test:test_upgrade() (gas: 38333960)
AllocPredeploys_Test:test_num_allocs() (gas: 1181352719)
AllocPredeploys_Test:test_num_allocs() (gas: 1181398071)
AllocPredeploys_Test:test_predeploys() (gas: 1181334529)
AllocPredeploys_Test:test_preinstalls() (gas: 1182050945)
AllocPredeploys_Test:test_proxies() (gas: 1408977746)
Expand Down
2 changes: 1 addition & 1 deletion contracts/core/src/octane/Staking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ contract Staking is OwnableUpgradeable, EIP712Upgradeable {
* @notice Burn the fee, requiring it be sent with the call
*/
function _burnFee() internal {
require(msg.value >= Fee, "Slashing: insufficient fee");
require(msg.value >= Fee, "Staking: insufficient fee");
payable(BurnAddr).transfer(msg.value);
}
}
52 changes: 49 additions & 3 deletions halo/evmstaking2/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/omni-network/omni/lib/feature"
"github.com/omni-network/omni/lib/k1util"
"github.com/omni-network/omni/lib/log"
"github.com/omni-network/omni/lib/umath"
evmenginetypes "github.com/omni-network/omni/octane/evmengine/types"

"github.com/ethereum/go-ethereum/common"
Expand All @@ -26,6 +27,7 @@ var (
stakingABI = mustGetABI(bindings.StakingMetaData)
createValidatorEvent = mustGetEvent(stakingABI, "CreateValidator")
delegateEvent = mustGetEvent(stakingABI, "Delegate")
editValidatorEvent = mustGetEvent(stakingABI, "EditValidator")
)

// Keeper also implements the evmenginetypes.EvmEventProcessor interface.
Expand Down Expand Up @@ -126,7 +128,7 @@ func (Keeper) Name() string {

// FilterParams defines the matching EVM log events, see github.com/ethereum/go-ethereum#FilterQuery.
func (k Keeper) FilterParams() ([]common.Address, [][]common.Hash) {
return []common.Address{k.address}, [][]common.Hash{{createValidatorEvent.ID, delegateEvent.ID}}
return []common.Address{k.address}, [][]common.Hash{{createValidatorEvent.ID, delegateEvent.ID, editValidatorEvent.ID}}
}

// Deliver processes a omni deposit log event, which must be one of:
Expand Down Expand Up @@ -185,12 +187,12 @@ func (k Keeper) parseAndDeliver(ctx context.Context, elog *evmenginetypes.EVMEve

switch ethlog.Topics[0] {
case createValidatorEvent.ID:
delegate, err := k.contract.ParseCreateValidator(ethlog)
createVal, err := k.contract.ParseCreateValidator(ethlog)
if err != nil {
return errors.Wrap(err, "parse create validator")
}

if err := k.deliverCreateValidator(ctx, delegate); err != nil {
if err := k.deliverCreateValidator(ctx, createVal); err != nil {
return errors.Wrap(err, "create validator")
}
case delegateEvent.ID:
Expand All @@ -202,6 +204,15 @@ func (k Keeper) parseAndDeliver(ctx context.Context, elog *evmenginetypes.EVMEve
if err := k.deliverDelegate(ctx, delegate); err != nil {
return errors.Wrap(err, "delegate")
}
case editValidatorEvent.ID:
editVal, err := k.contract.ParseEditValidator(ethlog)
if err != nil {
return errors.Wrap(err, "parse edit validator")
}

if err := k.deliverEditValidator(ctx, editVal); err != nil {
return errors.Wrap(err, "edit validator")
}
default:
return errors.New("unknown event")
}
Expand Down Expand Up @@ -253,6 +264,41 @@ func (k Keeper) deliverDelegate(ctx context.Context, ev *bindings.StakingDelegat
return nil
}

func (k Keeper) deliverEditValidator(ctx context.Context, ev *bindings.StakingEditValidator) error {
valAddr := sdk.ValAddress(ev.Validator.Bytes())

p := ev.Params
description := stypes.Description{
Moniker: p.Moniker,
Identity: p.Identity,
Website: p.Website,
SecurityContact: p.SecurityContact,
Details: p.Details,
}

rateI64, err := umath.ToInt64(p.CommissionRatePercentage)
if err != nil {
return errors.Wrap(err, "convert commission rate")
}
rate := math.LegacyNewDec(rateI64)

minSelf := math.NewIntFromBigInt(p.MinSelfDelegation)

log.Info(ctx, "EVM staking editing validator",
"validator", ev.Validator.Hex(),
"moniker", description.Moniker,
"rate", p.CommissionRatePercentage,
"min_self", p.MinSelfDelegation,
)

msg := stypes.NewMsgEditValidator(valAddr.String(), description, &rate, &minSelf)
if _, err := k.sServer.EditValidator(ctx, msg); err != nil {
return errors.Wrap(err, "edit validator")
}

return nil
}

func (k Keeper) createAccIfNone(ctx context.Context, addr sdk.AccAddress) {
if !k.aKeeper.HasAccount(ctx, addr) {
acc := k.aKeeper.NewAccountWithAddress(ctx, addr)
Expand Down
67 changes: 66 additions & 1 deletion halo/evmstaking2/keeper/keeper_internal_test.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
package keeper

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

"github.com/omni-network/omni/contracts/bindings"
"github.com/omni-network/omni/halo/evmstaking2/testutil"
"github.com/omni-network/omni/halo/evmstaking2/types"
"github.com/omni-network/omni/lib/errors"
"github.com/omni-network/omni/lib/ethclient"
"github.com/omni-network/omni/lib/feature"
"github.com/omni-network/omni/lib/k1util"
"github.com/omni-network/omni/lib/netconf"
"github.com/omni-network/omni/lib/umath"
evmengkeeper "github.com/omni-network/omni/octane/evmengine/keeper"
etypes "github.com/omni-network/omni/octane/evmengine/types"

Expand Down Expand Up @@ -358,6 +360,69 @@ func TestNonSelfDelegationEventDelivery(t *testing.T) {
require.Equal(t, msg.Amount, stake)
}

func TestEditValidator(t *testing.T) {
t.Parallel()

privKey := k1.GenPrivKey()
valAddr, err := k1util.PubKeyToAddress(privKey.PubKey())
require.NoError(t, err)

params := &bindings.StakingEditValidatorParams{
Moniker: "moniker",
Identity: "identity",
Website: "https://website",
SecurityContact: "https://contract",
Details: "details",
CommissionRatePercentage: 99,
MinSelfDelegation: umath.NewBigInt(11),
}
ethClientMock, err := ethclient.NewEngineMock(
ethclient.WithMockEditValidator(privKey.PubKey(), params),
)
require.NoError(t, err)

var msgBuffer []*stypes.MsgEditValidator

ctrl := gomock.NewController(t)
sServerMock := testutil.NewMockStakingMsgServer(ctrl)
sServerMock.EXPECT().
EditValidator(gomock.Any(), gomock.Any()).
Times(1).
DoAndReturn(
func(ctx context.Context, msg *stypes.MsgEditValidator) (*stypes.MsgEditValidatorResponse, error) {
msgBuffer = append(msgBuffer, msg)
return new(stypes.MsgEditValidatorResponse), nil
},
)

keeper, ctx := setupKeeper(t, 1, sServerMock)

events, err := getStakingEvents(ctx, ethClientMock, keeper)
require.NoError(t, err)
require.Len(t, events, 1)

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

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

require.Len(t, msgBuffer, 1)
msg := msgBuffer[0]

require.Equal(t, msg.ValidatorAddress, sdk.ValAddress(valAddr.Bytes()).String())
require.Equal(t, msg.Description.Moniker, params.Moniker)
require.Equal(t, msg.Description.Identity, params.Identity)
require.Equal(t, msg.Description.Website, params.Website)
require.Equal(t, msg.Description.SecurityContact, params.SecurityContact)
require.Equal(t, msg.Description.Details, params.Details)
require.Equal(t, msg.MinSelfDelegation.String(), params.MinSelfDelegation.String())
require.Equal(t, msg.CommissionRate.TruncateInt64(), int64(params.CommissionRatePercentage))
}

func assertContains(t *testing.T, ctx context.Context, keeper *Keeper, eventID uint64) {
t.Helper()
found, err := keeper.eventsTable.Has(ctx, eventID)
Expand Down
19 changes: 17 additions & 2 deletions halo/evmstaking2/testutil/mock_interfaces.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions halo/evmstaking2/types/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ type StakingKeeper interface {
type StakingMsgServer interface {
CreateValidator(ctx context.Context, msg *stypes.MsgCreateValidator) (*stypes.MsgCreateValidatorResponse, error)
Delegate(ctx context.Context, msg *stypes.MsgDelegate) (*stypes.MsgDelegateResponse, error)
EditValidator(ctx context.Context, msg *stypes.MsgEditValidator) (*stypes.MsgEditValidatorResponse, error)
}
2 changes: 1 addition & 1 deletion halo/genutil/evm/testdata/TestMakeEVMGenesis.golden

Large diffs are not rendered by default.

46 changes: 39 additions & 7 deletions lib/ethclient/enginemock.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,11 @@ type payloadArgs struct {

//nolint:gochecknoglobals // This is a static mapping.
var (
delegateEvent = mustGetABI(bindings.StakingMetaData).Events["Delegate"]
portalRegEvent = mustGetABI(bindings.PortalRegistryMetaData).Events["PortalRegistered"]
planUpgradeEvent = mustGetABI(bindings.UpgradeMetaData).Events["PlanUpgrade"]
createValidatorEvent = mustGetABI(bindings.StakingMetaData).Events["CreateValidator"]
delegateEvent = mustGetABI(bindings.StakingMetaData).Events["Delegate"]
portalRegEvent = mustGetABI(bindings.PortalRegistryMetaData).Events["PortalRegistered"]
planUpgradeEvent = mustGetABI(bindings.UpgradeMetaData).Events["PlanUpgrade"]
createValEvent = mustGetABI(bindings.StakingMetaData).Events["CreateValidator"]
editValEvent = mustGetABI(bindings.StakingMetaData).Events["EditValidator"]
)

var _ EngineClient = (*engineMock)(nil)
Expand All @@ -66,7 +67,7 @@ type engineMock struct {
payloads map[engine.PayloadID]payloadArgs
}

// ValidatorCreation returns an option to add a validator creation event to the mock.
// WithMockValidatorCreation returns an option to add a validator creation event to the mock.
func WithMockValidatorCreation(pubkey crypto.PubKey) func(*engineMock) {
return func(mock *engineMock) {
mock.mu.Lock()
Expand All @@ -78,7 +79,7 @@ func WithMockValidatorCreation(pubkey crypto.PubKey) func(*engineMock) {
}

oneEth := new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether))
data, err := createValidatorEvent.Inputs.NonIndexed().Pack(pubkey.Bytes(), oneEth)
data, err := createValEvent.Inputs.NonIndexed().Pack(pubkey.Bytes(), oneEth)
if err != nil {
panic(errors.Wrap(err, "pack create validator"))
}
Expand All @@ -87,7 +88,7 @@ func WithMockValidatorCreation(pubkey crypto.PubKey) func(*engineMock) {
eventLog := types.Log{
Address: contractAddr,
Topics: []common.Hash{
createValidatorEvent.ID,
createValEvent.ID,
common.HexToHash(valAddr.Hex()), // validator
},
Data: data,
Expand All @@ -98,6 +99,37 @@ func WithMockValidatorCreation(pubkey crypto.PubKey) func(*engineMock) {
}
}

// WithMockEditValidator returns an option to add an edit validator event to the mock.
func WithMockEditValidator(pubkey crypto.PubKey, params *bindings.StakingEditValidatorParams) func(*engineMock) {
return func(mock *engineMock) {
mock.mu.Lock()
defer mock.mu.Unlock()

valAddr, err := k1util.PubKeyToAddress(pubkey)
if err != nil {
panic(errors.Wrap(err, "pubkey to address"))
}

data, err := editValEvent.Inputs.NonIndexed().Pack(params)
if err != nil {
panic(errors.Wrap(err, "pack edit validator params"))
}

contractAddr := common.HexToAddress(predeploys.Staking)
eventLog := types.Log{
Address: contractAddr,
Topics: []common.Hash{
editValEvent.ID,
common.HexToHash(valAddr.Hex()), // validator
},
Data: data,
Index: 101,
}

mock.pendingLogs[contractAddr] = append(mock.pendingLogs[contractAddr], eventLog)
}
}

// WithMockDelegation returns an option to add a delegation event to the mock from the specified address.
func WithMockDelegation(validatorPubkey crypto.PubKey, delegatorAddr common.Address, ether int64) func(*engineMock) {
return func(mock *engineMock) {
Expand Down

0 comments on commit b7e1159

Please sign in to comment.