Skip to content

Commit

Permalink
add avs manager precompiles
Browse files Browse the repository at this point in the history
  • Loading branch information
mikebraver committed Mar 27, 2024
1 parent 714ec6c commit faae296
Show file tree
Hide file tree
Showing 8 changed files with 261 additions and 33 deletions.
Empty file added precompiles/avs/abi.json
Empty file.
116 changes: 116 additions & 0 deletions precompiles/avs/avs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package avs

import (
"bytes"
"embed"
"fmt"

avsKeeper "github.com/ExocoreNetwork/exocore/x/avs/keeper"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
cmn "github.com/evmos/evmos/v14/precompiles/common"
)

var _ vm.PrecompiledContract = &Precompile{}

// Embed abi json file to the executable binary. Needed when importing as dependency.
//
//go:embed abi.json
var f embed.FS

// Precompile defines the precompiled contract for avs.
type Precompile struct {
cmn.Precompile
avsKeeper avsKeeper.Keeper
}

// NewPrecompile creates a new avs Precompile instance as a
// PrecompiledContract interface.
func NewPrecompile(
avsKeeper avsKeeper.Keeper,
authzKeeper authzkeeper.Keeper,
) (*Precompile, error) {
abiBz, err := f.ReadFile("abi.json")
if err != nil {
return nil, fmt.Errorf("error loading the avs ABI %s", err)
}

newAbi, err := abi.JSON(bytes.NewReader(abiBz))
if err != nil {
return nil, fmt.Errorf(cmn.ErrInvalidABI, err)
}

return &Precompile{
Precompile: cmn.Precompile{
ABI: newAbi,
AuthzKeeper: authzKeeper,
KvGasConfig: storetypes.KVGasConfig(),
TransientKVGasConfig: storetypes.TransientGasConfig(),
ApprovalExpiration: cmn.DefaultExpirationDuration,
},
avsKeeper: avsKeeper,
}, nil
}

// Address defines the address of the avs compile contract.
// address: 0x0000000000000000000000000000000000000902
func (p Precompile) Address() common.Address {
return common.HexToAddress("0x0000000000000000000000000000000000000902")
}

// RequiredGas calculates the precompiled contract's base gas rate.
func (p Precompile) RequiredGas(input []byte) uint64 {
methodID := input[:4]

method, err := p.MethodById(methodID)
if err != nil {
// This should never happen since this method is going to fail during Run
return 0
}
return p.Precompile.RequiredGas(input, p.IsTransaction(method.Name))
}

// Run executes the precompiled contract deposit methods defined in the ABI.
func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz []byte, err error) {
ctx, stateDB, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, p.IsTransaction)
if err != nil {
return nil, err
}

// This handles any out of gas errors that may occur during the execution of a precompile tx or query.
// It avoids panics and returns the out of gas error so the EVM can continue gracefully.
defer cmn.HandleGasError(ctx, contract, initialGas, &err)()

if method.Name == MethodAVSAction {
bz, err = p.AVSInfoRegisterOrDeregister(ctx, evm.Origin, contract, stateDB, method, args)
}

if err != nil {
ctx.Logger().Error("call avs precompile error", "module", "avs precompile", "err", err)
return nil, err
}

cost := ctx.GasMeter().GasConsumed() - initialGas

if !contract.UseGas(cost) {
return nil, vm.ErrOutOfGas
}

return bz, nil
}

// IsTransaction checks if the given methodID corresponds to a transaction or query.
//
// Available avs transactions are:
// - AVSRegister
func (Precompile) IsTransaction(methodID string) bool {
switch methodID {
case MethodAVSAction:
return true
default:
return false
}
}
35 changes: 35 additions & 0 deletions precompiles/avs/tx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package avs

import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
)

const (
// AVSRegister defines the ABI method name for the avs
// related transaction.
MethodAVSAction = "avsAction"
)

// AVSInfoRegister register the avs related information and change the state in avs keeper module.
func (p Precompile) AVSInfoRegisterOrDeregister(
ctx sdk.Context,
_ common.Address,
contract *vm.Contract,

Check warning on line 20 in precompiles/avs/tx.go

View workflow job for this annotation

GitHub Actions / Run golangci-lint

unused-parameter: parameter 'contract' seems to be unused, consider removing or renaming it as _ (revive)
_ vm.StateDB,
method *abi.Method,
args []interface{},
) ([]byte, error) {
// parse the avs input params first.
avsParams, err := p.GetAVSParamsFromInputs(ctx, args)
if err != nil {
return nil, err
}
err = p.avsKeeper.AVSInfoUpdate(ctx, avsParams)
if err != nil {
return nil, err
}
return method.Outputs.Pack(true)
}
40 changes: 40 additions & 0 deletions precompiles/avs/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package avs

