Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: CNS-962-user-spec-implementation #1505

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
3 changes: 1 addition & 2 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@ func New(
keys[specmoduletypes.MemStoreKey],
app.GetSubspace(specmoduletypes.ModuleName),
app.StakingKeeper,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)
specModule := specmodule.NewAppModule(appCodec, app.SpecKeeper, app.AccountKeeper, app.BankKeeper)

Expand Down Expand Up @@ -608,10 +609,8 @@ func New(
govRouter.AddRoute(govtypes.RouterKey, v1beta1.ProposalHandler).
//
// user defined
AddRoute(specmoduletypes.ProposalsRouterKey, specmodule.NewSpecProposalsHandler(app.SpecKeeper)).
// copied the code from param and changed the handler to enable functionality
AddRoute(paramproposal.RouterKey, specmodule.NewParamChangeProposalHandler(app.ParamsKeeper)).
// user defined
AddRoute(plansmoduletypes.ProposalsRouterKey, plansmodule.NewPlansProposalsHandler(app.PlansKeeper)).
AddRoute(pairingmoduletypes.ProposalsRouterKey, pairingmodule.NewPairingProposalsHandler(app.PairingKeeper)).

Expand Down
2 changes: 1 addition & 1 deletion app/upgrades/upgrade_0_35_0.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func v_35_0(
params := lk.SpecKeeper.GetParams(ctx)
params.AllowlistedExpeditedMsgs = []string{
proto.MessageName(&protocoltypes.MsgSetVersion{}),
proto.MessageName(&spectypes.SpecAddProposal{}),
proto.MessageName(&spectypes.MsgAddSpecs{}),
proto.MessageName(&ibctypes.ClientUpdateProposal{}),
proto.MessageName(&ibctypes.UpgradeProposal{}),
}
Expand Down
1 change: 1 addition & 0 deletions proto/lavanet/lava/spec/spec.proto
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,5 @@ message Spec {
];
uint64 shares = 19;
string identity = 20;
bool user_spec = 21;
}
18 changes: 0 additions & 18 deletions proto/lavanet/lava/spec/spec_add_proposal.proto

This file was deleted.

13 changes: 12 additions & 1 deletion proto/lavanet/lava/spec/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,21 @@ package lavanet.lava.spec;
// this line is used by starport scaffolding # proto/tx/import

option go_package = "github.com/lavanet/lava/x/spec/types";
import "gogoproto/gogo.proto";
import "lavanet/lava/spec/spec.proto";

// Msg defines the Msg service.
service Msg {
rpc AddSpecs(MsgAddSpecs) returns (MsgAddSpecsResponse);
// this line is used by starport scaffolding # proto/tx/rpc
}

// this line is used by starport scaffolding # proto/tx/message
// this line is used by starport scaffolding # proto/tx/message

message MsgAddSpecs {
string creator = 1;
repeated Spec specs = 2 [(gogoproto.nullable) = false];
}

message MsgAddSpecsResponse {
}
6 changes: 4 additions & 2 deletions testutil/common/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ func CreateMockSpec() spectypes.Spec {
spec.BlockDistanceForFinalizedData = 0
spec.DataReliabilityEnabled = true
spec.MinStakeProvider = sdk.NewCoin(commonconsts.TestTokenDenom, sdk.NewInt(1000))
spec.ApiCollections = []*spectypes.ApiCollection{{Enabled: true, CollectionData: spectypes.CollectionData{ApiInterface: "stub", Type: "GET"}, Apis: []*spectypes.Api{{Name: specName + "API", ComputeUnits: 100, Enabled: true}}}}
spec.BlockDistanceForFinalizedData = 0
spec.ApiCollections = []*spectypes.ApiCollection{{Enabled: true, CollectionData: spectypes.CollectionData{ApiInterface: spectypes.APIInterfaceJsonRPC, Type: "GET"}, Apis: []*spectypes.Api{{Name: specName + "API", ComputeUnits: 100, Enabled: true}}}}
spec.BlocksInFinalizationProof = 10
spec.Shares = 1
spec.AverageBlockTime = 10000
spec.AllowedBlockLagForQosSync = 5
return spec
}

Expand Down
2 changes: 1 addition & 1 deletion testutil/keeper/dualstaking.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func DualstakingKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) {
nil,
&mockAccountKeeper{},
epochstorageKeeper,
speckeeper.NewKeeper(cdc, nil, nil, paramsSubspaceSpec, nil),
speckeeper.NewKeeper(cdc, nil, nil, paramsSubspaceSpec, nil, ""),
fixationkeeper.NewKeeper(cdc, tsKeeper, epochstorageKeeper.BlocksToSaveRaw),
)