import (
exocmn "github.com/ExocoreNetwork/exocore/precompiles/common"
"github.com/ExocoreNetwork/exocore/x/avs/keeper"
sdk "github.com/cosmos/cosmos-sdk/types"
cmn "github.com/evmos/evmos/v14/precompiles/common"
"golang.org/x/xerrors"
)

func (p Precompile) GetAVSParamsFromInputs(ctx sdk.Context, args []interface{}) (*keeper.AVSParams, error) {
if len(args) != 4 {
return nil, xerrors.Errorf(cmn.ErrInvalidNumberOfArgs, 4, len(args))
}
avsParams := &keeper.AVSParams{}
avsName, ok := args[0].(string)
if !ok {
return nil, xerrors.Errorf(exocmn.ErrContractInputParaOrType, 0, "string", avsName)
}
avsParams.AVSName = avsName

avsAddress, ok := args[1].([]byte)
if !ok || avsAddress == nil {
return nil, xerrors.Errorf(exocmn.ErrContractInputParaOrType, 1, "[]byte", avsAddress)
}
avsParams.AVSAddress = avsAddress

operatorAddress, ok := args[2].([]byte)
if !ok || operatorAddress == nil {
return nil, xerrors.Errorf(exocmn.ErrContractInputParaOrType, 2, "[]byte", operatorAddress)
}
avsParams.OperatorAddress = operatorAddress

action, ok := args[3].(uint64)
if !ok || action != keeper.RegisterAction || action != keeper.DeRegisterAction {

Check failure on line 35 in precompiles/avs/types.go

View workflow job for this annotation

GitHub Actions / test-unit-cover

suspect or: action != keeper.RegisterAction || action != keeper.DeRegisterAction
return nil, xerrors.Errorf(exocmn.ErrContractInputParaOrType, 3, "uint64", action)
}
avsParams.Action = action
return avsParams, nil
}
51 changes: 40 additions & 11 deletions x/avs/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"

errorsmod "cosmossdk.io/errors"
delegationtypes "github.com/ExocoreNetwork/exocore/x/delegation/types"
"github.com/cometbft/cometbft/libs/log"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/store/prefix"
Expand All @@ -16,10 +17,11 @@ import (

type (
Keeper struct {
cdc codec.BinaryCodec
storeKey storetypes.StoreKey
memKey storetypes.StoreKey
paramstore paramtypes.Subspace
cdc codec.BinaryCodec
storeKey storetypes.StoreKey
memKey storetypes.StoreKey
paramstore paramtypes.Subspace
operatorKeeper delegationtypes.OperatorKeeper
}
)

Expand Down Expand Up @@ -47,15 +49,42 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName))
}

func (k Keeper) SetAVSInfo(ctx sdk.Context, info *types.AVSInfo) (err error) {
avsAddr, err := sdk.AccAddressFromBech32(info.AVSAddress)
func (k Keeper) AVSInfoUpdate(ctx sdk.Context, params *AVSParams) error {
operatorAddress := params.OperatorAddress
opAccAddr, err := sdk.AccAddressFromBech32(string(operatorAddress))
if err != nil {
return errorsmod.Wrap(err, fmt.Sprintf("error occurred when parse acc address from Bech32,the addr is:%s", operatorAddress))
}
if !k.operatorKeeper.IsOperator(ctx, opAccAddr) {
return errorsmod.Wrap(delegationtypes.ErrOperatorNotExist, "AVSInfoUpdate: invalid operator address")
}
action := params.Action

if action == RegisterAction {
return k.SetAVSInfo(ctx, params.AVSName, string(params.AVSAddress), string(operatorAddress))
} else {

Check warning on line 65 in x/avs/keeper/keeper.go

View workflow job for this annotation

GitHub Actions / Run golangci-lint

indent-error-flow: if block ends with a return statement, so drop this else and outdent its block (revive)
return k.DeleteAVSInfo(ctx, string(params.AVSAddress))
}
}

func (k Keeper) SetAVSInfo(ctx sdk.Context, AVSName string, AVSAddress string, OperatorAddress string) (err error) {
avsAddr, err := sdk.AccAddressFromBech32(AVSAddress)
if err != nil {
return errorsmod.Wrap(err, "GetAVSInfo: error occurred when parse acc address from Bech32")
}
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixAVSInfo)
bz := k.cdc.MustMarshal(info)
store.Set(avsAddr, bz)
return nil
if !store.Has(avsAddr) {
AVSInfo := &types.AVSInfo{Name: AVSName, AVSAddress: AVSAddress, OperatorAddress: []string{OperatorAddress}}
bz := k.cdc.MustMarshal(AVSInfo)
store.Set(avsAddr, bz)
return nil
} else {

Check warning on line 81 in x/avs/keeper/keeper.go

View workflow job for this annotation

GitHub Actions / Run golangci-lint

indent-error-flow: if block ends with a return statement, so drop this else and outdent its block (revive)
value := store.Get(avsAddr)
ret := &types.AVSInfo{}
k.cdc.MustUnmarshal(value, ret)
ret.OperatorAddress = append(ret.OperatorAddress, OperatorAddress)
return nil
}
}

func (k Keeper) GetAVSInfo(ctx sdk.Context, addr string) (*types.AVSInfo, error) {
Expand All @@ -74,8 +103,8 @@ func (k Keeper) GetAVSInfo(ctx sdk.Context, addr string) (*types.AVSInfo, error)
return &ret, nil
}

func (k Keeper) DeleteAVSInfo(ctx sdk.Context, info *types.AVSInfo) error {
avsAddr, err := sdk.AccAddressFromBech32(info.AVSAddress)
func (k Keeper) DeleteAVSInfo(ctx sdk.Context, addr string) error {
avsAddr, err := sdk.AccAddressFromBech32(addr)
if err != nil {
return errorsmod.Wrap(err, "AVSInfo: error occurred when parse acc address from Bech32")
}
Expand Down
36 changes: 18 additions & 18 deletions x/avs/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,34 @@ package keeper

import (
"context"
"fmt"

"github.com/ExocoreNetwork/exocore/x/avs/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)

var _ types.MsgServer = &Keeper{}

func (k Keeper) RegisterAVS(ctx context.Context, req *types.RegisterAVSReq) (*types.RegisterAVSResponse, error) {

Check warning on line 11 in x/avs/keeper/msg_server.go

View workflow job for this annotation

GitHub Actions / Run golangci-lint

unused-parameter: parameter 'ctx' seems to be unused, consider removing or renaming it as _ (revive)
c := sdk.UnwrapSDKContext(ctx)
fromAddress := req.FromAddress
operatorAddress := req.Info.OperatorAddress
for _, opAddr := range operatorAddress {
if fromAddress == opAddr {
// Set purely for AVS itself information.
if err := k.SetAVSInfo(c, req.Info); err != nil {
return nil, err
}
}
}
return nil, fmt.Errorf("The fromAddress %s is different from operatorAddress %s ", fromAddress, operatorAddress)
// Disable cosmos transaction temporarily
// c := sdk.UnwrapSDKContext(ctx)
// fromAddress := req.FromAddress
// operatorAddress := req.Info.OperatorAddress
// for _, opAddr := range operatorAddress {
// if fromAddress == opAddr {
// // Set purely for AVS itself information.
// if err := k.SetAVSInfo(c, req.Info); err != nil {
// return nil, err
// }
// }
// }
return nil, nil
}

func (k Keeper) DeRegisterAVS(ctx context.Context, req *types.DeRegisterAVSReq) (*types.DeRegisterAVSResponse, error) {

Check warning on line 27 in x/avs/keeper/msg_server.go

View workflow job for this annotation

GitHub Actions / Run golangci-lint

unused-parameter: parameter 'ctx' seems to be unused, consider removing or renaming it as _ (revive)
c := sdk.UnwrapSDKContext(ctx)
if err := k.DeleteAVSInfo(c, req.Info); err != nil {
return nil, err
}
// Disable cosmos transaction temporarily
// c := sdk.UnwrapSDKContext(ctx)
// if err := k.DeleteAVSInfo(c, req.Info); err != nil {
// return nil, err
// }

return nil, nil
}
14 changes: 12 additions & 2 deletions x/avs/keeper/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,22 @@ import (

// GetParams get all parameters as types.Params
func (k Keeper) GetParams(ctx sdk.Context) types.Params {

Check warning on line 9 in x/avs/keeper/params.go

View workflow job for this annotation

GitHub Actions / Run golangci-lint

unused-parameter: parameter 'ctx' seems to be unused, consider removing or renaming it as _ (revive)
return types.NewParams(
)
return types.NewParams()
}

// SetParams set the params
func (k Keeper) SetParams(ctx sdk.Context, params types.Params) {
k.paramstore.SetParamSet(ctx, &params)
}

type AVSParams struct {
AVSName string
AVSAddress []byte
OperatorAddress []byte
Action uint64
}

const (
RegisterAction = iota + 1
DeRegisterAction
)
2 changes: 0 additions & 2 deletions x/avs/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import (
"github.com/cosmos/cosmos-sdk/x/auth/types"
)



// AccountKeeper defines the expected account keeper used for simulations (noalias)
type AccountKeeper interface {
GetAccount(ctx sdk.Context, addr sdk.AccAddress) types.AccountI
Expand Down

0 comments on commit faae296

Please sign in to comment.