Expand Down
11 changes: 2 additions & 9 deletions testutil/keeper/keepers_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ func InitAllKeepers(t testing.TB) (*Servers, *Keepers, context.Context) {
init_balance()
ks.StakingKeeper = *stakingkeeper.NewKeeper(cdc, stakingStoreKey, ks.AccountKeeper, ks.BankKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String())
ks.Distribution = distributionkeeper.NewKeeper(cdc, distributionStoreKey, ks.AccountKeeper, ks.BankKeeper, ks.StakingKeeper, authtypes.FeeCollectorName, authtypes.NewModuleAddress(govtypes.ModuleName).String())
ks.Spec = *speckeeper.NewKeeper(cdc, specStoreKey, specMemStoreKey, specparamsSubspace, ks.StakingKeeper)
ks.Spec = *speckeeper.NewKeeper(cdc, specStoreKey, specMemStoreKey, specparamsSubspace, ks.StakingKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String())
ks.Epochstorage = *epochstoragekeeper.NewKeeper(cdc, epochStoreKey, epochMemStoreKey, epochparamsSubspace, &ks.BankKeeper, &ks.AccountKeeper, ks.Spec, ks.StakingKeeper)
ks.FixationStoreKeeper = fixationkeeper.NewKeeper(cdc, ks.TimerStoreKeeper, ks.Epochstorage.BlocksToSaveRaw)
ks.Dualstaking = *dualstakingkeeper.NewKeeper(cdc, dualstakingStoreKey, dualstakingMemStoreKey, dualstakingparamsSubspace, &ks.BankKeeper, &ks.StakingKeeper, &ks.AccountKeeper, ks.Epochstorage, ks.Spec, ks.FixationStoreKeeper)
Expand Down Expand Up @@ -383,14 +383,7 @@ func SimulatePlansDelProposal(ctx sdk.Context, plansKeeper planskeeper.Keeper, p
}

func SimulateSpecAddProposal(ctx sdk.Context, specKeeper speckeeper.Keeper, specsToPropose []spectypes.Spec) error {
proposal := spectypes.NewSpecAddProposal("mockProposal", "mockProposal specs add for testing", specsToPropose)
err := proposal.ValidateBasic()
if err != nil {
return err
}
proposalHandler := spec.NewSpecProposalsHandler(specKeeper)
err = proposalHandler(ctx, proposal)
return err
return specKeeper.HandleSpecs(ctx, specsToPropose, specKeeper.GetAuthority())
}

func SimulateUnstakeProposal(ctx sdk.Context, pairingKeeper pairingkeeper.Keeper, providersInfo []pairingtypes.ProviderUnstakeInfo, delegatorsSlashing []pairingtypes.DelegatorSlashing) error {
Expand Down
2 changes: 1 addition & 1 deletion testutil/keeper/plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func PlanKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) {
memStoreKey,
paramsSubspace,
epochstorageKeeper,
speckeeper.NewKeeper(cdc, nil, nil, paramsSubspaceSpec, nil),
speckeeper.NewKeeper(cdc, nil, nil, paramsSubspaceSpec, nil, ""),
fixationkeeper.NewKeeper(cdc, timerstorekeeper.NewKeeper(cdc), epochstorageKeeper.BlocksToSaveRaw),
nil,
)
Expand Down
3 changes: 2 additions & 1 deletion testutil/keeper/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ func specKeeper() (*keeper.Keeper, sdk.Context, error) {
memStoreKey,
paramsSubspace,
nil,
"",
)

ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger())
Expand All @@ -79,7 +80,7 @@ func GetASpec(specIndex, getToTopMostPath string, ctxArg *sdk.Context, keeper *k
}
proposalFile := "./cookbook/specs/ibc.json,./cookbook/specs/cosmoswasm.json,./cookbook/specs/tendermint.json,./cookbook/specs/cosmossdk.json,./cookbook/specs/cosmossdk_full.json,./cookbook/specs/ethereum.json,./cookbook/specs/cosmoshub.json,./cookbook/specs/lava.json,./cookbook/specs/osmosis.json,./cookbook/specs/fantom.json,./cookbook/specs/celo.json,./cookbook/specs/optimism.json,./cookbook/specs/arbitrum.json,./cookbook/specs/starknet.json,./cookbook/specs/aptos.json,./cookbook/specs/juno.json,./cookbook/specs/polygon.json,./cookbook/specs/evmos.json,./cookbook/specs/base.json,./cookbook/specs/canto.json,./cookbook/specs/sui.json,./cookbook/specs/solana.json,./cookbook/specs/bsc.json,./cookbook/specs/axelar.json,./cookbook/specs/avalanche.json,./cookbook/specs/fvm.json"
for _, fileName := range strings.Split(proposalFile, ",") {
proposal := utils.SpecAddProposalJSON{}
proposal := utils.SpecAddProposalWithDepositJSON{}

contents, err := os.ReadFile(getToTopMostPath + fileName)
if err != nil {
Expand Down
9 changes: 9 additions & 0 deletions x/conflict/keeper/msg_server_detection.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ func (k msgServer) Detection(goCtx context.Context, msg *types.MsgDetection) (*t
utils.Attribute{Key: "client", Value: msg.Creator},
)
}

spec, found := k.specKeeper.GetSpec(ctx, msg.ResponseConflict.ConflictRelayData0.Request.RelaySession.SpecId)
if !found || spec.UserSpec {
return nil, utils.LavaFormatWarning("Simulation: invalid spec for conflict (not found or user spec)", err,
utils.Attribute{Key: "found", Value: found},
utils.Attribute{Key: "userSpec", Value: spec.UserSpec},
)
}

if msg.FinalizationConflict != nil && msg.ResponseConflict == nil && msg.SameProviderConflict == nil {
err := k.Keeper.ValidateFinalizationConflict(ctx, msg.FinalizationConflict, clientAddr)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions x/conflict/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type EpochstorageKeeper interface {
type SpecKeeper interface {
IsSpecFoundAndActive(ctx sdk.Context, chainID string) (foundAndActive, found bool, providersType spectypes.Spec_ProvidersTypes)
IsFinalizedBlock(ctx sdk.Context, chainID string, requestedBlock, latestBlock int64) bool
GetSpec(ctx sdk.Context, index string) (val spectypes.Spec, found bool)
}

// AccountKeeper defines the expected account keeper used for simulations (noalias)
Expand Down
6 changes: 3 additions & 3 deletions x/pairing/keeper/msg_server_relay_payment.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ func (k msgServer) RelayPayment(goCtx context.Context, msg *types.MsgRelayPaymen
utils.LogLavaEvent(ctx, logger, types.RelayPaymentEventName, successDetails, "New Proof Of Work Was Accepted")

cuAfterQos := rewardedCUDec.TruncateInt().Uint64()
err = k.chargeCuToSubscriptionAndCreditProvider(ctx, project, relay, cuAfterQos)
err = k.chargeCuToSubscriptionAndCreditProvider(ctx, project, relay, cuAfterQos, spec.UserSpec)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding more detailed error messages or handling for the chargeCuToSubscriptionAndCreditProvider function.

This function now includes a userSpec boolean which affects the charging logic. However, the error messages could be more descriptive to help in debugging, especially since userSpec influences the flow. Consider enhancing the error handling to provide more context about the failure, particularly how userSpec impacts the outcome.

if err != nil {
return nil, utils.LavaFormatError("Failed charging CU to project and subscription", err)
}
Expand Down Expand Up @@ -393,7 +393,7 @@ func (k EpochCuCache) updateProvidersComplainerCU(ctx sdk.Context, unresponsiveP
return nil
}

func (k Keeper) chargeCuToSubscriptionAndCreditProvider(ctx sdk.Context, project projectstypes.Project, relay *types.RelaySession, cuAfterQos uint64) error {
func (k Keeper) chargeCuToSubscriptionAndCreditProvider(ctx sdk.Context, project projectstypes.Project, relay *types.RelaySession, cuAfterQos uint64, userSpec bool) error {
epoch := uint64(relay.Epoch)

err := k.projectsKeeper.ChargeComputeUnitsToProject(ctx, project, epoch, relay.CuSum)
omerlavanet marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -406,7 +406,7 @@ func (k Keeper) chargeCuToSubscriptionAndCreditProvider(ctx sdk.Context, project
return fmt.Errorf("failed to add CU to the subscription")
}

err = k.subscriptionKeeper.AddTrackedCu(ctx, sub.Consumer, relay.Provider, relay.SpecId, cuAfterQos, sub.Block)
err = k.subscriptionKeeper.AddTrackedCu(ctx, sub.Consumer, relay.Provider, relay.SpecId, cuAfterQos, sub.Block, userSpec)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure the new parameter userSpec is correctly documented and tested.

The addition of the userSpec parameter to the AddTrackedCu method modifies how CU tracking is handled. It would be beneficial to update the method's documentation to reflect this change and to ensure that unit tests cover scenarios where userSpec is both true and false. Would you like assistance in updating the documentation or creating the necessary tests?

if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion x/pairing/keeper/msg_server_stake_provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ func TestCmdStakeProviderGeoConfigAndEnum(t *testing.T) {
require.NoError(t, err)
// adjust endpoints to match the default API interfaces and addons generated with ts
for i := 0; i < len(endpoints); i++ {
endpoints[i].ApiInterfaces = []string{"stub"}
endpoints[i].ApiInterfaces = []string{spectypes.APIInterfaceJsonRPC}
endpoints[i].Addons = []string{}
}
_, err = ts.TxPairingStakeProvider(provider, acc.GetVaultAddr(), ts.spec.Index, ts.spec.MinStakeProvider, endpoints, geo, common.MockDescription())
Expand Down
2 changes: 1 addition & 1 deletion x/pairing/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ type SubscriptionKeeper interface {
GetAllSubTrackedCuIndices(ctx sdk.Context, sub string) []string
GetTrackedCu(ctx sdk.Context, sub string, provider string, chainID string, block uint64) (cu uint64, found bool, key string)
CalcTotalMonthlyReward(ctx sdk.Context, totalAmount math.Int, trackedCu uint64, totalCuUsedBySub uint64) math.Int
AddTrackedCu(ctx sdk.Context, sub string, provider string, chainID string, cu uint64, block uint64) error
AddTrackedCu(ctx sdk.Context, sub string, provider string, chainID string, cu uint64, block uint64, userSpec bool) error
GetAllSubscriptionsIndices(ctx sdk.Context) []string
AppendAdjustment(ctx sdk.Context, consumer string, provider string, totalConsumerUsage uint64, usageWithThisProvider uint64)
CalculateParticipationFees(ctx sdk.Context, reward sdk.Coin) (sdk.Coins, sdk.Coins, error)
Expand Down
73 changes: 63 additions & 10 deletions x/spec/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"strings"
"time"

codectypes "github.com/cosmos/cosmos-sdk/codec/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
Expand All @@ -18,6 +17,7 @@ import (
"github.com/lavanet/lava/x/spec/client/utils"
"github.com/lavanet/lava/x/spec/types"

"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version"
Expand All @@ -43,7 +43,7 @@ func GetTxCmd() *cobra.Command {
}

// this line is used by starport scaffolding # 1

cmd.AddCommand(CmdTxAddSpecs())
return cmd
}

Expand Down Expand Up @@ -89,10 +89,6 @@ $ %s tx gov spec-proposal spec-add <path/to/proposal.json> --from=<key_or_addres

from := clientCtx.GetFromAddress()
content := &proposal.Proposal
deposit, err := sdk.ParseCoinsNormalized(proposal.Deposit)
if err != nil {
return err
}

devTest, err := cmd.Flags().GetBool(devTestFlagName)
if err == nil && devTest {
Expand All @@ -115,14 +111,13 @@ $ %s tx gov spec-proposal spec-add <path/to/proposal.json> --from=<key_or_addres
}
}

contentAny, err := codectypes.NewAnyWithValue(content)
deposit, err := sdk.ParseCoinsNormalized(proposal.Deposit)
if err != nil {
return err
}

msgExecLegacy := govv1.NewMsgExecLegacyContent(contentAny, authtypes.NewModuleAddress(govtypes.ModuleName).String())

submitPropMsg, err := govv1.NewMsgSubmitProposal([]sdk.Msg{msgExecLegacy}, deposit, from.String(), proposal.Proposal.Description, proposal.Proposal.Title, "Add a new spec", isExpedited)
msgAddSpecs := types.NewMsgAddSpecs(authtypes.NewModuleAddress(govtypes.ModuleName).String(), content.Specs)
submitPropMsg, err := govv1.NewMsgSubmitProposal([]sdk.Msg{msgAddSpecs}, deposit, from.String(), proposal.Proposal.Description, proposal.Proposal.Title, "Add a new spec", isExpedited)
if err != nil {
return err
}
Expand All @@ -134,3 +129,61 @@ $ %s tx gov spec-proposal spec-add <path/to/proposal.json> --from=<key_or_addres
cmd.Flags().Bool(expeditedFlagName, false, "set to true to make the spec proposal expedited")
return cmd
}

// CmdTxAddSpecs returns a CLI command handler for creating
// a add spec transaction
func CmdTxAddSpecs() *cobra.Command {
cmd := &cobra.Command{
Use: "spec-add [proposal-file,proposal-file,...]",
Args: cobra.ExactArgs(1),
Short: "Submit a spec add",
Long: strings.TrimSpace(
fmt.Sprintf(`send a transaction to add or modify existing user specs.
Example:
$ %s tx spec spec-add <path/to/proposal.json> --from=<key_or_address>
`,
version.AppName,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
proposal, err := utils.ParseSpecAddProposalJSON(clientCtx.LegacyAmino, args[0])
if err != nil {
return err
}

from := clientCtx.GetFromAddress()
content := &proposal.Proposal

devTest, err := cmd.Flags().GetBool(devTestFlagName)
if err == nil && devTest {
// modify the lava spec for dev tests
for idx, spec := range content.Specs {
if spec.Index == "LAV1" {
utilslib.LavaFormatInfo("modified lava spec time for dev tests")
content.Specs[idx].AverageBlockTime = (1 * time.Second).Milliseconds()
for collection := range content.Specs[idx].ApiCollections {
for verification := range content.Specs[idx].ApiCollections[collection].Verifications {
if content.Specs[idx].ApiCollections[collection].Verifications[verification].Name == "chain-id" {
content.Specs[idx].ApiCollections[collection].Verifications[verification].Values[0].ExpectedValue = "*"
}
if content.Specs[idx].ApiCollections[collection].Verifications[verification].Name == "pruning" {
content.Specs[idx].ApiCollections[collection].Verifications = append(content.Specs[idx].ApiCollections[collection].Verifications[:verification], content.Specs[idx].ApiCollections[collection].Verifications[verification+1:]...)
}
}
}
}
}
}

msgAddSpecs := types.NewMsgAddSpecs(from.String(), content.Specs)
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msgAddSpecs)
},
}
cmd.Flags().Bool(devTestFlagName, false, "set to true to modify the average block time for lava spec")
flags.AddTxFlagsToCmd(cmd)
return cmd
}
14 changes: 10 additions & 4 deletions x/spec/client/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,21 @@ import (

type (
SpecAddProposalJSON struct {
Proposal types.SpecAddProposal `json:"proposal"`
Deposit string `json:"deposit" yaml:"deposit"`
Title string `json:"title"`
Description string `json:"description"`
Specs []types.Spec `json:"specs"`
}

SpecAddProposalWithDepositJSON struct {
Proposal SpecAddProposalJSON `json:"proposal"`
Deposit string `json:"deposit" yaml:"deposit"`
}
)

// Parse spec add proposal JSON form file
func ParseSpecAddProposalJSON(cdc *codec.LegacyAmino, proposalFile string) (ret SpecAddProposalJSON, err error) {
func ParseSpecAddProposalJSON(cdc *codec.LegacyAmino, proposalFile string) (ret SpecAddProposalWithDepositJSON, err error) {
for _, fileName := range strings.Split(proposalFile, ",") {
proposal := SpecAddProposalJSON{}
proposal := SpecAddProposalWithDepositJSON{}

contents, err := os.ReadFile(fileName)
if err != nil {
Expand Down
5 changes: 5 additions & 0 deletions x/spec/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type (
paramstore paramtypes.Subspace

stakingKeeper types.StakingKeeper
authority string
}
)

Expand All @@ -30,6 +31,7 @@ func NewKeeper(
memKey storetypes.StoreKey,
ps paramtypes.Subspace,
stakingKeeper types.StakingKeeper,
authority string,
) *Keeper {
// set KeyTable if it has not already been set
if !ps.HasKeyTable() {
Expand All @@ -42,6 +44,7 @@ func NewKeeper(
memKey: memKey,
paramstore: ps,
stakingKeeper: stakingKeeper,
authority: authority,
}
}

Expand All @@ -50,3 +53,5 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger {
}

func (k Keeper) BeginBlock(ctx sdk.Context) {}

func (k Keeper) GetAuthority() string { return k.authority }
Loading
Loading