diff --git a/Readme.md b/Readme.md index 07a96d1a34..bb5ecfe670 100644 --- a/Readme.md +++ b/Readme.md @@ -56,9 +56,9 @@ LAVA_BINARY=lavad make install Or check out the latest [release](https://github.com/lavanet/lava/releases). -### Add `lavad` autocomplete +### Add `lavad`/`lavap` autocomplete -You can add a useful autocomplete feature to `lavad` with a simple bash [script](https://github.com/lavanet/lava/blob/update-readme-autocomplete/scripts/lavad_auto_completion_install.sh). +You can add a useful autocomplete feature to `lavad` & `lavap` with a simple bash [script](https://github.com/lavanet/lava/blob/main/scripts/lavad_auto_completion_install.sh). ### Quick Start diff --git a/app/app.go b/app/app.go index 085bcf694a..3825f2f4ae 100644 --- a/app/app.go +++ b/app/app.go @@ -164,6 +164,7 @@ var Upgrades = []upgrades.Upgrade{ upgrades.Upgrade_0_31_0, upgrades.Upgrade_0_31_1, upgrades.Upgrade_0_32_0, + upgrades.Upgrade_0_32_3, } // this line is used by starport scaffolding # stargate/wasm/app/enabledProposals @@ -241,6 +242,7 @@ var ( string(rewardsmoduletypes.ValidatorsRewardsDistributionPoolName): {authtypes.Burner, authtypes.Staking}, string(rewardsmoduletypes.ProviderRewardsDistributionPool): {authtypes.Burner, authtypes.Staking}, string(rewardsmoduletypes.ProvidersRewardsAllocationPool): {authtypes.Minter, authtypes.Staking}, + dualstakingmoduletypes.ModuleName: {authtypes.Burner, authtypes.Staking}, // this line is used by starport scaffolding # stargate/app/maccPerms } ) diff --git a/app/upgrades/empty_upgrades.go b/app/upgrades/empty_upgrades.go index 405506aaaa..3a5a188c19 100644 --- a/app/upgrades/empty_upgrades.go +++ b/app/upgrades/empty_upgrades.go @@ -181,3 +181,9 @@ var Upgrade_0_32_0 = Upgrade{ Deleted: []string{minttypes.StoreKey}, }, } + +var Upgrade_0_32_3 = Upgrade{ + UpgradeName: "v0.32.3", + CreateUpgradeHandler: defaultUpgradeHandler, + StoreUpgrades: store.StoreUpgrades{}, +} diff --git a/cmd/lavad/cmd/genaccounts.go b/cmd/lavad/cmd/genaccounts.go index ca2db2b560..ec0dca4070 100644 --- a/cmd/lavad/cmd/genaccounts.go +++ b/cmd/lavad/cmd/genaccounts.go @@ -20,10 +20,12 @@ import ( ) const ( - flagVestingStart = "vesting-start-time" - flagVestingEnd = "vesting-end-time" - flagVestingAmt = "vesting-amount" - flagModuleAccount = "module-account" + flagVestingStart = "vesting-start-time" + flagVestingEnd = "vesting-end-time" + flagVestingAmt = "vesting-amount" + flagModuleAccount = "module-account" + flagPeriodicLength = "periodic-length" + flagPeriodicNumber = "periodic-Number" ) // AddGenesisAccountCmd returns add-genesis-account cobra Command. @@ -102,6 +104,16 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa return fmt.Errorf("failed to parse vesting amount: %w", err) } + periodicLength, err := cmd.Flags().GetInt64(flagPeriodicLength) + if err != nil { + return err + } + + periodicNumber, err := cmd.Flags().GetInt64(flagPeriodicNumber) + if err != nil { + return err + } + // create concrete account type based on input parameters var genAccount authtypes.GenesisAccount @@ -121,6 +133,30 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa } switch { + case periodicLength != 0 || periodicNumber != 0: + if periodicLength <= 0 { + return errors.New("periodic account must set periodicLength flag") + } + + if periodicNumber <= 0 { + return errors.New("periodic account must set periodicNumber flag") + } + + if vestingStart <= 0 { + return errors.New("periodic account must have vesting start flag") + } + + if !vestingAmt.QuoInt(sdk.NewInt(periodicNumber)).MulInt(sdk.NewInt(periodicNumber)).IsEqual(vestingAmt) { + return errors.New("periodic vesting amount must be divisble by the periodicNumber") + } + + var periods []authvesting.Period + for i := int64(0); i < periodicNumber; i++ { + period := authvesting.Period{Length: periodicLength, Amount: vestingAmt.QuoInt(sdk.NewInt(periodicNumber))} + periods = append(periods, period) + } + + genAccount = authvesting.NewPeriodicVestingAccount(baseAccount, vestingAmt, vestingStart, periods) case vestingStart != 0 && vestingEnd != 0: genAccount = authvesting.NewContinuousVestingAccountRaw(baseVestingAccount, vestingStart) @@ -200,6 +236,9 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa cmd.Flags().Int64(flagVestingStart, 0, "schedule start time (unix epoch) for vesting accounts") cmd.Flags().Int64(flagVestingEnd, 0, "schedule end time (unix epoch) for vesting accounts") cmd.Flags().Bool(flagModuleAccount, false, "create a module account") + cmd.Flags().Int64(flagPeriodicLength, 0, "length of the each period") + cmd.Flags().Int64(flagPeriodicNumber, 0, "number of periods") + flags.AddQueryFlagsToCmd(cmd) return cmd diff --git a/config/rpcconsumer_test.yml b/config/rpcconsumer_test.yml index 1ca0d54810..48ce63a48f 100644 --- a/config/rpcconsumer_test.yml +++ b/config/rpcconsumer_test.yml @@ -1,14 +1,13 @@ endpoints: - - chain-id: EVMOS + - chain-id: LAV1 api-interface: tendermintrpc - network-address: 127.0.0.1:3333 - - chain-id: EVMOS + network-address: 127.0.0.1:3360 + - chain-id: LAV1 api-interface: rest - network-address: 127.0.0.1:3334 - - chain-id: EVMOS + network-address: 127.0.0.1:3361 + - chain-id: LAV1 api-interface: grpc - network-address: 127.0.0.1:3335 - - chain-id: EVMOS - api-interface: jsonrpc - network-address: 127.0.0.1:3336 + network-address: 127.0.0.1:3362 + tls-enabled: true + health-check-path: "/" metrics-listen-address: ":7779" \ No newline at end of file diff --git a/go.mod b/go.mod index 13af56f9cc..18917a6609 100644 --- a/go.mod +++ b/go.mod @@ -28,6 +28,7 @@ require ( require ( cosmossdk.io/errors v1.0.0 cosmossdk.io/math v1.2.0 + github.com/cosmos/cosmos-proto v1.0.0-beta.2 github.com/cosmos/gogoproto v1.4.10 github.com/dgraph-io/badger/v4 v4.1.0 github.com/fullstorydev/grpcurl v1.8.5 @@ -68,7 +69,6 @@ require ( github.com/cockroachdb/errors v1.10.0 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect github.com/cockroachdb/redact v1.1.5 // indirect - github.com/cosmos/cosmos-proto v1.0.0-beta.2 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/ics23/go v0.10.0 // indirect github.com/cosmos/rosetta-sdk-go v0.10.0 // indirect diff --git a/proto/lavanet/lava/subscription/query.proto b/proto/lavanet/lava/subscription/query.proto index 16caca7778..632b92e006 100644 --- a/proto/lavanet/lava/subscription/query.proto +++ b/proto/lavanet/lava/subscription/query.proto @@ -21,12 +21,12 @@ service Query { option (google.api.http).get = "/lavanet/lava/subscription/current/{consumer}"; } -// Queries a list of ListProjects items. + // Queries a list of ListProjects items. rpc ListProjects(QueryListProjectsRequest) returns (QueryListProjectsResponse) { option (google.api.http).get = "/lavanet/lava/subscription/list_projects/{subscription}"; } -// Queries a list of List items. + // Queries a list of List items. rpc List(QueryListRequest) returns (QueryListResponse) { option (google.api.http).get = "/lavanet/lava/subscription/list"; } @@ -80,7 +80,9 @@ message ListInfoStruct { uint64 month_cu_left = 7; // remaining CU allowance this month string cluster = 8; uint64 duration_total = 9; - bool auto_renewal = 10; + reserved 10; + string auto_renewal_next_plan = 11; + FutureSubscription future_subscription = 12; } message QueryNextToMonthExpiryRequest { diff --git a/proto/lavanet/lava/subscription/subscription.proto b/proto/lavanet/lava/subscription/subscription.proto index e60780e6c2..c6f8c6d86c 100644 --- a/proto/lavanet/lava/subscription/subscription.proto +++ b/proto/lavanet/lava/subscription/subscription.proto @@ -18,8 +18,9 @@ message Subscription { reserved 12; string cluster = 13; // cluster key uint64 duration_total = 14; // continous subscription usage - bool auto_renewal = 15; // automatic renewal when the subscription expires + reserved 15; // automatic renewal when the subscription expires FutureSubscription future_subscription = 16; // future subscription made with buy --advance-purchase + string auto_renewal_next_plan = 17; // the next plan to subscribe to. If none is set, then auto renewal is disabled } message FutureSubscription { diff --git a/proto/lavanet/lava/subscription/tx.proto b/proto/lavanet/lava/subscription/tx.proto index ac10f8fd93..6cdf08ebcd 100644 --- a/proto/lavanet/lava/subscription/tx.proto +++ b/proto/lavanet/lava/subscription/tx.proto @@ -47,6 +47,8 @@ message MsgDelProjectResponse { message MsgAutoRenewal { string creator = 1; bool enable = 2; + string consumer = 3; + string index = 4; } message MsgAutoRenewalResponse { diff --git a/protocol/chainlib/grpc.go b/protocol/chainlib/grpc.go index 766fb1f6d4..0445def4e6 100644 --- a/protocol/chainlib/grpc.go +++ b/protocol/chainlib/grpc.go @@ -317,7 +317,7 @@ func (apil *GrpcChainListener) Serve(ctx context.Context) { return relayReply.Data, convertRelayMetaDataToMDMetaData(metadataToReply), nil } - _, httpServer, err := grpcproxy.NewGRPCProxy(sendRelayCallback) + _, httpServer, err := grpcproxy.NewGRPCProxy(sendRelayCallback, apil.endpoint.HealthCheckPath) if err != nil { utils.LavaFormatFatal("provider failure RegisterServer", err, utils.Attribute{Key: "listenAddr", Value: apil.endpoint.NetworkAddress}) } @@ -327,7 +327,21 @@ func (apil *GrpcChainListener) Serve(ctx context.Context) { utils.LavaFormatInfo("Server listening", utils.Attribute{Key: "Address", Value: lis.Addr()}) - if err := httpServer.Serve(lis); !errors.Is(err, http.ErrServerClosed) { + var serveExecutor func() error + if apil.endpoint.TLSEnabled { + utils.LavaFormatInfo("Running with self signed TLS certificate") + var certificateErr error + httpServer.TLSConfig, certificateErr = lavasession.GetSelfSignedConfig() + if certificateErr != nil { + utils.LavaFormatFatal("failed getting a self signed certificate", certificateErr) + } + serveExecutor = func() error { return httpServer.ServeTLS(lis, "", "") } + } else { + utils.LavaFormatInfo("Running with disabled TLS configuration") + serveExecutor = func() error { return httpServer.Serve(lis) } + } + + if err := serveExecutor(); !errors.Is(err, http.ErrServerClosed) { utils.LavaFormatFatal("Portal failed to serve", err, utils.Attribute{Key: "Address", Value: lis.Addr()}, utils.Attribute{Key: "ChainID", Value: apil.endpoint.ChainID}) } } diff --git a/protocol/chainlib/grpcproxy/grpcproxy.go b/protocol/chainlib/grpcproxy/grpcproxy.go index 3e15b55c41..4bd3c32f63 100644 --- a/protocol/chainlib/grpcproxy/grpcproxy.go +++ b/protocol/chainlib/grpcproxy/grpcproxy.go @@ -16,20 +16,25 @@ import ( type ProxyCallBack = func(ctx context.Context, method string, reqBody []byte) ([]byte, metadata.MD, error) -func NewGRPCProxy(cb ProxyCallBack) (*grpc.Server, *http.Server, error) { +func NewGRPCProxy(cb ProxyCallBack, healthCheckPath string) (*grpc.Server, *http.Server, error) { s := grpc.NewServer(grpc.UnknownServiceHandler(makeProxyFunc(cb)), grpc.ForceServerCodec(RawBytesCodec{})) wrappedServer := grpcweb.WrapServer(s) handler := func(resp http.ResponseWriter, req *http.Request) { // Set CORS headers resp.Header().Set("Access-Control-Allow-Origin", "*") resp.Header().Set("Access-Control-Allow-Headers", "Content-Type,x-grpc-web") - + if req.URL.Path == healthCheckPath && req.Method == http.MethodGet { + resp.WriteHeader(200) + _, _ = resp.Write(make([]byte, 0)) + return + } wrappedServer.ServeHTTP(resp, req) } httpServer := &http.Server{ Handler: h2c.NewHandler(http.HandlerFunc(handler), &http2.Server{}), } + return s, httpServer, nil } diff --git a/protocol/chainlib/grpcproxy/grpcproxy_test.go b/protocol/chainlib/grpcproxy/grpcproxy_test.go index abb256bf22..a871534e87 100644 --- a/protocol/chainlib/grpcproxy/grpcproxy_test.go +++ b/protocol/chainlib/grpcproxy/grpcproxy_test.go @@ -20,7 +20,7 @@ func TestGRPCProxy(t *testing.T) { responseHeaders := make(metadata.MD) responseHeaders["test-headers"] = append(responseHeaders["test-headers"], "55") return respBytes, responseHeaders, nil - }) + }, "") require.NoError(t, err) client := testproto.NewTestClient(testproto.InMemoryClientConn(t, proxyGRPCSrv)) diff --git a/protocol/chainlib/jsonRPC.go b/protocol/chainlib/jsonRPC.go index 86c7dd5ec7..6cda46d3b4 100644 --- a/protocol/chainlib/jsonRPC.go +++ b/protocol/chainlib/jsonRPC.go @@ -451,6 +451,10 @@ func (apil *JsonRPCChainListener) Serve(ctx context.Context) { return addHeadersAndSendString(fiberCtx, reply.GetMetadata(), response) }) + app.Get(apil.endpoint.HealthCheckPath, func(fiberCtx *fiber.Ctx) error { + fiberCtx.Status(http.StatusOK) + return fiberCtx.SendString("Health status OK") + }) // Go ListenWithRetry(app, apil.endpoint.NetworkAddress) } diff --git a/protocol/chainlib/rest.go b/protocol/chainlib/rest.go index d880e1e31f..5137019223 100644 --- a/protocol/chainlib/rest.go +++ b/protocol/chainlib/rest.go @@ -331,6 +331,10 @@ func (apil *RestChainListener) Serve(ctx context.Context) { query := "?" + string(fiberCtx.Request().URI().QueryString()) path := "/" + fiberCtx.Params("*") + if path == apil.endpoint.HealthCheckPath { + fiberCtx.Status(http.StatusOK) + return fiberCtx.SendString("Health status OK") + } dappID := extractDappIDFromFiberContext(fiberCtx) analytics := metrics.NewRelayAnalytics(dappID, chainID, apiInterface) diff --git a/protocol/chainlib/tendermintRPC.go b/protocol/chainlib/tendermintRPC.go index 005a21581d..9ba5b2cd3c 100644 --- a/protocol/chainlib/tendermintRPC.go +++ b/protocol/chainlib/tendermintRPC.go @@ -474,6 +474,10 @@ func (apil *TendermintRpcChainListener) Serve(ctx context.Context) { startTime := time.Now() query := "?" + string(fiberCtx.Request().URI().QueryString()) path := fiberCtx.Params("*") + if "/"+path == apil.endpoint.HealthCheckPath { + fiberCtx.Status(http.StatusOK) + return fiberCtx.SendString("Health status OK") + } dappID := extractDappIDFromFiberContext(fiberCtx) ctx, cancel := context.WithCancel(context.Background()) guid := utils.GenerateUniqueIdentifier() diff --git a/protocol/common/endpoints.go b/protocol/common/endpoints.go index 82013c2f78..ec0f346ee9 100644 --- a/protocol/common/endpoints.go +++ b/protocol/common/endpoints.go @@ -27,6 +27,8 @@ const ( BLOCK_PROVIDERS_ADDRESSES_HEADER_NAME = "lava-providers-block" RELAY_TIMEOUT_HEADER_NAME = "lava-relay-timeout" EXTENSION_OVERRIDE_HEADER_NAME = "lava-extension" + // send http request to /lava/health to see if the process is up - (ret code 200) + DEFAULT_HEALTH_PATH = "/lava/health" ) type NodeUrl struct { diff --git a/protocol/lavasession/common.go b/protocol/lavasession/common.go index a76526441b..0b3ffdb2b9 100644 --- a/protocol/lavasession/common.go +++ b/protocol/lavasession/common.go @@ -112,6 +112,16 @@ func GetCaCertificate(serverCertPath, serverKeyPath string) (*tls.Config, error) }, nil } +func GetSelfSignedConfig() (*tls.Config, error) { + cert, err := GenerateSelfSignedCertificate() + if err != nil { + return nil, utils.LavaFormatError("failed to generate TLS certificate", err) + } + return &tls.Config{ + Certificates: []tls.Certificate{cert}, + }, nil +} + func GetTlsConfig(networkAddress NetworkAddressData) *tls.Config { var tlsConfig *tls.Config var err error @@ -122,12 +132,9 @@ func GetTlsConfig(networkAddress NetworkAddressData) *tls.Config { utils.LavaFormatFatal("failed to generate TLS certificate", err) } } else { - cert, err := GenerateSelfSignedCertificate() + tlsConfig, err = GetSelfSignedConfig() if err != nil { - utils.LavaFormatFatal("failed to generate TLS certificate", err) - } - tlsConfig = &tls.Config{ - Certificates: []tls.Certificate{cert}, + utils.LavaFormatFatal("failed GetSelfSignedConfig", err) } } return tlsConfig diff --git a/protocol/lavasession/consumer_session_manager_test.go b/protocol/lavasession/consumer_session_manager_test.go index 75565d761d..e8a52d7f7a 100644 --- a/protocol/lavasession/consumer_session_manager_test.go +++ b/protocol/lavasession/consumer_session_manager_test.go @@ -45,7 +45,7 @@ func CreateConsumerSessionManager() *ConsumerSessionManager { AllowInsecureConnectionToProviders = true // set to allow insecure for tests purposes rand.InitRandomSeed() baseLatency := common.AverageWorldLatency / 2 // we want performance to be half our timeout or better - return NewConsumerSessionManager(&RPCEndpoint{"stub", "stub", "stub", 0}, provideroptimizer.NewProviderOptimizer(provideroptimizer.STRATEGY_BALANCED, 0, baseLatency, 1), nil) + return NewConsumerSessionManager(&RPCEndpoint{"stub", "stub", "stub", false, "/", 0}, provideroptimizer.NewProviderOptimizer(provideroptimizer.STRATEGY_BALANCED, 0, baseLatency, 1), nil) } var grpcServer *grpc.Server diff --git a/protocol/lavasession/consumer_types.go b/protocol/lavasession/consumer_types.go index 720b71d482..6f4a8459ee 100644 --- a/protocol/lavasession/consumer_types.go +++ b/protocol/lavasession/consumer_types.go @@ -98,10 +98,12 @@ type SessionWithProvider struct { type SessionWithProviderMap map[string]*SessionWithProvider type RPCEndpoint struct { - NetworkAddress string `yaml:"network-address,omitempty" json:"network-address,omitempty" mapstructure:"network-address"` // HOST:PORT - ChainID string `yaml:"chain-id,omitempty" json:"chain-id,omitempty" mapstructure:"chain-id"` // spec chain identifier - ApiInterface string `yaml:"api-interface,omitempty" json:"api-interface,omitempty" mapstructure:"api-interface"` - Geolocation uint64 `yaml:"geolocation,omitempty" json:"geolocation,omitempty" mapstructure:"geolocation"` + NetworkAddress string `yaml:"network-address,omitempty" json:"network-address,omitempty" mapstructure:"network-address"` // HOST:PORT + ChainID string `yaml:"chain-id,omitempty" json:"chain-id,omitempty" mapstructure:"chain-id"` // spec chain identifier + ApiInterface string `yaml:"api-interface,omitempty" json:"api-interface,omitempty" mapstructure:"api-interface"` + TLSEnabled bool `yaml:"tls-enabled,omitempty" json:"tls-enabled,omitempty" mapstructure:"tls-enabled"` + HealthCheckPath string `yaml:"health-check-path,omitempty" json:"health-check-path,omitempty" mapstructure:"health-check-path"` // health check status code 200 path, default is "/" + Geolocation uint64 `yaml:"geolocation,omitempty" json:"geolocation,omitempty" mapstructure:"geolocation"` } func (endpoint *RPCEndpoint) String() (retStr string) { diff --git a/protocol/rpcconsumer/rpcconsumer.go b/protocol/rpcconsumer/rpcconsumer.go index bf2e45c4f8..00df175a16 100644 --- a/protocol/rpcconsumer/rpcconsumer.go +++ b/protocol/rpcconsumer/rpcconsumer.go @@ -278,6 +278,9 @@ func ParseEndpoints(viper_endpoints *viper.Viper, geolocation uint64) (endpoints } for _, endpoint := range endpoints { endpoint.Geolocation = geolocation + if endpoint.HealthCheckPath == "" { + endpoint.HealthCheckPath = common.DEFAULT_HEALTH_PATH + } } return } diff --git a/protocol/rpcconsumer/rpcconsumer_server.go b/protocol/rpcconsumer/rpcconsumer_server.go index cb2a6120b1..c456ec29eb 100644 --- a/protocol/rpcconsumer/rpcconsumer_server.go +++ b/protocol/rpcconsumer/rpcconsumer_server.go @@ -304,7 +304,7 @@ func (rpccs *RPCConsumerServer) SendRelay( if len(relayResults) == 0 { rpccs.appendHeadersToRelayResult(ctx, errorRelayResult, retries) // suggest the user to add the timeout flag - if uint64(timeouts) == retries { + if uint64(timeouts) == retries && retries > 0 { utils.LavaFormatDebug("all relays timeout", utils.Attribute{Key: "GUID", Value: ctx}, utils.Attribute{Key: "errors", Value: relayErrors.relayErrors}) return errorRelayResult, utils.LavaFormatError("Failed all relay retries due to timeout consider adding 'lava-relay-timeout' header to extend the allowed timeout duration", nil, utils.Attribute{Key: "GUID", Value: ctx}) } diff --git a/protocol/rpcprovider/provider_listener.go b/protocol/rpcprovider/provider_listener.go index 51a83706a8..9c62d909f2 100644 --- a/protocol/rpcprovider/provider_listener.go +++ b/protocol/rpcprovider/provider_listener.go @@ -74,7 +74,7 @@ func NewProviderListener(ctx context.Context, networkAddress lavasession.Network var serveExecutor func() error if networkAddress.DisableTLS { - utils.LavaFormatWarning("Running with disabled TLS configuration", nil) + utils.LavaFormatInfo("Running with disabled TLS configuration") serveExecutor = func() error { return pl.httpServer.Serve(lis) } } else { pl.httpServer.TLSConfig = lavasession.GetTlsConfig(networkAddress) diff --git a/protocol/statetracker/tx_sender.go b/protocol/statetracker/tx_sender.go index 4be0a855b7..a95ed0bfa4 100644 --- a/protocol/statetracker/tx_sender.go +++ b/protocol/statetracker/tx_sender.go @@ -196,6 +196,7 @@ func (ts *TxSender) SendTxAndVerifyCommit(txfactory tx.Factory, msg sdk.Msg) (pa utils.LavaFormatDebug("transaction results", utils.Attribute{Key: "jsonParsedResult", Value: jsonParsedResult}) } resultData, err := common.ParseTransactionResult(jsonParsedResult) + utils.LavaFormatDebug("Sent Transaction", utils.LogAttr("Hash", string(resultData.Txhash))) if err != nil { return common.TxResultData{}, err } @@ -218,6 +219,7 @@ func (ts *TxSender) waitForTxCommit(resultData common.TxResultData) (common.TxRe result, err := clientCtx.Client.Tx(ctx, resultData.Txhash, false) cancel() if err == nil { + utils.LavaFormatDebug("Tx Found successfully on chain!", utils.LogAttr("Hash", string(resultData.Txhash))) txResultChan <- result return } diff --git a/scripts/lavad_auto_completion_install.sh b/scripts/lava_auto_completion_install.sh similarity index 97% rename from scripts/lavad_auto_completion_install.sh rename to scripts/lava_auto_completion_install.sh index 91c6d0b84d..c4995de400 100755 --- a/scripts/lavad_auto_completion_install.sh +++ b/scripts/lava_auto_completion_install.sh @@ -40,7 +40,7 @@ case $terminal_type in bashrc_file="$HOME/.bash_profile" fi - if ! grep -q "source $file" $bashrc_file; then + if ! grep -q "source \$file" $bashrc_file; then echo >> $bashrc_file echo "if [ -d $comp_dir ]; then" >> $bashrc_file echo " for file in $comp_dir/*; do" >> $bashrc_file @@ -66,7 +66,7 @@ case $terminal_type in bashrc_file="$HOME/.bash_profile" fi - if ! grep -q "source $file" $bashrc_file; then + if ! grep -q "source \$file" $bashrc_file; then echo >> $bashrc_file echo "if [ -d $comp_dir ]; then" >> $bashrc_file echo " for file in $comp_dir/*; do" >> $bashrc_file diff --git a/scripts/pre_setups/init_evmos_only_with_node.sh b/scripts/pre_setups/init_evmos_only_with_node.sh index 2c2e8510af..2d581f40c0 100755 --- a/scripts/pre_setups/init_evmos_only_with_node.sh +++ b/scripts/pre_setups/init_evmos_only_with_node.sh @@ -16,8 +16,9 @@ make install-all echo "[Test Setup] setting up a new lava node" screen -d -m -S node bash -c "./scripts/start_env_dev.sh" screen -ls -echo "[Test Setup] sleeping 20 seconds for node to finish setup (if its not enough increase timeout)" -sleep 20 +echo "[Test Setup] waiting blocks to start progressing" +sleep 3 +wait_for_lava_node_to_start GASPRICE="0.000000001ulava" lavad tx gov submit-legacy-proposal spec-add ./cookbook/specs/spec_add_ibc.json,./cookbook/specs/spec_add_cosmoswasm.json,./cookbook/specs/spec_add_cosmossdk.json,./cookbook/specs/spec_add_cosmossdk_45.json,./cookbook/specs/spec_add_cosmossdk_full.json,./cookbook/specs/spec_add_ethereum.json,./cookbook/specs/spec_add_cosmoshub.json,./cookbook/specs/spec_add_lava.json,./cookbook/specs/spec_add_osmosis.json,./cookbook/specs/spec_add_fantom.json,./cookbook/specs/spec_add_celo.json,./cookbook/specs/spec_add_optimism.json,./cookbook/specs/spec_add_arbitrum.json,./cookbook/specs/spec_add_starknet.json,./cookbook/specs/spec_add_aptos.json,./cookbook/specs/spec_add_juno.json,./cookbook/specs/spec_add_polygon.json,./cookbook/specs/spec_add_evmos.json,./cookbook/specs/spec_add_base.json,./cookbook/specs/spec_add_canto.json,./cookbook/specs/spec_add_sui.json,./cookbook/specs/spec_add_solana.json,./cookbook/specs/spec_add_bsc.json,./cookbook/specs/spec_add_axelar.json,./cookbook/specs/spec_add_avalanche.json,./cookbook/specs/spec_add_fvm.json --lava-dev-test -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE & @@ -27,7 +28,7 @@ lavad tx gov vote 1 yes -y --from alice --gas-adjustment "1.5" --gas "auto" --ga sleep 4 # Plans proposal -lavad tx gov submit-legacy-proposal plans-add ./cookbook/plans/default.json,./cookbook/plans/temporary-add.json -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE +lavad tx gov submit-legacy-proposal plans-add ./cookbook/plans/test_plans/default.json,./cookbook/plans/test_plans/temporary-add.json -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE wait_next_block wait_next_block lavad tx gov vote 2 yes -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE diff --git a/scripts/pre_setups/init_lava_only_with_node.sh b/scripts/pre_setups/init_lava_only_with_node.sh index 20c9a6c2a2..cee1d1ad7b 100755 --- a/scripts/pre_setups/init_lava_only_with_node.sh +++ b/scripts/pre_setups/init_lava_only_with_node.sh @@ -17,7 +17,8 @@ echo "[Test Setup] setting up a new lava node" screen -d -m -S node bash -c "./scripts/start_env_dev.sh" screen -ls echo "[Test Setup] sleeping 20 seconds for node to finish setup (if its not enough increase timeout)" -sleep 20 +sleep 5 +wait_for_lava_node_to_start GASPRICE="0.000000001ulava" lavad tx gov submit-legacy-proposal spec-add ./cookbook/specs/spec_add_ibc.json,./cookbook/specs/spec_add_cosmoswasm.json,./cookbook/specs/spec_add_cosmossdk.json,./cookbook/specs/spec_add_cosmossdk_45.json,./cookbook/specs/spec_add_cosmossdk_full.json,./cookbook/specs/spec_add_ethereum.json,./cookbook/specs/spec_add_cosmoshub.json,./cookbook/specs/spec_add_lava.json,./cookbook/specs/spec_add_osmosis.json,./cookbook/specs/spec_add_fantom.json,./cookbook/specs/spec_add_celo.json,./cookbook/specs/spec_add_optimism.json,./cookbook/specs/spec_add_arbitrum.json,./cookbook/specs/spec_add_starknet.json,./cookbook/specs/spec_add_aptos.json,./cookbook/specs/spec_add_juno.json,./cookbook/specs/spec_add_polygon.json,./cookbook/specs/spec_add_evmos.json,./cookbook/specs/spec_add_base.json,./cookbook/specs/spec_add_canto.json,./cookbook/specs/spec_add_sui.json,./cookbook/specs/spec_add_solana.json,./cookbook/specs/spec_add_bsc.json,./cookbook/specs/spec_add_axelar.json,./cookbook/specs/spec_add_avalanche.json,./cookbook/specs/spec_add_fvm.json --lava-dev-test -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE & @@ -52,7 +53,7 @@ $PROVIDER1_LISTENER LAV1 grpc '$LAVA_GRPC' \ $EXTRA_PROVIDER_FLAGS --geolocation 1 --log_level debug --from servicer1 --chain-id lava --metrics-listen-address ":7776" 2>&1 | tee $LOGS_DIR/PROVIDER1.log" && sleep 0.25 screen -d -m -S consumers bash -c "source ~/.bashrc; lavap rpcconsumer \ -127.0.0.1:3360 LAV1 rest 127.0.0.1:3361 LAV1 tendermintrpc 127.0.0.1:3362 LAV1 grpc \ +./config/rpcconsumer_test.yml \ $EXTRA_PORTAL_FLAGS --geolocation 1 --log_level debug --from user1 --chain-id lava --allow-insecure-provider-dialing --metrics-listen-address ":7779" 2>&1 | tee $LOGS_DIR/CONSUMERS.log" && sleep 0.25 echo "--- setting up screens done ---" diff --git a/scripts/pre_setups/init_lava_only_with_node_with_cache.sh b/scripts/pre_setups/init_lava_only_with_node_with_cache.sh index 0783f77429..fa6b5b3c3d 100755 --- a/scripts/pre_setups/init_lava_only_with_node_with_cache.sh +++ b/scripts/pre_setups/init_lava_only_with_node_with_cache.sh @@ -16,8 +16,9 @@ make install-all echo "[Test Setup] setting up a new lava node" screen -d -m -S node bash -c "./scripts/start_env_dev.sh" screen -ls -echo "[Test Setup] sleeping 20 seconds for node to finish setup (if its not enough increase timeout)" -sleep 20 +echo "[Test Setup] waiting blocks to start progressing" +sleep 5 +wait_for_lava_node_to_start GASPRICE="0.000000001ulava" lavad tx gov submit-legacy-proposal spec-add ./cookbook/specs/spec_add_ibc.json,./cookbook/specs/spec_add_cosmoswasm.json,./cookbook/specs/spec_add_cosmossdk.json,./cookbook/specs/spec_add_cosmossdk_45.json,./cookbook/specs/spec_add_cosmossdk_full.json,./cookbook/specs/spec_add_ethereum.json,./cookbook/specs/spec_add_cosmoshub.json,./cookbook/specs/spec_add_lava.json,./cookbook/specs/spec_add_osmosis.json,./cookbook/specs/spec_add_fantom.json,./cookbook/specs/spec_add_celo.json,./cookbook/specs/spec_add_optimism.json,./cookbook/specs/spec_add_arbitrum.json,./cookbook/specs/spec_add_starknet.json,./cookbook/specs/spec_add_aptos.json,./cookbook/specs/spec_add_juno.json,./cookbook/specs/spec_add_polygon.json,./cookbook/specs/spec_add_evmos.json,./cookbook/specs/spec_add_base.json,./cookbook/specs/spec_add_canto.json,./cookbook/specs/spec_add_sui.json,./cookbook/specs/spec_add_solana.json,./cookbook/specs/spec_add_bsc.json,./cookbook/specs/spec_add_axelar.json,./cookbook/specs/spec_add_avalanche.json,./cookbook/specs/spec_add_fvm.json -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE & @@ -27,7 +28,7 @@ lavad tx gov vote 1 yes -y --from alice --gas-adjustment "1.5" --gas "auto" --ga sleep 4 # Plans proposal -lavad tx gov submit-legacy-proposal plans-add ./cookbook/plans/default.json,./cookbook/plans/temporary-add.json -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE +lavad tx gov submit-legacy-proposal plans-add ./cookbook/plans/test_plans/default.json,./cookbook/plans/test_plans/temporary-add.json -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE wait_next_block wait_next_block lavad tx gov vote 2 yes -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE @@ -55,8 +56,8 @@ screen -d -m -S cache bash -c "source ~/.bashrc; lavap cache \ 127.0.0.1:20100 --metrics_address 0.0.0.0:20200 --log_level debug 2>&1 | tee $LOGS_DIR/CACHE.log" && sleep 0.25 screen -d -m -S consumers bash -c "source ~/.bashrc; lavap rpcconsumer \ -127.0.0.1:3360 LAV1 rest 127.0.0.1:3361 LAV1 tendermintrpc 127.0.0.1:3362 LAV1 grpc \ -$EXTRA_PORTAL_FLAGS --geolocation 1 --log_level debug --cache-be 127.0.0.1:20100 --from user1 --chain-id lava --allow-insecure-provider-dialing --metrics-listen-address ":7779" 2>&1 | tee $LOGS_DIR/CONSUMERS.log" && sleep 0.25 +./config/rpcconsumer_test.yml \ +$EXTRA_PORTAL_FLAGS --geolocation 1 --log_level debug --cache-be 127.0.0.1:20100 --from user1 --chain-id lava --allow-insecure-provider-dialing 2>&1 | tee $LOGS_DIR/CONSUMERS.log" && sleep 0.25 echo "--- setting up screens done ---" screen -ls \ No newline at end of file diff --git a/scripts/pre_setups/init_starknet_addons_only_with_node.sh b/scripts/pre_setups/init_starknet_addons_only_with_node.sh index 0fc062073c..51dae6bc62 100755 --- a/scripts/pre_setups/init_starknet_addons_only_with_node.sh +++ b/scripts/pre_setups/init_starknet_addons_only_with_node.sh @@ -16,8 +16,9 @@ make install-all echo "[Test Setup] setting up a new lava node" screen -d -m -S node bash -c "./scripts/start_env_dev.sh" screen -ls -echo "[Test Setup] sleeping 20 seconds for node to finish setup (if its not enough increase timeout)" -sleep 20 +echo "[Test Setup] waiting lava node to start" +sleep 3 +wait_for_lava_node_to_start GASPRICE="0.000000001ulava" lavad tx gov submit-legacy-proposal spec-add ./cookbook/specs/spec_add_ibc.json,./cookbook/specs/spec_add_cosmoswasm.json,./cookbook/specs/spec_add_cosmossdk.json,./cookbook/specs/spec_add_cosmossdk_45.json,./cookbook/specs/spec_add_cosmossdk_full.json,./cookbook/specs/spec_add_ethereum.json,./cookbook/specs/spec_add_cosmoshub.json,./cookbook/specs/spec_add_lava.json,./cookbook/specs/spec_add_osmosis.json,./cookbook/specs/spec_add_fantom.json,./cookbook/specs/spec_add_celo.json,./cookbook/specs/spec_add_optimism.json,./cookbook/specs/spec_add_arbitrum.json,./cookbook/specs/spec_add_starknet.json,./cookbook/specs/spec_add_aptos.json,./cookbook/specs/spec_add_juno.json,./cookbook/specs/spec_add_polygon.json,./cookbook/specs/spec_add_evmos.json,./cookbook/specs/spec_add_base.json,./cookbook/specs/spec_add_canto.json,./cookbook/specs/spec_add_sui.json,./cookbook/specs/spec_add_solana.json,./cookbook/specs/spec_add_bsc.json,./cookbook/specs/spec_add_axelar.json,./cookbook/specs/spec_add_avalanche.json,./cookbook/specs/spec_add_fvm.json --lava-dev-test -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE & @@ -27,7 +28,7 @@ lavad tx gov vote 1 yes -y --from alice --gas-adjustment "1.5" --gas "auto" --ga sleep 4 # Plans proposal -lavad tx gov submit-legacy-proposal plans-add ./cookbook/plans/default.json,./cookbook/plans/temporary-add.json -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE +lavad tx gov submit-legacy-proposal plans-add ./cookbook/plans/test_plans/default.json,./cookbook/plans/test_plans/temporary-add.json -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE wait_next_block wait_next_block lavad tx gov vote 2 yes -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE diff --git a/scripts/useful_commands.sh b/scripts/useful_commands.sh index 08fe38c6dc..cddf41e538 100755 --- a/scripts/useful_commands.sh +++ b/scripts/useful_commands.sh @@ -116,4 +116,22 @@ create_health_config() { echo "Comment #REPLACED not found in the file." exit 1 fi +} + + +# Function to extract latest_block_height from lavad status | jq +get_block_height() { + lavad status 2>/dev/null | jq -r '.SyncInfo.latest_block_height' +} + +wait_for_lava_node_to_start() { + # Monitor changes in block height + while true; do + current_height=$(get_block_height) + if [[ "$current_height" =~ ^[0-9]+$ && "$current_height" -gt 5 ]]; then + echo "Block height is now $current_height which is larger than 5" + break + fi + sleep 1 # Check every second + done } \ No newline at end of file diff --git a/testutil/common/tester.go b/testutil/common/tester.go index bab8c589a1..122811df37 100644 --- a/testutil/common/tester.go +++ b/testutil/common/tester.go @@ -56,10 +56,16 @@ func NewTester(t *testing.T) *Tester { // AdvanceBlock() and AdvanceEpoch() always use the current time for the // first block (and ignores the time delta arg if given); So call it here - // to generate a first timestamp and avoid any subsequent call with detla + // to generate a first timestamp and avoid any subsequent call with delta // argument call having the delta ignored. ts.AdvanceEpoch() + // On the 28th above day of the month, some tests fail because NextMonth is always truncating the day + // back to the 28th, so some timers will not trigger after executing ts.AdvanceMonths(1) + if ts.Ctx.BlockTime().Day() >= 26 { + ts.AdvanceBlock(5 * 24 * time.Hour) + } + return ts } @@ -483,10 +489,12 @@ func (ts *Tester) TxSubscriptionDelProject(creator, projectID string) error { } // TxSubscriptionAutoRenewal: implement 'tx subscription auto-renewal' -func (ts *Tester) TxSubscriptionAutoRenewal(creator string, enable bool) error { +func (ts *Tester) TxSubscriptionAutoRenewal(creator, consumer, planIndex string, enable bool) error { msg := &subscriptiontypes.MsgAutoRenewal{ - Creator: creator, - Enable: enable, + Creator: creator, + Consumer: consumer, + Enable: enable, + Index: planIndex, } _, err := ts.Servers.SubscriptionServer.AutoRenewal(ts.GoCtx, msg) return err @@ -954,7 +962,7 @@ func (ts *Tester) AdvanceEpochUntilStale(delta ...time.Duration) *Tester { // so caller can control when to cross the desired time). func (ts *Tester) AdvanceMonthsFrom(from time.Time, months int) *Tester { for next := from; months > 0; months -= 1 { - next = utils.NextMonth(next) + next = next.AddDate(0, 1, 0) delta := next.Sub(ts.BlockTime()) if months == 1 { delta -= 5 * time.Second diff --git a/x/pairing/keeper/delegator_rewards_test.go b/x/pairing/keeper/delegator_rewards_test.go index 46dce551db..3f9116bae5 100644 --- a/x/pairing/keeper/delegator_rewards_test.go +++ b/x/pairing/keeper/delegator_rewards_test.go @@ -349,13 +349,23 @@ func TestQueryDelegatorRewards(t *testing.T) { _, delegator1 := ts.GetAccount(common.CONSUMER, 1) _, delegator2 := ts.GetAccount(common.CONSUMER, 2) // delegates to no one - ts.TxSubscriptionBuy(client, client, "free", 1, false, false) // extend by a month so the sub won't expire + sub, err := ts.QuerySubscriptionCurrent(client) + require.NoError(t, err) + currentDurationLeft := sub.Sub.DurationLeft + require.NotZero(t, currentDurationLeft) + + monthsToBuy := 2 + ts.TxSubscriptionBuy(client, client, ts.plan.Index, monthsToBuy, false, false) // extend by a month so the sub won't expire + + sub, err = ts.QuerySubscriptionCurrent(client) + require.NoError(t, err) + require.Equal(t, currentDurationLeft+uint64(monthsToBuy), sub.Sub.DurationLeft) spec1 := common.CreateMockSpec() spec1.Index = "mock1" spec1.Name = "mock1" ts.AddSpec(spec1.Index, spec1) - err := ts.StakeProvider(provider1, spec1, testStake) + err = ts.StakeProvider(provider1, spec1, testStake) require.Nil(t, err) ts.AdvanceEpoch() diff --git a/x/pairing/keeper/pairing_test.go b/x/pairing/keeper/pairing_test.go index 935f972232..bbeacea638 100644 --- a/x/pairing/keeper/pairing_test.go +++ b/x/pairing/keeper/pairing_test.go @@ -872,7 +872,7 @@ func TestPairingUniformDistribution(t *testing.T) { _, clientAddr := ts.GetAccount(common.CONSUMER, 0) // make the subscription auto-renew so it won't expire after many (pairing) epochs - err := ts.TxSubscriptionAutoRenewal(clientAddr, true) + err := ts.TxSubscriptionAutoRenewal(clientAddr, clientAddr, ts.plan.Index, true) require.NoError(t, err) weightFunc := func(p epochstoragetypes.StakeEntry) int64 { return p.Stake.Amount.Int64() } @@ -899,7 +899,7 @@ func TestPairingDistributionPerStake(t *testing.T) { ts.AdvanceEpoch() // make the subscription auto-renew so it won't expire after many (pairing) epochs - err = ts.TxSubscriptionAutoRenewal(clientAddr, true) + err = ts.TxSubscriptionAutoRenewal(clientAddr, clientAddr, ts.plan.Index, true) require.Nil(t, err) weightFunc := func(p epochstoragetypes.StakeEntry) int64 { return p.Stake.Amount.Int64() } diff --git a/x/protocol/types/params.go b/x/protocol/types/params.go index d90826bbf4..bc409281e8 100644 --- a/x/protocol/types/params.go +++ b/x/protocol/types/params.go @@ -12,7 +12,7 @@ import ( var _ paramtypes.ParamSet = (*Params)(nil) const ( - TARGET_VERSION = "0.31.5" + TARGET_VERSION = "0.32.4" MIN_VERSION = "0.30.1" ) diff --git a/x/rewards/README.md b/x/rewards/README.md index 5d93956d30..3d548342bf 100644 --- a/x/rewards/README.md +++ b/x/rewards/README.md @@ -11,14 +11,17 @@ Please note that this module replaces Cosmos SDK's mint module, which is typical ## Contents * [Concepts](#concepts) - * [The Treasury](#the-treasury) - * [Validators Rewards Pool](#validators-rewards-pool) - * [Providers Rewards Pool](#providers-rewards-pool) + * [The Treasury](#the-treasury) + * [Validators Rewards Pool](#validators-rewards-pool) + * [Providers Rewards Pool](#providers-rewards-pool) * [Parameters](#parameters) - * [MinBondedTarget](#minbondedtarget) - * [MaxBondedTarget](#maxbondedtarget) - * [LowFactor](#lowfactor) - * [LeftOverBurnRate](#leftoverburnrate) + * [MinBondedTarget](#minbondedtarget) + * [MaxBondedTarget](#maxbondedtarget) + * [LowFactor](#lowfactor) + * [LeftOverBurnRate](#leftoverburnrate) +* [Queries](#queries) +* [Transactions](#transactions) +* [Proposals](#proposals) ## Concepts @@ -65,11 +68,11 @@ Besides these rewards, the provider also get monthly bonus rewards from a pre-al The total monthly bonus rewards ("total spec payout") are calculated per spec by the following formula: ```math -\text{Total spec payout}=\\\min\{RewardsMaxBoost\cdot\text{Total Base Payouts}, \\ \text{Spec Payout Cap}, \\ \max\{0,1.5(\text{Spec Payout Cap})-0.5(\text{Total Base Payouts})\}\} +\text{Total spec payout}=\\\min\{MaxRewardsBoost\cdot\text{Total Base Payouts}, \\ \text{Spec Payout Cap}, \\ \max\{0,1.5(\text{Spec Payout Cap})-0.5(\text{Total Base Payouts})\}\} ``` Where: -* $`\text{RewardsMaxBoost}`$ - A module's parameter (see [below](#maxrewardsboost)). +* $`\text{MaxRewardsBoost}`$ - A module's parameter (see [below](#maxrewardsboost)). * $`\text{Total Base Payouts}`$ - The sum of all base payouts the providers for this spec collected = $`\sum_{provider_1.._n} (\text{{provider base rewards}}_i)`$ * $`\text{Spec Payout Cap}`$ - The max value for this spec bonus rewards = $`\frac{specStake\cdot specShares}{\sum_i{specStake \cdot specShares}_i}`$. * SpecStake = Total effective stake of providers in this spec. @@ -81,10 +84,7 @@ The total spec payout is distributed between providers proportional to the rewar Provider Bonus Rewards = Total Spec Payout \cdot \frac{\sum_{\text{payment} \; i} (\text{{provider base rewards}}_{i,j} \times \text{{adjustment}}_{i,j})}{\sum_{\text{provider}\;j'}\sum_{\text{payment} \; i} (\text{{provider base rewards}}_{i,j'} )} ``` -Where: -* Adjustment - TBD - -Note that some of the providers rewards are sent to the community pool (according to the `CommunityTax` parameter, determined by the distribution module) and to the validators block rewards (according to the `ValidatorsSubscriptionParticipation` parameter, see [below](#validatorssubscriptionparticipation)). +Note that some of the providers rewards are sent to the community pool (according to the `CommunityTax` parameter, determined by the distribution module) and to the validators block rewards (according to the `ValidatorsSubscriptionParticipation` parameter, see [below](#validatorssubscriptionparticipation)). For more details about the `adjustment`, see [below](#adjustment). The participation fees are calculated according to the following formulas: @@ -95,6 +95,21 @@ The participation fees are calculated according to the following formulas: ```math \text{Community Participation Fee} = ValidatorsSubscriptionParticipation + CommunityTax\\ - \text{Validators Participation Fee} ``` + +#### Adjustment + +Adjustment is a security mechanism that prevents collusion and abuse of rewards boost. It calculates the distribution of usage across multiple providers for each consumer. The more scattered a consumer's usage is across providers, the higher the bonus rewards they can receive. The adjustment value is always smaller or equal to one and can reduce the bonus rewards by up to $\frac{1}{MaxRewardsBoost}$. + +The adjustment is calculated per epoch using a weighted average based on usage. It considers the consumer's CU (compute units) used with a specific provider relative to the total CU the consumer used. The formula is as follows: + +```math +\text{epochAdjustment}_\text{consumet i, provider j}=\\\min\{1,\;\;\;minAdjustment\cdot(\frac{\sum_{\text{provider }k}{CU_\text{i,k}}}{CU _\text{i,j}})\} +``` + +```math +\text{monthlyAdjustment}_{i,k} = \frac{\sum_{\text{epoch}\; t }\left(CU_\text{i}(t)\cdot \text{epochAdjustment}_{i,k}(t)\right)}{\sum_{\text{epoch}\; t}CU_{i}(t)} +``` + ## Parameters The rewards module contains the following parameters: @@ -141,8 +156,35 @@ To calculate the `BondedTargetFactor` see the following formula (note that the s ### MaxRewardsBoost -TBD +MaxRewardsBoost is a multiplier that determines the maximum bonus for provider rewards from subscriptions. ### ValidatorsSubscriptionParticipation ValidatorsSubscriptionParticipation is used to calculate the providers rewards participation fees. + +## Queries + +The rewards module supports the following queries: + +| Query | Arguments | What it does | +| ---------- | --------------- | ----------------------------------------------| +| `block-reward` | none | show the block reward for validators | +| `pools` | none | show the info of the distribution pools | +| `params` | none | shows the module's parameters | + +## Transactions + +The rewards module does not support any transactions. + +## Proposals + +The rewards module does not support any proposals. + +## Events + +The rewards module has the following events: + +| Event | When it happens | +| ---------- | --------------- | +| `distribution_pools_refill` | a successful distribution rewards pools refill | +| `provider_bonus_rewards` | a successful distribution of provider bonus rewards | diff --git a/x/rewards/keeper/pool_test.go b/x/rewards/keeper/pool_test.go index 0c86d8a077..5cc17ac407 100644 --- a/x/rewards/keeper/pool_test.go +++ b/x/rewards/keeper/pool_test.go @@ -374,8 +374,9 @@ func TestRefillPoolsTimerStore(t *testing.T) { require.Equal(t, expectedMonthsLeft, monthsLeft) ts.AdvanceMonths(1) - month = ts.GetNextMonth(ts.BlockTime()) - ts.BlockTime().UTC().Unix() ts.AdvanceBlock() - testkeeper.EndBlock(ts.Ctx, ts.Keepers) + // testkeeper.EndBlock(ts.Ctx, ts.Keepers) + defaultBlockTime := ts.Keepers.Downtime.GetParams(ts.Ctx).DowntimeDuration.Seconds() + month = ts.GetNextMonth(ts.BlockTime()) - ts.BlockTime().UTC().Unix() - int64(defaultBlockTime) } } diff --git a/x/rewards/keeper/providers.go b/x/rewards/keeper/providers.go index 7440dd40c1..17e6403b7f 100644 --- a/x/rewards/keeper/providers.go +++ b/x/rewards/keeper/providers.go @@ -27,6 +27,7 @@ func (k Keeper) AggregateRewards(ctx sdk.Context, provider, chainid string, adju // Distribute bonus rewards to providers across all chains based on performance func (k Keeper) distributeMonthlyBonusRewards(ctx sdk.Context) { + details := map[string]string{} total := k.TotalPoolTokens(ctx, types.ProviderRewardsDistributionPool) totalRewarded := sdk.ZeroInt() // specs emissions from the total reward pool base on stake @@ -60,9 +61,13 @@ func (k Keeper) distributeMonthlyBonusRewards(ctx sdk.Context) { if err != nil { utils.LavaFormatError("failed to send bonus rewards to provider", err, utils.LogAttr("provider", basepay.Provider)) } + + details[providerAddr.String()+" "+spec.ChainID] = reward.String() } } k.removeAllBasePay(ctx) + + utils.LogLavaEvent(ctx, k.Logger(ctx), types.ProvidersBonusRewardsEventName, details, "provider bonus rewards distributed successfully") } // specTotalPayout calculates the total bonus for a specific spec diff --git a/x/rewards/keeper/rewards.go b/x/rewards/keeper/rewards.go index 49ddcd388c..208f9e315f 100644 --- a/x/rewards/keeper/rewards.go +++ b/x/rewards/keeper/rewards.go @@ -4,6 +4,7 @@ import ( "encoding/binary" "fmt" "math" + "strconv" sdkmath "cosmossdk.io/math" @@ -59,7 +60,8 @@ func (k Keeper) RefillRewardsPools(ctx sdk.Context, _ []byte, data []byte) { monthsLeft = binary.BigEndian.Uint64(data) } - k.refillDistributionPool(ctx, monthsLeft, types.ValidatorsRewardsAllocationPoolName, types.ValidatorsRewardsDistributionPoolName, k.GetParams(ctx).LeftoverBurnRate) + burnRate := k.GetParams(ctx).LeftoverBurnRate + k.refillDistributionPool(ctx, monthsLeft, types.ValidatorsRewardsAllocationPoolName, types.ValidatorsRewardsDistributionPoolName, burnRate) k.refillDistributionPool(ctx, monthsLeft, types.ProvidersRewardsAllocationPool, types.ProviderRewardsDistributionPool, sdk.OneDec()) if monthsLeft > 0 { @@ -71,8 +73,22 @@ func (k Keeper) RefillRewardsPools(ctx sdk.Context, _ []byte, data []byte) { binary.BigEndian.PutUint64(monthsLeftBytes, monthsLeft) // open a new timer for next month - nextMonth := utils.NextMonth(ctx.BlockTime()).UTC().Unix() - k.refillRewardsPoolTS.AddTimerByBlockTime(ctx, uint64(nextMonth), []byte(types.RefillRewardsPoolTimerName), monthsLeftBytes) + nextMonth := utils.NextMonth(ctx.BlockTime()).UTC() + k.refillRewardsPoolTS.AddTimerByBlockTime(ctx, uint64(nextMonth.Unix()), []byte(types.RefillRewardsPoolTimerName), monthsLeftBytes) + + valDistPoolBalance := k.TotalPoolTokens(ctx, types.ValidatorsRewardsDistributionPoolName).Int64() + providerDistPoolBalance := k.TotalPoolTokens(ctx, types.ProviderRewardsDistributionPool).Int64() + nextRefillBlock := k.BlocksToNextTimerExpiry(ctx) + ctx.BlockHeight() + details := map[string]string{ + "allocation_pool_remaining_lifetime": strconv.FormatUint(monthsLeft, 10), + "validators_distribution_pool_balance": strconv.FormatInt(valDistPoolBalance, 10), + "providers_distribution_pool_balance": strconv.FormatInt(providerDistPoolBalance, 10), + "leftover_burn_rate": burnRate.String(), + "next_refill_time": nextMonth.String(), + "next_refill_block": strconv.FormatInt(nextRefillBlock, 10), + } + + utils.LogLavaEvent(ctx, k.Logger(ctx), types.DistributionPoolRefillEventName, details, "distribution rewards pools refilled successfully") } func (k Keeper) refillDistributionPool(ctx sdk.Context, monthsLeft uint64, allocationPool types.Pool, distributionPool types.Pool, burnRate sdkmath.LegacyDec) { diff --git a/x/rewards/types/types.go b/x/rewards/types/types.go index e9adb4a28d..38c17dea19 100644 --- a/x/rewards/types/types.go +++ b/x/rewards/types/types.go @@ -14,6 +14,7 @@ type Pool string // The allocation pools will get depleted after RewardsAllocationPoolsLifetime. const ( ValidatorsRewardsAllocationPoolName Pool = "validators_rewards_allocation_pool" + ProvidersRewardsAllocationPool Pool = "providers_rewards_allocation_pool" RewardsAllocationPoolsLifetime int64 = 48 // 4 years (in months) ) @@ -23,11 +24,9 @@ const ( // monthly quota of tokens from the allocation pools const ( ValidatorsRewardsDistributionPoolName Pool = "validators_rewards_distribution_pool" -) - -const ( - ProvidersRewardsAllocationPool Pool = "providers_rewards_allocation_pool" - ProviderRewardsDistributionPool Pool = "providers_rewards_distribution_pool" + ProviderRewardsDistributionPool Pool = "providers_rewards_distribution_pool" + DistributionPoolRefillEventName = "distribution_pools_refill" + ProvidersBonusRewardsEventName = "provider_bonus_rewards" ) // BlocksToTimerExpirySlackFactor is used to calculate the number of blocks until the diff --git a/x/subscription/client/cli/tx_auto_renewal.go b/x/subscription/client/cli/tx_auto_renewal.go index 87d499d87d..7aa1bdc552 100644 --- a/x/subscription/client/cli/tx_auto_renewal.go +++ b/x/subscription/client/cli/tx_auto_renewal.go @@ -1,45 +1,67 @@ package cli import ( - "strconv" - "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/tx" "github.com/lavanet/lava/x/subscription/types" + "github.com/spf13/cast" "github.com/spf13/cobra" ) -var _ = strconv.Itoa(0) - func CmdAutoRenewal() *cobra.Command { cmd := &cobra.Command{ - Use: "auto-renewal [enable: true/false]", + Use: "auto-renewal [true/false] [optional: plan-index] [optional: consumer]", Short: "Enable/Disable auto-renewal to a subscription", Long: `The auto-renewal command allows the subscription owner (consumer) to enable/disable - auto-renewal to a subscription. When a subscription with enabled auto-renewal expires, it's - automatically extended by one month indefinitely, until the auto-renewal is disabled`, - Example: `required flags: --from - - lavad tx subscription auto-renewal --from `, - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) (err error) { - enableStr := args[0] - enable, err := strconv.ParseBool(enableStr) - if err != nil { +auto-renewal to a subscription. When a subscription with enabled auto-renewal expires, it's +automatically extended by one month indefinitely, until the auto-renewal is disabled. +If 'true' is provided, and plan-index is not provided, the current plan is assumed.`, + Example: `Required flags: --from +lavad tx subscription auto-renewal true --from +lavad tx subscription auto-renewal true explorer --from +lavad tx subscription auto-renewal true explorer --from +lavad tx subscription auto-renewal false --from +lavad tx subscription auto-renewal false --from `, + Args: func(cmd *cobra.Command, args []string) error { + if err := cobra.MinimumNArgs(1)(cmd, args); err != nil { return err } + maxArgCount := 2 // true/false & consumer + if cast.ToBool(args[0]) { // If enabled, expect the plan-index as well + maxArgCount = 3 + } + return cobra.MaximumNArgs(maxArgCount)(cmd, args) + }, + RunE: func(cmd *cobra.Command, args []string) (err error) { clientCtx, err := client.GetClientTxContext(cmd) if err != nil { return err } creator := clientCtx.GetFromAddress().String() + enabled := cast.ToBool(args[0]) + consumer := creator + planIndex := "" + + switch len(args) { + case 2: + if enabled { + planIndex = args[1] + } else { + consumer = args[1] + } + case 3: + planIndex = args[1] + consumer = args[2] + } msg := types.NewMsgAutoRenewal( creator, - enable, + consumer, + planIndex, + enabled, ) if err := msg.ValidateBasic(); err != nil { return err diff --git a/x/subscription/client/cli/tx_buy.go b/x/subscription/client/cli/tx_buy.go index 563999398d..838eb402b6 100644 --- a/x/subscription/client/cli/tx_buy.go +++ b/x/subscription/client/cli/tx_buy.go @@ -12,8 +12,8 @@ import ( ) const ( - EnableAutoRenewalFlag = "enable-auto-renewal" - AdvancedPurchaseFlag = "advance-purchase" + BuyEnableAutoRenewalFlag = "enable-auto-renewal" + AdvancedPurchaseFlag = "advance-purchase" ) func CmdBuy() *cobra.Command { @@ -27,7 +27,8 @@ If the plan index is different than the consumer's current plan, it will upgrade Example: `required flags: --from , optional flags: --enable-auto-renewal lavad tx subscription buy [plan-index] --from lavad tx subscription buy [plan-index] --from 12 - lavad tx subscription buy [plan-index] --from 12 --advanced-purchase`, + lavad tx subscription buy [plan-index] --from 12 --enable-auto-renewal + lavad tx subscription buy [plan-index] --from 12 --advance-purchase`, Args: cobra.RangeArgs(1, 3), RunE: func(cmd *cobra.Command, args []string) (err error) { clientCtx, err := client.GetClientTxContext(cmd) @@ -49,9 +50,9 @@ If the plan index is different than the consumer's current plan, it will upgrade } // check if the command includes --enable-auto-renewal - enableAutoRenewalFlag := cmd.Flags().Lookup(EnableAutoRenewalFlag) + enableAutoRenewalFlag := cmd.Flags().Lookup(BuyEnableAutoRenewalFlag) if enableAutoRenewalFlag == nil { - return fmt.Errorf("%s flag wasn't found", EnableAutoRenewalFlag) + return fmt.Errorf("%s flag wasn't found", BuyEnableAutoRenewalFlag) } autoRenewal := enableAutoRenewalFlag.Changed @@ -78,7 +79,7 @@ If the plan index is different than the consumer's current plan, it will upgrade } flags.AddTxFlagsToCmd(cmd) - cmd.Flags().Bool(EnableAutoRenewalFlag, false, "enables auto-renewal upon expiration") + cmd.Flags().Bool(BuyEnableAutoRenewalFlag, false, "enables auto-renewal upon expiration") cmd.Flags().Bool(AdvancedPurchaseFlag, false, "make an advanced purchase that will be activated once the current subscription ends") return cmd diff --git a/x/subscription/keeper/grpc_query_list.go b/x/subscription/keeper/grpc_query_list.go index 939284a7b6..379dc73cd3 100644 --- a/x/subscription/keeper/grpc_query_list.go +++ b/x/subscription/keeper/grpc_query_list.go @@ -32,16 +32,17 @@ func (k Keeper) List(goCtx context.Context, req *types.QueryListRequest) (*types } subInfoStruct := types.ListInfoStruct{ - Consumer: sub.Consumer, - Plan: sub.PlanIndex, - DurationTotal: sub.DurationTotal, - DurationLeft: sub.DurationLeft, - MonthExpiry: sub.MonthExpiryTime, - MonthCuTotal: sub.MonthCuTotal, - MonthCuLeft: sub.MonthCuLeft, - DurationBought: sub.DurationBought, - Cluster: sub.Cluster, - AutoRenewal: sub.AutoRenewal, + Consumer: sub.Consumer, + Plan: sub.PlanIndex, + DurationTotal: sub.DurationTotal, + DurationLeft: sub.DurationLeft, + MonthExpiry: sub.MonthExpiryTime, + MonthCuTotal: sub.MonthCuTotal, + MonthCuLeft: sub.MonthCuLeft, + DurationBought: sub.DurationBought, + Cluster: sub.Cluster, + AutoRenewalNextPlan: sub.AutoRenewalNextPlan, + FutureSubscription: sub.FutureSubscription, } allSubsInfo = append(allSubsInfo, subInfoStruct) diff --git a/x/subscription/keeper/migrations.go b/x/subscription/keeper/migrations.go index 3143898aea..4e471adc78 100644 --- a/x/subscription/keeper/migrations.go +++ b/x/subscription/keeper/migrations.go @@ -9,6 +9,7 @@ import ( "github.com/lavanet/lava/utils" v2 "github.com/lavanet/lava/x/subscription/migrations/v2" v5 "github.com/lavanet/lava/x/subscription/migrations/v5" + v6 "github.com/lavanet/lava/x/subscription/migrations/v6" "github.com/lavanet/lava/x/subscription/types" ) @@ -149,3 +150,34 @@ func (m Migrator) Migrate5to6(ctx sdk.Context) error { return nil } + +// Migrate6to7 implements store migration from v6 to v7: +// -- if subscription's auto_renewal = true, set auto_renewal_next_plan to the current's subscription plan +func (m Migrator) Migrate6to7(ctx sdk.Context) error { + utils.LavaFormatDebug("migrate 6->7: subscriptions") + + for _, index := range m.keeper.subsFS.GetAllEntryIndices(ctx) { + for _, block := range m.keeper.subsFS.GetAllEntryVersions(ctx, index) { + var subscriptionV6 v6.Subscription + var subscriptionV7 types.Subscription + foundOld := m.keeper.subsFS.FindEntry(ctx, index, block, &subscriptionV6) + foundNew := m.keeper.subsFS.FindEntry(ctx, index, block, &subscriptionV7) + if !foundOld || !foundNew { + utils.LavaFormatError("cannot migrate sub", fmt.Errorf("sub not found"), + utils.Attribute{Key: "index", Value: index}, + utils.Attribute{Key: "block", Value: block}, + ) + } + + if subscriptionV6.AutoRenewal { + subscriptionV7.AutoRenewalNextPlan = subscriptionV7.PlanIndex + } else { + subscriptionV7.AutoRenewalNextPlan = types.AUTO_RENEWAL_PLAN_NONE + } + + m.keeper.subsFS.ModifyEntry(ctx, index, block, &subscriptionV7) + } + } + + return nil +} diff --git a/x/subscription/keeper/msg_server_auto_renewal.go b/x/subscription/keeper/msg_server_auto_renewal.go index 94e4fbff75..868ff302ba 100644 --- a/x/subscription/keeper/msg_server_auto_renewal.go +++ b/x/subscription/keeper/msg_server_auto_renewal.go @@ -3,6 +3,7 @@ package keeper import ( "context" "fmt" + "strings" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/lavanet/lava/utils" @@ -12,22 +13,72 @@ import ( func (k msgServer) AutoRenewal(goCtx context.Context, msg *types.MsgAutoRenewal) (*types.MsgAutoRenewalResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - sub, found := k.GetSubscription(ctx, msg.Creator) + // Find consumer's subscription + sub, found := k.GetSubscription(ctx, msg.Consumer) if !found { return nil, utils.LavaFormatWarning("could not change auto-renewal of subscription", fmt.Errorf("subscription not found"), - utils.Attribute{Key: "sub_consumer", Value: msg.Creator}, + utils.Attribute{Key: "consumer", Value: msg.Consumer}, + ) + } + + // Verify creator either sub.Creator or sub.Consumer + if msg.Creator != sub.Consumer && msg.Creator != sub.Creator { + return nil, utils.LavaFormatWarning("could not change auto-renewal of subscription", fmt.Errorf("creator is not authorized to change auto-renewal for this subscription"), + utils.Attribute{Key: "creator", Value: msg.Creator}, + utils.Attribute{Key: "consumer", Value: msg.Consumer}, ) } - sub.AutoRenewal = msg.Enable - err := k.subsFS.AppendEntry(ctx, msg.Creator, sub.Block, &sub) + // If msg.Enable == false, verify not already disabled + if !msg.Enable && sub.AutoRenewalNextPlan == types.AUTO_RENEWAL_PLAN_NONE { + return nil, utils.LavaFormatWarning("could not change auto-renewal of subscription", fmt.Errorf("auto-renewal is already disabled"), + utils.Attribute{Key: "creator", Value: msg.Creator}, + utils.Attribute{Key: "consumer", Value: msg.Consumer}, + ) + } + + // If msg.Enable == true, verify plan index + if msg.Enable { + if strings.TrimSpace(msg.Index) == "" { + msg.Index = sub.PlanIndex + } + + if _, found := k.plansKeeper.FindPlan(ctx, msg.Index, uint64(ctx.BlockHeight())); !found { + return nil, utils.LavaFormatWarning("could not change auto-renewal of subscription", fmt.Errorf("could not find plan (%s)", msg.Index), + utils.Attribute{Key: "creator", Value: msg.Creator}, + utils.Attribute{Key: "consumer", Value: msg.Consumer}, + utils.Attribute{Key: "index", Value: msg.Index}, + ) + } + } + + if !msg.Enable { + msg.Index = types.AUTO_RENEWAL_PLAN_NONE + } + + // For the event log + prevCreator := sub.Creator + prevAutoRenewalNextPlan := sub.AutoRenewalNextPlan + + sub.Creator = msg.Creator + sub.AutoRenewalNextPlan = msg.Index + err := k.subsFS.AppendEntry(ctx, msg.Consumer, sub.Block, &sub) if err != nil { return nil, utils.LavaFormatError("could not change auto-renewal of subscription", err, utils.Attribute{Key: "sub_consumer", Value: msg.Creator}, - utils.Attribute{Key: "original_auto_renewal", Value: sub.AutoRenewal}, + utils.Attribute{Key: "original_auto_renewal", Value: sub.AutoRenewalNextPlan}, utils.Attribute{Key: "new_auto_renewal", Value: msg.Enable}, ) } + details := map[string]string{ + "prevCreator": prevCreator, + "creator": msg.Creator, + "consumer": msg.Consumer, + "prevAutoRenewPlan": prevAutoRenewalNextPlan, + "newAutoRenewPlan": sub.AutoRenewalNextPlan, + } + utils.LogLavaEvent(ctx, k.Logger(ctx), types.SubscriptionAutoRenewChangeEventName, details, "subscription auto-renew changed") + return &types.MsgAutoRenewalResponse{}, nil } diff --git a/x/subscription/keeper/subscription.go b/x/subscription/keeper/subscription.go index 53a6280022..dbecf8f6c8 100644 --- a/x/subscription/keeper/subscription.go +++ b/x/subscription/keeper/subscription.go @@ -76,63 +76,16 @@ func (k Keeper) CreateSubscription( return utils.LavaFormatWarning("failed to create subscription", err) } } else { - // allow renewal with the same plan ("same" means both plan index); - // otherwise, upgrade the plan. + // Allow renewal with the same plan ("same" means both plan index); + // If the plan index is different - upgrade if the price is higher + // If the plan index is the same but the plan block is different - treat as advanced purchase if plan.Index != sub.PlanIndex { - currentPlan, err := k.GetPlanFromSubscription(ctx, consumer, block) - if err != nil { - return utils.LavaFormatError("failed to find plan for current subscription", err, - utils.LogAttr("consumer", consumer), - utils.LogAttr("block", block), - ) - } - if plan.Price.Amount.LT(currentPlan.Price.Amount) { - return utils.LavaFormatError("New plan's price must be higher than the old plan", nil, - utils.LogAttr("consumer", consumer), - utils.LogAttr("currentPlan", currentPlan), - utils.LogAttr("newPlan", plan), - utils.LogAttr("block", block), - ) - } - originalPlanIndex := sub.PlanIndex - originalPlanBlock := sub.PlanBlock - err = k.upgradeSubscriptionPlan(ctx, duration, &sub, &plan) + err := k.upgradeSubscriptionPlan(ctx, &sub, &plan) if err != nil { return err } - - // Upgrade worked, now we can decrease the old plan's refcount - k.plansKeeper.PutPlan(ctx, originalPlanIndex, originalPlanBlock) - - details := map[string]string{ - "consumer": consumer, - "oldPlan": sub.PlanIndex, - "newPlan": plan.Index, - } - utils.LogLavaEvent(ctx, k.Logger(ctx), types.UpgradeSubscriptionEventName, details, "subscription upgraded") } else if plan.Block != sub.PlanBlock { - // if the plan was changed since the subscription originally bought it, allow extension - // only if the updated plan's price is up to 5% more than the original price - subPlan, found := k.plansKeeper.FindPlan(ctx, plan.Index, sub.PlanBlock) - if !found { - return utils.LavaFormatError("cannot extend subscription", fmt.Errorf("critical: cannot find subscription's plan"), - utils.Attribute{Key: "plan_index", Value: plan.Index}, - utils.Attribute{Key: "block", Value: strconv.FormatUint(sub.PlanBlock, 10)}) - } - if plan.Price.Amount.GT(subPlan.Price.Amount.MulRaw(105).QuoRaw(100)) { - // current_plan_price > 1.05 * original_plan_price - return utils.LavaFormatError("cannot auto-extend subscription", fmt.Errorf("subscription's original plan price is lower by more than 5 percent than current plan"), - utils.Attribute{Key: "sub", Value: sub.Consumer}, - utils.Attribute{Key: "plan", Value: plan.Index}, - utils.Attribute{Key: "original_plan_block", Value: strconv.FormatUint(subPlan.Block, 10)}, - utils.Attribute{Key: "original_plan_price", Value: subPlan.Price.String()}, - utils.Attribute{Key: "current_plan_block", Value: strconv.FormatUint(plan.Block, 10)}, - utils.Attribute{Key: "current_plan_block", Value: plan.Price.String()}, - ) - } - - // update sub plan - sub.PlanBlock = plan.Block + return utils.LavaFormatWarning("requested plan block has changed, can't extend. Please use the --advance-purchase with the same plan index.", nil) } // The total duration may not exceed MAX_SUBSCRIPTION_DURATION, but allow an @@ -154,7 +107,7 @@ func (k Keeper) CreateSubscription( return utils.LavaFormatWarning("create subscription failed", err) } - if !found || sub.AutoRenewal { + if !found { expiry := uint64(utils.NextMonth(ctx.BlockTime()).UTC().Unix()) sub.MonthExpiryTime = expiry sub.Block = block @@ -211,14 +164,20 @@ func (k Keeper) verifySubscriptionBuyInputAndGetPlan(ctx sdk.Context, block uint func (k Keeper) createNewSubscription(ctx sdk.Context, plan *planstypes.Plan, creator, consumer string, block uint64, autoRenewalFlag bool, ) (types.Subscription, error) { + autoRenewalNextPlan := types.AUTO_RENEWAL_PLAN_NONE + if autoRenewalFlag { + // On subscription creation, auto renewal is set to the subscription's plan + autoRenewalNextPlan = plan.Index + } + sub := types.Subscription{ - Creator: creator, - Consumer: consumer, - Block: block, - PlanIndex: plan.Index, - PlanBlock: plan.Block, - DurationTotal: 0, - AutoRenewal: autoRenewalFlag, + Creator: creator, + Consumer: consumer, + Block: block, + PlanIndex: plan.Index, + PlanBlock: plan.Block, + DurationTotal: 0, + AutoRenewalNextPlan: autoRenewalNextPlan, } sub.MonthCuTotal = plan.PlanPolicy.GetTotalCuLimit() @@ -234,9 +193,26 @@ func (k Keeper) createNewSubscription(ctx sdk.Context, plan *planstypes.Plan, cr return sub, nil } -func (k Keeper) upgradeSubscriptionPlan(ctx sdk.Context, duration uint64, sub *types.Subscription, toPlan *planstypes.Plan) error { +func (k Keeper) upgradeSubscriptionPlan(ctx sdk.Context, sub *types.Subscription, newPlan *planstypes.Plan) error { block := uint64(ctx.BlockHeight()) + currentPlan, err := k.GetPlanFromSubscription(ctx, sub.Consumer, block) + if err != nil { + return utils.LavaFormatError("failed to find plan for current subscription", err, + utils.LogAttr("consumer", sub.Consumer), + utils.LogAttr("block", block), + ) + } + + if newPlan.Price.Amount.LT(currentPlan.Price.Amount) { + return utils.LavaFormatError("New plan's price must be higher than the old plan", nil, + utils.LogAttr("consumer", sub.Consumer), + utils.LogAttr("currentPlan", currentPlan), + utils.LogAttr("newPlan", newPlan), + utils.LogAttr("block", block), + ) + } + // Track CU for the previous subscription k.addCuTrackerTimerForSubscription(ctx, block, sub) @@ -252,7 +228,6 @@ func (k Keeper) upgradeSubscriptionPlan(ctx sdk.Context, duration uint64, sub *t // The "old" subscription's duration is now expired // If called from CreateSubscription, the duration will reset to the duration bought sub.DurationLeft = 0 - sub.Cluster = types.GetClusterKey(*sub) nextEpoch, err := k.epochstorageKeeper.GetNextEpoch(ctx, block) if err != nil { @@ -263,11 +238,44 @@ func (k Keeper) upgradeSubscriptionPlan(ctx sdk.Context, duration uint64, sub *t // Remove one refcount for previous plan k.plansKeeper.PutPlan(ctx, sub.PlanIndex, sub.PlanBlock) - sub.PlanIndex = toPlan.Index - sub.PlanBlock = toPlan.Block - sub.MonthCuTotal = toPlan.PlanPolicy.TotalCuLimit + sub.PlanIndex = newPlan.Index + sub.PlanBlock = newPlan.Block + sub.MonthCuTotal = newPlan.PlanPolicy.TotalCuLimit + + k.resetSubscriptionDetailsAndAppendEntry(ctx, sub, nextEpoch, true) + + details := map[string]string{ + "consumer": sub.Consumer, + "oldPlan": sub.PlanIndex, + "newPlan": newPlan.Index, + } + utils.LogLavaEvent(ctx, k.Logger(ctx), types.UpgradeSubscriptionEventName, details, "subscription upgraded") + return nil +} + +func (k Keeper) renewSubscription(ctx sdk.Context, sub *types.Subscription) error { + planIndex := sub.AutoRenewalNextPlan + creatorAcct, plan, err := k.verifySubscriptionBuyInputAndGetPlan(ctx, sub.Block, sub.Creator, sub.Consumer, planIndex) + if err != nil { + return err + } + + sub.PlanIndex = plan.Index + sub.PlanBlock = plan.Block + sub.DurationBought += 1 + sub.DurationLeft = 1 - return k.resetSubscriptionDetailsAndAppendEntry(ctx, sub, nextEpoch, true) + k.resetSubscriptionDetailsAndAppendEntry(ctx, sub, sub.Block, false) + + // Charge creator for 1 extra month + price := plan.GetPrice() + + err = k.chargeFromCreatorAccountToModule(ctx, creatorAcct, price) + if err != nil { + return err + } + + return nil } func (k Keeper) advanceMonth(ctx sdk.Context, subkey []byte) { @@ -316,10 +324,10 @@ func (k Keeper) advanceMonth(ctx sdk.Context, subkey []byte) { sub.MonthCuTotal = plan.PlanPolicy.TotalCuLimit k.resetSubscriptionDetailsAndAppendEntry(ctx, &sub, block, false) - } else if sub.AutoRenewal { + } else if sub.IsAutoRenewalOn() { // apply the DurationLeft decrease to 0 and buy an extra month k.subsFS.ModifyEntry(ctx, sub.Consumer, sub.Block, &sub) - err := k.CreateSubscription(ctx, sub.Creator, sub.Consumer, sub.PlanIndex, 1, sub.AutoRenewal) + err := k.renewSubscription(ctx, &sub) if err != nil { utils.LavaFormatWarning("subscription auto renewal failed. removing subscription", err, utils.Attribute{Key: "consumer", Value: sub.Consumer}, @@ -399,7 +407,6 @@ func (k Keeper) resetSubscriptionDetailsAndAppendEntry(ctx sdk.Context, sub *typ ) } } - k.subsTS.AddTimerByBlockTime(ctx, expiry, tsKey, []byte{}) sub.MonthExpiryTime = expiry @@ -408,9 +415,6 @@ func (k Keeper) resetSubscriptionDetailsAndAppendEntry(ctx sdk.Context, sub *typ err := k.subsFS.AppendEntry(ctx, sub.Consumer, block, sub) if err != nil { - // Remove new timer if failed - k.subsTS.DelTimerByBlockTime(ctx, expiry, []byte(sub.Consumer)) - // normally would panic! but ok to ignore - the subscription remains // as is with same remaining duration (but not renewed CU) return utils.LavaFormatError("critical: failed to recharge subscription", err, @@ -420,6 +424,8 @@ func (k Keeper) resetSubscriptionDetailsAndAppendEntry(ctx sdk.Context, sub *typ ) } + k.subsTS.AddTimerByBlockTime(ctx, expiry, tsKey, []byte{}) + return nil } diff --git a/x/subscription/keeper/subscription_test.go b/x/subscription/keeper/subscription_test.go index 0eaadc96d6..7792a6d12b 100644 --- a/x/subscription/keeper/subscription_test.go +++ b/x/subscription/keeper/subscription_test.go @@ -33,8 +33,8 @@ func newTester(t *testing.T) *tester { premiumPlan.Price = freePlan.Price.AddAmount(math.NewInt(100)) premiumPlan.Block = ts.BlockHeight() premiumPlan.AnnualDiscountPercentage += 5 - premiumPlan.PlanPolicy.TotalCuLimit += 100 - premiumPlan.PlanPolicy.EpochCuLimit += 10 + premiumPlan.PlanPolicy.TotalCuLimit += 10000 + premiumPlan.PlanPolicy.EpochCuLimit += 1000 ts.AddPlan(premiumPlan.Index, premiumPlan) ts.DisableParticipationFees() @@ -257,12 +257,9 @@ func TestRenewSubscription(t *testing.T) { require.NoError(t, err) // try extending the subscription (we could extend with 1 more month, - // but since the subscription's plan changed and its new price is increased - // by more than 5% , the extension should fail) + // but since the subscription's plan changed, it should fail) _, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false, false) - require.NotNil(t, err) - require.Equal(t, uint64(12), sub.DurationLeft) - require.Equal(t, uint64(9), sub.DurationBought) + require.Error(t, err) // get the subscription's plan and make sure it uses the old plan plan, found = ts.FindPlan(sub.PlanIndex, sub.PlanBlock) @@ -772,83 +769,402 @@ func TestDurationTotal(t *testing.T) { // verifies that subs with auto-renewal enabled get renewed automatically func TestSubAutoRenewal(t *testing.T) { ts := newTester(t) - ts.SetupAccounts(3, 0, 0) // 2 sub, 0 adm, 0 dev + subA := "A" + subB := "B" + subC := "C" plan := ts.Plan("free") - _, subAddr1 := ts.Account("sub1") - _, subAddr2 := ts.Account("sub2") - _, subAddr3 := ts.Account("sub3") - // buy two subscriptions with enabled auto-renewal in two different ways - // and one with disabled auto-renewal. - // verify the auto-renewal flag is true in the first two subs - _, err := ts.TxSubscriptionBuy(subAddr1, subAddr1, plan.Index, 1, true, false) - require.NoError(t, err) - _, err = ts.TxSubscriptionBuy(subAddr2, subAddr2, plan.Index, 1, false, false) - require.NoError(t, err) - err = ts.TxSubscriptionAutoRenewal(subAddr2, true) - require.NoError(t, err) - _, err = ts.TxSubscriptionBuy(subAddr3, subAddr3, plan.Index, 1, false, false) - require.NoError(t, err) + testCases := []struct { + creator string + consumer string + immediatelyBuyAutoRenewal bool + buyAutoRenewal bool + autoRenewalCreator string + autoRenewalConsumer string + shouldFail bool + }{ + { + creator: subA, + consumer: subA, + immediatelyBuyAutoRenewal: true, + buyAutoRenewal: false, + autoRenewalCreator: subA, + autoRenewalConsumer: subA, + shouldFail: false, + }, + { + creator: subA, + consumer: subA, + immediatelyBuyAutoRenewal: false, + buyAutoRenewal: true, + autoRenewalCreator: subA, + autoRenewalConsumer: subA, + shouldFail: false, + }, + { + creator: subA, + consumer: subA, + immediatelyBuyAutoRenewal: false, + buyAutoRenewal: false, + autoRenewalCreator: subA, + autoRenewalConsumer: subA, + shouldFail: false, + }, + { + creator: subA, + consumer: subA, + immediatelyBuyAutoRenewal: true, + buyAutoRenewal: true, + autoRenewalCreator: subA, + autoRenewalConsumer: subA, + shouldFail: false, + }, + { + creator: subA, + consumer: subB, + immediatelyBuyAutoRenewal: true, + buyAutoRenewal: false, + autoRenewalCreator: subA, + autoRenewalConsumer: subB, + shouldFail: false, + }, + { + creator: subA, + consumer: subB, + immediatelyBuyAutoRenewal: false, + buyAutoRenewal: true, + autoRenewalCreator: subA, + autoRenewalConsumer: subB, + shouldFail: false, + }, + { + creator: subA, + consumer: subB, + immediatelyBuyAutoRenewal: true, + buyAutoRenewal: true, + autoRenewalCreator: subA, + autoRenewalConsumer: subB, + shouldFail: false, + }, + { + creator: subA, + consumer: subB, + immediatelyBuyAutoRenewal: false, + buyAutoRenewal: true, + autoRenewalCreator: subA, + autoRenewalConsumer: subA, + shouldFail: true, + }, + { + creator: subA, + consumer: subB, + immediatelyBuyAutoRenewal: false, + buyAutoRenewal: true, + autoRenewalCreator: subB, + autoRenewalConsumer: subB, + shouldFail: false, + }, + { + creator: subA, + consumer: subB, + immediatelyBuyAutoRenewal: false, + buyAutoRenewal: true, + autoRenewalCreator: subC, + autoRenewalConsumer: subB, + shouldFail: true, + }, + } - sub1, found := ts.getSubscription(subAddr1) - require.True(t, found) - require.True(t, sub1.AutoRenewal) - sub2, found := ts.getSubscription(subAddr2) - require.True(t, found) - require.True(t, sub2.AutoRenewal) - sub3, found := ts.getSubscription(subAddr3) - require.True(t, found) - require.False(t, sub3.AutoRenewal) + addAccounts := func(idx int) []string { + creatorAccountName := testCases[idx].creator + consumerAccountName := testCases[idx].consumer + autoRenewalCreatorAccountName := testCases[idx].autoRenewalCreator + autoRenewalConsumerAccountName := testCases[idx].autoRenewalConsumer + + accounts := map[string]struct{}{} + if _, ok := accounts[creatorAccountName]; !ok { + accounts[creatorAccountName] = struct{}{} + } + if _, ok := accounts[consumerAccountName]; !ok { + accounts[consumerAccountName] = struct{}{} + } + if _, ok := accounts[autoRenewalCreatorAccountName]; !ok { + accounts[autoRenewalCreatorAccountName] = struct{}{} + } + if _, ok := accounts[autoRenewalConsumerAccountName]; !ok { + accounts[autoRenewalConsumerAccountName] = struct{}{} + } + + for sub := range accounts { + ts.AddAccount(sub, idx, 1000000) + } + + return []string{creatorAccountName, consumerAccountName, autoRenewalCreatorAccountName, autoRenewalConsumerAccountName} + } + + allAccounts := map[int][]string{} + + for i := 0; i < len(testCases); i++ { + allAccounts[i] = addAccounts(i) + } + + for i := 0; i < len(testCases); i++ { + _, creatorAccountAddr := ts.GetAccount(allAccounts[i][0], i) + _, consumerAccountAddr := ts.GetAccount(allAccounts[i][1], i) + _, autoRenewalCreatorAccountAddr := ts.GetAccount(allAccounts[i][2], i) + _, autoRenewalConsumerAccountAddr := ts.GetAccount(allAccounts[i][3], i) + + testCase := testCases[i] + + _, err := ts.TxSubscriptionBuy(creatorAccountAddr, consumerAccountAddr, plan.Index, 1, testCase.immediatelyBuyAutoRenewal, false) + require.NoError(t, err) + + if testCase.buyAutoRenewal { + err = ts.TxSubscriptionAutoRenewal(autoRenewalCreatorAccountAddr, autoRenewalConsumerAccountAddr, plan.Index, true) + if !testCase.shouldFail { + require.NoError(t, err, testCase) + } else { + require.Error(t, err, testCase) + } + } + + sub, found := ts.getSubscription(consumerAccountAddr) + require.True(t, found) + if (testCase.immediatelyBuyAutoRenewal || testCase.buyAutoRenewal) && !testCase.shouldFail { + require.Equal(t, sub.AutoRenewalNextPlan, plan.Index, testCase) + require.Equal(t, sub.Creator, autoRenewalCreatorAccountAddr, testCase) + } else { + require.Equal(t, sub.AutoRenewalNextPlan, types.AUTO_RENEWAL_PLAN_NONE, testCase) + } + } // advance a couple of months to expire and automatically // extend all subscriptions. verify that sub1 and sub2 can // still be found and their duration left is always 1 - for i := 0; i < 5; i++ { + for month := 0; month < 5; month++ { ts.AdvanceMonths(1).AdvanceEpoch() - newSub1, found := ts.getSubscription(subAddr1) - require.True(t, found) - require.Equal(t, uint64(1), newSub1.DurationLeft) - newSub2, found := ts.getSubscription(subAddr2) - require.True(t, found) - require.Equal(t, uint64(1), newSub2.DurationLeft) - _, found = ts.getSubscription(subAddr3) - require.False(t, found) + for i := 0; i < len(testCases); i++ { + testCase := testCases[i] + + _, consumerAccountAddr := ts.GetAccount(allAccounts[i][1], i) + newSub, found := ts.getSubscription(consumerAccountAddr) + if (testCase.immediatelyBuyAutoRenewal || testCase.buyAutoRenewal) && !testCase.shouldFail { + require.True(t, found, testCase) + require.Equal(t, uint64(1), newSub.DurationLeft, testCase) + } else { + require.False(t, found, testCase) + } + } } } -// TestSubRenewalFailHighPlanPrice checks that auto-renewal fails when the -// original subscription's plan price increased by more than 5% -func TestSubRenewalFailHighPlanPrice(t *testing.T) { +func TestSubAutoRenewalDisable(t *testing.T) { ts := newTester(t) - ts.SetupAccounts(1, 0, 0) // 1 sub, 0 adm, 0 dev + ts.SetupAccounts(3, 0, 0) // 3 sub, 0 adm, 0 dev - _, subAddr1 := ts.Account("sub1") - plan := ts.Plan("free") + freePlan := ts.Plan("free") + _, consumer1 := ts.Account("sub1") + _, creator2 := ts.Account("sub2") + _, consumer2 := ts.Account("sub3") - _, err := ts.TxSubscriptionBuy(subAddr1, subAddr1, plan.Index, 1, true, false) + // Buy subscription with auto-renewal on + _, err := ts.TxSubscriptionBuy(consumer1, consumer1, freePlan.Index, 1, true, false) require.NoError(t, err) - _, found := ts.getSubscription(subAddr1) + // Check subscription has auto-renewal + sub, found := ts.getSubscription(consumer1) require.True(t, found) + require.Equal(t, freePlan.Index, sub.AutoRenewalNextPlan) - // edit the subscription's plan (increase the price by 6% and change the policy (shouldn't matter)) - plan.PlanPolicy.EpochCuLimit += 100 - plan.Price.Amount = plan.Price.Amount.MulRaw(106).QuoRaw(100) - - ts.AdvanceEpoch() // advance epoch so the new plan will be appended as a new entry - err = keepertest.SimulatePlansAddProposal(ts.Ctx, ts.Keepers.Plans, []planstypes.Plan{plan}, false) + // Disable auto-renewal + err = ts.TxSubscriptionAutoRenewal(consumer1, consumer1, freePlan.Index, false) require.NoError(t, err) + // Check subscription does not have auto-renewal + sub, found = ts.getSubscription(consumer1) + require.True(t, found) + require.Equal(t, types.AUTO_RENEWAL_PLAN_NONE, sub.AutoRenewalNextPlan) - // advance month to make the subscription expire ts.AdvanceMonths(1).AdvanceEpoch() - // the auto-renewal should've failed since the plan price is too high - // so the subscription should not be found - _, found = ts.getSubscription(subAddr1) + // Check subscription is expired + sub, found = ts.getSubscription(consumer1) + require.False(t, found) + + // Buy subscription with auto-renewal on + _, err = ts.TxSubscriptionBuy(creator2, consumer2, freePlan.Index, 1, true, false) + require.Nil(t, err) + // Check subscription has auto-renewal + sub, found = ts.getSubscription(consumer2) + require.True(t, found) + require.Equal(t, freePlan.Index, sub.AutoRenewalNextPlan) + + // Disable auto-renewal + err = ts.TxSubscriptionAutoRenewal(creator2, consumer2, freePlan.Index, false) + require.Nil(t, err) + // Check subscription does not have auto-renewal + sub, found = ts.getSubscription(consumer2) + require.True(t, found) + require.Equal(t, types.AUTO_RENEWAL_PLAN_NONE, sub.AutoRenewalNextPlan) + + ts.AdvanceMonths(1).AdvanceEpoch() + + // Check subscription is expired + sub, found = ts.getSubscription(consumer2) require.False(t, found) } +func TestSubAutoRenewalDifferentPlanIndexOnSubBuy(t *testing.T) { + ts := newTester(t) + + freePlan := ts.Plan("free") + premiumPlan := ts.Plan("premium") + creatorAcc, creatorAddr := ts.AddAccount("sub", 1, 20000) + creatorBalance := ts.GetBalance(creatorAcc.Addr) + _, consumerAddr := ts.AddAccount("sub", 2, 200000) + + // Buy subscription with auto-renewal on + _, err := ts.TxSubscriptionBuy(creatorAddr, consumerAddr, freePlan.Index, 1, true, false) + require.Nil(t, err) + // Check subscription has auto-renewal + sub, found := ts.getSubscription(consumerAddr) + require.True(t, found) + require.Equal(t, freePlan.Index, sub.AutoRenewalNextPlan) + // Check creator paid + creatorBalance -= freePlan.Price.Amount.Int64() + require.Equal(t, creatorBalance, ts.GetBalance(creatorAcc.Addr)) + + ts.AdvanceMonths(1).AdvanceEpoch() + + // Check new subscription + sub, found = ts.getSubscription(consumerAddr) + require.True(t, found) + require.Equal(t, freePlan.Index, sub.AutoRenewalNextPlan) + require.Equal(t, freePlan.Index, sub.PlanIndex) + + // Check creator paid for free plan + creatorBalance -= freePlan.Price.Amount.Int64() + require.Equal(t, creatorBalance, ts.GetBalance(creatorAcc.Addr)) + + // Set auto-renewal to premium + err = ts.TxSubscriptionAutoRenewal(creatorAddr, consumerAddr, premiumPlan.Index, true) + require.Nil(t, err) + // Check subscription has auto-renewal + sub, found = ts.getSubscription(consumerAddr) + require.True(t, found) + require.Equal(t, premiumPlan.Index, sub.AutoRenewalNextPlan) + require.Equal(t, creatorAddr, sub.Creator) + + ts.AdvanceMonths(1).AdvanceEpoch() + + // Check new subscription + sub, found = ts.getSubscription(consumerAddr) + require.True(t, found) + require.Equal(t, premiumPlan.Index, sub.AutoRenewalNextPlan) + require.Equal(t, premiumPlan.Index, sub.PlanIndex) + + // Check creator paid for new sub + creatorBalance -= premiumPlan.Price.Amount.Int64() + require.Equal(t, creatorBalance, ts.GetBalance(creatorAcc.Addr)) +} + +func TestSubAutoRenewalDifferentPlanIndexOnSubBuyDifferentCreator(t *testing.T) { + ts := newTester(t) + + freePlan := ts.Plan("free") + premiumPlan := ts.Plan("premium") + creatorAcc, creatorAddr := ts.AddAccount("sub", 1, 20000) + creatorBalance := ts.GetBalance(creatorAcc.Addr) + consumerAcc, consumerAddr := ts.AddAccount("sub", 2, 200000) + consumerBalance := ts.GetBalance(consumerAcc.Addr) + + // Buy subscription with auto-renewal on + _, err := ts.TxSubscriptionBuy(creatorAddr, consumerAddr, freePlan.Index, 1, true, false) + require.Nil(t, err) + // Check subscription has auto-renewal + sub, found := ts.getSubscription(consumerAddr) + require.True(t, found) + require.Equal(t, freePlan.Index, sub.AutoRenewalNextPlan) + // Check creator paid + creatorBalance -= freePlan.Price.Amount.Int64() + require.Equal(t, creatorBalance, ts.GetBalance(creatorAcc.Addr)) + + ts.AdvanceMonths(1).AdvanceEpoch() + + // Check new subscription + sub, found = ts.getSubscription(consumerAddr) + require.True(t, found) + require.Equal(t, freePlan.Index, sub.AutoRenewalNextPlan) + require.Equal(t, freePlan.Index, sub.PlanIndex) + + // Check creator paid for free plan + creatorBalance -= freePlan.Price.Amount.Int64() + require.Equal(t, creatorBalance, ts.GetBalance(creatorAcc.Addr)) + + // Set auto-renewal to premium + err = ts.TxSubscriptionAutoRenewal(consumerAddr, consumerAddr, premiumPlan.Index, true) + require.Nil(t, err) + // Check subscription has auto-renewal + sub, found = ts.getSubscription(consumerAddr) + require.True(t, found) + require.Equal(t, premiumPlan.Index, sub.AutoRenewalNextPlan) + require.Equal(t, consumerAddr, sub.Creator) + + ts.AdvanceMonths(1).AdvanceEpoch() + + // Check new subscription + sub, found = ts.getSubscription(consumerAddr) + require.True(t, found) + require.Equal(t, premiumPlan.Index, sub.AutoRenewalNextPlan) + require.Equal(t, premiumPlan.Index, sub.PlanIndex) + + // Check creator paid for new sub + consumerBalance -= premiumPlan.Price.Amount.Int64() + require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) +} + +func TestSubAutoRenewalDifferentPlanIndexOnAutoRenewTx(t *testing.T) { + ts := newTester(t) + + freePlan := ts.Plan("free") + premiumPlan := ts.Plan("premium") + creatorAcc, creatorAddr := ts.AddAccount("sub", 1, 20000) + creatorBalance := ts.GetBalance(creatorAcc.Addr) + _, consumerAddr := ts.AddAccount("sub", 2, 200000) + + // Buy subscription with auto-renewal off + _, err := ts.TxSubscriptionBuy(creatorAddr, consumerAddr, freePlan.Index, 1, false, false) + require.Nil(t, err) + // Check subscription does not have auto-renewal + sub, found := ts.getSubscription(consumerAddr) + require.True(t, found) + require.Equal(t, types.AUTO_RENEWAL_PLAN_NONE, sub.AutoRenewalNextPlan) + // Check creator paid + creatorBalance -= freePlan.Price.Amount.Int64() + require.Equal(t, creatorBalance, ts.GetBalance(creatorAcc.Addr)) + + // Enable auto-renewal for premium + err = ts.TxSubscriptionAutoRenewal(creatorAddr, consumerAddr, premiumPlan.Index, true) + require.Nil(t, err) + // Check subscription has auto-renewal + sub, found = ts.getSubscription(consumerAddr) + require.True(t, found) + require.Equal(t, premiumPlan.Index, sub.AutoRenewalNextPlan) + require.Equal(t, creatorAddr, sub.Creator) + + ts.AdvanceMonths(1).AdvanceEpoch() + + // Check new subscription + sub, found = ts.getSubscription(consumerAddr) + require.True(t, found) + require.Equal(t, premiumPlan.Index, sub.AutoRenewalNextPlan) + require.Equal(t, premiumPlan.Index, sub.PlanIndex) + + // Check creator paid for new sub + creatorBalance -= premiumPlan.Price.Amount.Int64() + require.Equal(t, creatorBalance, ts.GetBalance(creatorAcc.Addr)) +} + // TestNextToMonthExpiryQuery checks that the NextToMonthExpiry query works as intended // scenario - buy 3 subs: 2 at the same time, and one a little after. The query should return the two subs // then, expire those and expect to get the last one from the query @@ -906,6 +1222,37 @@ func TestNextToMonthExpiryQuery(t *testing.T) { require.Equal(t, 0, len(res.Subscriptions)) } +func TestSubBuySamePlanBlockUpdated(t *testing.T) { + ts := newTester(t) + ts.SetupAccounts(1, 0, 0) // 1 sub, 0 adm, 0 dev + + _, consumerAddr := ts.Account("sub1") + plan := ts.Plan("free") + + _, err := ts.TxSubscriptionBuy(consumerAddr, consumerAddr, plan.Index, 1, false, false) + require.Nil(t, err) + _, found := ts.getSubscription(consumerAddr) + require.True(t, found) + + // Advance block so the new plan will get a new block + ts.AdvanceBlock() + + // Edit the subscription's plan (increase the price) + plan.PlanPolicy.EpochCuLimit += 100 + plan.Price.Amount = plan.Price.Amount.AddRaw(10) + + // Propose new plan + err = keepertest.SimulatePlansAddProposal(ts.Ctx, ts.Keepers.Plans, []planstypes.Plan{plan}, false) + require.Nil(t, err) + + // Advance epoch so the new plan will be appended + ts.AdvanceEpoch() + + // Buy the plan again + _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, plan.Index, 1, false, false) + require.Error(t, err) +} + // TestPlanRemovedWhenSubscriptionExpires checks that if a subscription is expired // the plan's refcount is decreased. // in this test, we buy a subscription, update the plan and expire the subscription @@ -1066,6 +1413,8 @@ func TestSubscriptionCuExhaustAndUpgrade(t *testing.T) { premiumPlusPlan := common.CreateMockPlan() premiumPlusPlan.Index = "premium-plus" premiumPlusPlan.Price = premiumPlan.Price.AddAmount(math.NewInt(100)) + premiumPlusPlan.PlanPolicy.TotalCuLimit += 1000 + premiumPlusPlan.PlanPolicy.EpochCuLimit += 100 ts.AddPlan(premiumPlusPlan.Index, premiumPlusPlan) // Buy free plan @@ -1154,6 +1503,8 @@ func TestSubscriptionCuExhaustAndUpgrade(t *testing.T) { require.Equal(t, expectedPrice, reward.Amount) } +// ### Advance Purchase Tests ### + func TestSubscriptionAdvancePurchaseStartsOnExpirationOfCurrent(t *testing.T) { ts := newTester(t) ts.SetupAccounts(1, 0, 0) // 1 sub, 0 adm, 0 dev diff --git a/x/subscription/migrations/v6/subscription.pb.go b/x/subscription/migrations/v6/subscription.pb.go new file mode 100644 index 0000000000..521214471f --- /dev/null +++ b/x/subscription/migrations/v6/subscription.pb.go @@ -0,0 +1,1162 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: lavanet/lava/subscription/subscription.proto + +package v6 + +import ( + fmt "fmt" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type Subscription struct { + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + Consumer string `protobuf:"bytes,2,opt,name=consumer,proto3" json:"consumer,omitempty"` + Block uint64 `protobuf:"varint,3,opt,name=block,proto3" json:"block,omitempty"` + PlanIndex string `protobuf:"bytes,4,opt,name=plan_index,json=planIndex,proto3" json:"plan_index,omitempty"` + PlanBlock uint64 `protobuf:"varint,5,opt,name=plan_block,json=planBlock,proto3" json:"plan_block,omitempty"` + DurationBought uint64 `protobuf:"varint,6,opt,name=duration_bought,json=durationBought,proto3" json:"duration_bought,omitempty"` + DurationLeft uint64 `protobuf:"varint,7,opt,name=duration_left,json=durationLeft,proto3" json:"duration_left,omitempty"` + MonthExpiryTime uint64 `protobuf:"varint,8,opt,name=month_expiry_time,json=monthExpiryTime,proto3" json:"month_expiry_time,omitempty"` + MonthCuTotal uint64 `protobuf:"varint,10,opt,name=month_cu_total,json=monthCuTotal,proto3" json:"month_cu_total,omitempty"` + MonthCuLeft uint64 `protobuf:"varint,11,opt,name=month_cu_left,json=monthCuLeft,proto3" json:"month_cu_left,omitempty"` + Cluster string `protobuf:"bytes,13,opt,name=cluster,proto3" json:"cluster,omitempty"` + DurationTotal uint64 `protobuf:"varint,14,opt,name=duration_total,json=durationTotal,proto3" json:"duration_total,omitempty"` + AutoRenewal bool `protobuf:"varint,15,opt,name=auto_renewal,json=autoRenewal,proto3" json:"auto_renewal,omitempty"` + FutureSubscription *FutureSubscription `protobuf:"bytes,16,opt,name=future_subscription,json=futureSubscription,proto3" json:"future_subscription,omitempty"` +} + +func (m *Subscription) Reset() { *m = Subscription{} } +func (m *Subscription) String() string { return proto.CompactTextString(m) } +func (*Subscription) ProtoMessage() {} +func (*Subscription) Descriptor() ([]byte, []int) { + return fileDescriptor_c3bc5507ca237d79, []int{0} +} +func (m *Subscription) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Subscription) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Subscription.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Subscription) XXX_Merge(src proto.Message) { + xxx_messageInfo_Subscription.Merge(m, src) +} +func (m *Subscription) XXX_Size() int { + return m.Size() +} +func (m *Subscription) XXX_DiscardUnknown() { + xxx_messageInfo_Subscription.DiscardUnknown(m) +} + +var xxx_messageInfo_Subscription proto.InternalMessageInfo + +func (m *Subscription) GetCreator() string { + if m != nil { + return m.Creator + } + return "" +} + +func (m *Subscription) GetConsumer() string { + if m != nil { + return m.Consumer + } + return "" +} + +func (m *Subscription) GetBlock() uint64 { + if m != nil { + return m.Block + } + return 0 +} + +func (m *Subscription) GetPlanIndex() string { + if m != nil { + return m.PlanIndex + } + return "" +} + +func (m *Subscription) GetPlanBlock() uint64 { + if m != nil { + return m.PlanBlock + } + return 0 +} + +func (m *Subscription) GetDurationBought() uint64 { + if m != nil { + return m.DurationBought + } + return 0 +} + +func (m *Subscription) GetDurationLeft() uint64 { + if m != nil { + return m.DurationLeft + } + return 0 +} + +func (m *Subscription) GetMonthExpiryTime() uint64 { + if m != nil { + return m.MonthExpiryTime + } + return 0 +} + +func (m *Subscription) GetMonthCuTotal() uint64 { + if m != nil { + return m.MonthCuTotal + } + return 0 +} + +func (m *Subscription) GetMonthCuLeft() uint64 { + if m != nil { + return m.MonthCuLeft + } + return 0 +} + +func (m *Subscription) GetCluster() string { + if m != nil { + return m.Cluster + } + return "" +} + +func (m *Subscription) GetDurationTotal() uint64 { + if m != nil { + return m.DurationTotal + } + return 0 +} + +func (m *Subscription) GetAutoRenewal() bool { + if m != nil { + return m.AutoRenewal + } + return false +} + +func (m *Subscription) GetFutureSubscription() *FutureSubscription { + if m != nil { + return m.FutureSubscription + } + return nil +} + +type FutureSubscription struct { + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + PlanIndex string `protobuf:"bytes,2,opt,name=plan_index,json=planIndex,proto3" json:"plan_index,omitempty"` + PlanBlock uint64 `protobuf:"varint,3,opt,name=plan_block,json=planBlock,proto3" json:"plan_block,omitempty"` + DurationBought uint64 `protobuf:"varint,4,opt,name=duration_bought,json=durationBought,proto3" json:"duration_bought,omitempty"` +} + +func (m *FutureSubscription) Reset() { *m = FutureSubscription{} } +func (m *FutureSubscription) String() string { return proto.CompactTextString(m) } +func (*FutureSubscription) ProtoMessage() {} +func (*FutureSubscription) Descriptor() ([]byte, []int) { + return fileDescriptor_c3bc5507ca237d79, []int{1} +} +func (m *FutureSubscription) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *FutureSubscription) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_FutureSubscription.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *FutureSubscription) XXX_Merge(src proto.Message) { + xxx_messageInfo_FutureSubscription.Merge(m, src) +} +func (m *FutureSubscription) XXX_Size() int { + return m.Size() +} +func (m *FutureSubscription) XXX_DiscardUnknown() { + xxx_messageInfo_FutureSubscription.DiscardUnknown(m) +} + +var xxx_messageInfo_FutureSubscription proto.InternalMessageInfo + +func (m *FutureSubscription) GetCreator() string { + if m != nil { + return m.Creator + } + return "" +} + +func (m *FutureSubscription) GetPlanIndex() string { + if m != nil { + return m.PlanIndex + } + return "" +} + +func (m *FutureSubscription) GetPlanBlock() uint64 { + if m != nil { + return m.PlanBlock + } + return 0 +} + +func (m *FutureSubscription) GetDurationBought() uint64 { + if m != nil { + return m.DurationBought + } + return 0 +} + +func init() { + proto.RegisterType((*Subscription)(nil), "lavanet.lava.subscription.SubscriptionV6") + proto.RegisterType((*FutureSubscription)(nil), "lavanet.lava.subscription.FutureSubscriptionV6") +} + +func init() { + proto.RegisterFile("lavanet/lava/subscription/subscription.proto", fileDescriptor_c3bc5507ca237d79) +} + +var fileDescriptor_c3bc5507ca237d79 = []byte{ + // 452 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x93, 0xcf, 0x6e, 0xd3, 0x40, + 0x10, 0xc6, 0xb3, 0xad, 0xdb, 0x3a, 0x93, 0xbf, 0x2c, 0x1c, 0x16, 0x24, 0xac, 0x10, 0x40, 0x44, + 0xa8, 0x38, 0x12, 0xbc, 0x41, 0x10, 0x95, 0xa8, 0x38, 0x99, 0x9e, 0x38, 0x60, 0xd9, 0xee, 0xa6, + 0xb1, 0xb0, 0xbd, 0xd6, 0x7a, 0x16, 0xd2, 0xb7, 0xe0, 0xc2, 0x5b, 0xf0, 0x20, 0x1c, 0x7b, 0xe4, + 0x88, 0x92, 0x17, 0x41, 0x1e, 0x27, 0x56, 0xac, 0x42, 0xd4, 0xd3, 0x6a, 0x7e, 0xf3, 0x7d, 0x1e, + 0xef, 0xce, 0x0c, 0x9c, 0x26, 0xc1, 0xd7, 0x20, 0x93, 0x38, 0x2d, 0xcf, 0x69, 0x61, 0xc2, 0x22, + 0xd2, 0x71, 0x8e, 0xb1, 0xca, 0x1a, 0x81, 0x9b, 0x6b, 0x85, 0x8a, 0x3f, 0xdc, 0xa8, 0xdd, 0xf2, + 0x74, 0x77, 0x05, 0xe3, 0x9f, 0x16, 0x74, 0x3f, 0xee, 0x00, 0x2e, 0xe0, 0x24, 0xd2, 0x32, 0x40, + 0xa5, 0x05, 0x1b, 0xb1, 0x49, 0xdb, 0xdb, 0x86, 0xfc, 0x11, 0xd8, 0x91, 0xca, 0x0a, 0x93, 0x4a, + 0x2d, 0x0e, 0x28, 0x55, 0xc7, 0xfc, 0x01, 0x1c, 0x85, 0x89, 0x8a, 0xbe, 0x88, 0xc3, 0x11, 0x9b, + 0x58, 0x5e, 0x15, 0xf0, 0xc7, 0x00, 0x79, 0x12, 0x64, 0x7e, 0x9c, 0x5d, 0xca, 0xa5, 0xb0, 0xc8, + 0xd3, 0x2e, 0xc9, 0xfb, 0x12, 0xd4, 0xe9, 0xca, 0x79, 0x44, 0x4e, 0x4a, 0xcf, 0xc8, 0xfd, 0x02, + 0x06, 0x97, 0x46, 0x07, 0xe5, 0x5f, 0xf9, 0xa1, 0x32, 0x57, 0x0b, 0x14, 0xc7, 0xa4, 0xe9, 0x6f, + 0xf1, 0x8c, 0x28, 0x7f, 0x0a, 0xbd, 0x5a, 0x98, 0xc8, 0x39, 0x8a, 0x13, 0x92, 0x75, 0xb7, 0xf0, + 0x83, 0x9c, 0x23, 0x7f, 0x09, 0xf7, 0x52, 0x95, 0xe1, 0xc2, 0x97, 0xcb, 0x3c, 0xd6, 0xd7, 0x3e, + 0xc6, 0xa9, 0x14, 0x36, 0x09, 0x07, 0x94, 0x78, 0x47, 0xfc, 0x22, 0x4e, 0x25, 0x7f, 0x06, 0xfd, + 0x4a, 0x1b, 0x19, 0x1f, 0x15, 0x06, 0x89, 0x80, 0xea, 0x8b, 0x44, 0xdf, 0x9a, 0x8b, 0x92, 0xf1, + 0x31, 0xf4, 0x6a, 0x15, 0x95, 0xed, 0x90, 0xa8, 0xb3, 0x11, 0x51, 0xd5, 0xf2, 0x35, 0x13, 0x53, + 0xa0, 0xd4, 0xa2, 0xb7, 0x79, 0xcd, 0x2a, 0xe4, 0xcf, 0xa1, 0xbe, 0xc6, 0xa6, 0x46, 0x9f, 0xec, + 0xf5, 0x55, 0xaa, 0x22, 0x4f, 0xa0, 0x1b, 0x18, 0x54, 0xbe, 0x96, 0x99, 0xfc, 0x16, 0x24, 0x62, + 0x30, 0x62, 0x13, 0xdb, 0xeb, 0x94, 0xcc, 0xab, 0x10, 0xff, 0x0c, 0xf7, 0xe7, 0x06, 0x8d, 0x96, + 0xfe, 0x6e, 0x67, 0xc5, 0x70, 0xc4, 0x26, 0x9d, 0xd7, 0xaf, 0xdc, 0xff, 0xf6, 0xde, 0x3d, 0x23, + 0xd7, 0x6e, 0xf7, 0x3d, 0x3e, 0xbf, 0xc5, 0xce, 0x2d, 0xbb, 0x3d, 0x84, 0x73, 0xcb, 0xee, 0x0e, + 0x7b, 0xe3, 0x1f, 0x0c, 0xf8, 0x6d, 0xdb, 0x9e, 0xa1, 0x69, 0x8e, 0xc0, 0xc1, 0xfe, 0x11, 0x38, + 0xbc, 0xc3, 0x08, 0x58, 0xff, 0x1a, 0x81, 0xd9, 0xd9, 0xaf, 0x95, 0xc3, 0x6e, 0x56, 0x0e, 0xfb, + 0xb3, 0x72, 0xd8, 0xf7, 0xb5, 0xd3, 0xba, 0x59, 0x3b, 0xad, 0xdf, 0x6b, 0xa7, 0xf5, 0xe9, 0xf4, + 0x2a, 0xc6, 0x85, 0x09, 0xdd, 0x48, 0xa5, 0xd3, 0xc6, 0xd2, 0x2c, 0x9b, 0x6b, 0x83, 0xd7, 0xb9, + 0x2c, 0xc2, 0x63, 0x5a, 0x98, 0x37, 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xb1, 0xdc, 0x42, 0x8e, + 0x60, 0x03, 0x00, 0x00, +} + +func (m *Subscription) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Subscription) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Subscription) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.FutureSubscription != nil { + { + size, err := m.FutureSubscription.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSubscription(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x82 + } + if m.AutoRenewal { + i-- + if m.AutoRenewal { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x78 + } + if m.DurationTotal != 0 { + i = encodeVarintSubscription(dAtA, i, uint64(m.DurationTotal)) + i-- + dAtA[i] = 0x70 + } + if len(m.Cluster) > 0 { + i -= len(m.Cluster) + copy(dAtA[i:], m.Cluster) + i = encodeVarintSubscription(dAtA, i, uint64(len(m.Cluster))) + i-- + dAtA[i] = 0x6a + } + if m.MonthCuLeft != 0 { + i = encodeVarintSubscription(dAtA, i, uint64(m.MonthCuLeft)) + i-- + dAtA[i] = 0x58 + } + if m.MonthCuTotal != 0 { + i = encodeVarintSubscription(dAtA, i, uint64(m.MonthCuTotal)) + i-- + dAtA[i] = 0x50 + } + if m.MonthExpiryTime != 0 { + i = encodeVarintSubscription(dAtA, i, uint64(m.MonthExpiryTime)) + i-- + dAtA[i] = 0x40 + } + if m.DurationLeft != 0 { + i = encodeVarintSubscription(dAtA, i, uint64(m.DurationLeft)) + i-- + dAtA[i] = 0x38 + } + if m.DurationBought != 0 { + i = encodeVarintSubscription(dAtA, i, uint64(m.DurationBought)) + i-- + dAtA[i] = 0x30 + } + if m.PlanBlock != 0 { + i = encodeVarintSubscription(dAtA, i, uint64(m.PlanBlock)) + i-- + dAtA[i] = 0x28 + } + if len(m.PlanIndex) > 0 { + i -= len(m.PlanIndex) + copy(dAtA[i:], m.PlanIndex) + i = encodeVarintSubscription(dAtA, i, uint64(len(m.PlanIndex))) + i-- + dAtA[i] = 0x22 + } + if m.Block != 0 { + i = encodeVarintSubscription(dAtA, i, uint64(m.Block)) + i-- + dAtA[i] = 0x18 + } + if len(m.Consumer) > 0 { + i -= len(m.Consumer) + copy(dAtA[i:], m.Consumer) + i = encodeVarintSubscription(dAtA, i, uint64(len(m.Consumer))) + i-- + dAtA[i] = 0x12 + } + if len(m.Creator) > 0 { + i -= len(m.Creator) + copy(dAtA[i:], m.Creator) + i = encodeVarintSubscription(dAtA, i, uint64(len(m.Creator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *FutureSubscription) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *FutureSubscription) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *FutureSubscription) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.DurationBought != 0 { + i = encodeVarintSubscription(dAtA, i, uint64(m.DurationBought)) + i-- + dAtA[i] = 0x20 + } + if m.PlanBlock != 0 { + i = encodeVarintSubscription(dAtA, i, uint64(m.PlanBlock)) + i-- + dAtA[i] = 0x18 + } + if len(m.PlanIndex) > 0 { + i -= len(m.PlanIndex) + copy(dAtA[i:], m.PlanIndex) + i = encodeVarintSubscription(dAtA, i, uint64(len(m.PlanIndex))) + i-- + dAtA[i] = 0x12 + } + if len(m.Creator) > 0 { + i -= len(m.Creator) + copy(dAtA[i:], m.Creator) + i = encodeVarintSubscription(dAtA, i, uint64(len(m.Creator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintSubscription(dAtA []byte, offset int, v uint64) int { + offset -= sovSubscription(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Subscription) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovSubscription(uint64(l)) + } + l = len(m.Consumer) + if l > 0 { + n += 1 + l + sovSubscription(uint64(l)) + } + if m.Block != 0 { + n += 1 + sovSubscription(uint64(m.Block)) + } + l = len(m.PlanIndex) + if l > 0 { + n += 1 + l + sovSubscription(uint64(l)) + } + if m.PlanBlock != 0 { + n += 1 + sovSubscription(uint64(m.PlanBlock)) + } + if m.DurationBought != 0 { + n += 1 + sovSubscription(uint64(m.DurationBought)) + } + if m.DurationLeft != 0 { + n += 1 + sovSubscription(uint64(m.DurationLeft)) + } + if m.MonthExpiryTime != 0 { + n += 1 + sovSubscription(uint64(m.MonthExpiryTime)) + } + if m.MonthCuTotal != 0 { + n += 1 + sovSubscription(uint64(m.MonthCuTotal)) + } + if m.MonthCuLeft != 0 { + n += 1 + sovSubscription(uint64(m.MonthCuLeft)) + } + l = len(m.Cluster) + if l > 0 { + n += 1 + l + sovSubscription(uint64(l)) + } + if m.DurationTotal != 0 { + n += 1 + sovSubscription(uint64(m.DurationTotal)) + } + if m.AutoRenewal { + n += 2 + } + if m.FutureSubscription != nil { + l = m.FutureSubscription.Size() + n += 2 + l + sovSubscription(uint64(l)) + } + return n +} + +func (m *FutureSubscription) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovSubscription(uint64(l)) + } + l = len(m.PlanIndex) + if l > 0 { + n += 1 + l + sovSubscription(uint64(l)) + } + if m.PlanBlock != 0 { + n += 1 + sovSubscription(uint64(m.PlanBlock)) + } + if m.DurationBought != 0 { + n += 1 + sovSubscription(uint64(m.DurationBought)) + } + return n +} + +func sovSubscription(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozSubscription(x uint64) (n int) { + return sovSubscription(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Subscription) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSubscription + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Subscription: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Subscription: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSubscription + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSubscription + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSubscription + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Consumer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSubscription + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSubscription + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSubscription + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Consumer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Block", wireType) + } + m.Block = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSubscription + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Block |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PlanIndex", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSubscription + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSubscription + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSubscription + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PlanIndex = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PlanBlock", wireType) + } + m.PlanBlock = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSubscription + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PlanBlock |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DurationBought", wireType) + } + m.DurationBought = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSubscription + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DurationBought |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DurationLeft", wireType) + } + m.DurationLeft = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSubscription + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DurationLeft |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MonthExpiryTime", wireType) + } + m.MonthExpiryTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSubscription + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MonthExpiryTime |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 10: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MonthCuTotal", wireType) + } + m.MonthCuTotal = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSubscription + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MonthCuTotal |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 11: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MonthCuLeft", wireType) + } + m.MonthCuLeft = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSubscription + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MonthCuLeft |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 13: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Cluster", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSubscription + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSubscription + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSubscription + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Cluster = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 14: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DurationTotal", wireType) + } + m.DurationTotal = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSubscription + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DurationTotal |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 15: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field AutoRenewal", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSubscription + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.AutoRenewal = bool(v != 0) + case 16: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FutureSubscription", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSubscription + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSubscription + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSubscription + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.FutureSubscription == nil { + m.FutureSubscription = &FutureSubscription{} + } + if err := m.FutureSubscription.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipSubscription(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSubscription + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *FutureSubscription) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSubscription + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: FutureSubscription: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: FutureSubscription: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSubscription + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSubscription + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSubscription + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PlanIndex", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSubscription + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSubscription + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSubscription + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PlanIndex = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PlanBlock", wireType) + } + m.PlanBlock = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSubscription + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PlanBlock |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DurationBought", wireType) + } + m.DurationBought = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSubscription + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DurationBought |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipSubscription(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSubscription + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipSubscription(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowSubscription + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowSubscription + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowSubscription + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthSubscription + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupSubscription + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthSubscription + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthSubscription = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowSubscription = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupSubscription = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/subscription/module.go b/x/subscription/module.go index 9ab6de76fc..ffeee2dbd8 100644 --- a/x/subscription/module.go +++ b/x/subscription/module.go @@ -154,6 +154,12 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { // panic:ok: at start up, migration cannot proceed anyhow panic(fmt.Errorf("%s: failed to register migration to v6: %w", types.ModuleName, err)) } + + // register v6 -> v7 migration + if err := cfg.RegisterMigration(types.ModuleName, 6, migrator.Migrate6to7); err != nil { + // panic:ok: at start up, migration cannot proceed anyhow + panic(fmt.Errorf("%s: failed to register migration to v6: %w", types.ModuleName, err)) + } } // RegisterInvariants registers the capability module's invariants. @@ -178,7 +184,7 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.Raw } // ConsensusVersion implements ConsensusVersion. -func (AppModule) ConsensusVersion() uint64 { return 6 } +func (AppModule) ConsensusVersion() uint64 { return 7 } // BeginBlock executes all ABCI BeginBlock logic respective to the capability module. func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} diff --git a/x/subscription/types/message_auto_renewal.go b/x/subscription/types/message_auto_renewal.go index cc9c8cebb6..5d92cda6c0 100644 --- a/x/subscription/types/message_auto_renewal.go +++ b/x/subscription/types/message_auto_renewal.go @@ -1,6 +1,8 @@ package types import ( + "strings" + sdkerrors "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" legacyerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -10,10 +12,12 @@ const TypeMsgAutoRenewal = "add_project" var _ sdk.Msg = &MsgAutoRenewal{} -func NewMsgAutoRenewal(creator string, enable bool) *MsgAutoRenewal { +func NewMsgAutoRenewal(creator, consumer, planIndex string, enable bool) *MsgAutoRenewal { return &MsgAutoRenewal{ - Creator: creator, - Enable: enable, + Consumer: consumer, + Creator: creator, + Enable: enable, + Index: planIndex, } } @@ -44,5 +48,14 @@ func (msg *MsgAutoRenewal) ValidateBasic() error { return sdkerrors.Wrapf(legacyerrors.ErrInvalidAddress, "invalid creator address (%s)", err) } + _, err = sdk.AccAddressFromBech32(msg.Consumer) + if err != nil { + return sdkerrors.Wrapf(legacyerrors.ErrInvalidAddress, "invalid consumer address (%s)", err) + } + + if !msg.Enable && strings.TrimSpace(msg.Index) != "" { + return sdkerrors.Wrapf(ErrInvalidParameter, "can't use plan index when `--disable` flag is passed") + } + return nil } diff --git a/x/subscription/types/message_auto_renewal_test.go b/x/subscription/types/message_auto_renewal_test.go index 91f497422d..abc691c820 100644 --- a/x/subscription/types/message_auto_renewal_test.go +++ b/x/subscription/types/message_auto_renewal_test.go @@ -15,18 +15,49 @@ func TestMsgAutoRenewal_ValidateBasic(t *testing.T) { err error }{ { - name: "invalid address", + name: "creator invalid address", msg: MsgAutoRenewal{ - Creator: "invalid_address", - Enable: false, + Creator: "invalid_address", + Consumer: sample.AccAddress(), + Enable: false, }, err: legacyerrors.ErrInvalidAddress, - }, { + }, + { + name: "consumer invalid address", + msg: MsgAutoRenewal{ + Creator: sample.AccAddress(), + Consumer: "invalid_address", + Enable: false, + }, + err: legacyerrors.ErrInvalidAddress, + }, + { name: "valid address", msg: MsgAutoRenewal{ - Creator: sample.AccAddress(), - Enable: false, + Creator: sample.AccAddress(), + Consumer: sample.AccAddress(), + Enable: false, + }, + }, + { + name: "valid plan", + msg: MsgAutoRenewal{ + Creator: sample.AccAddress(), + Consumer: sample.AccAddress(), + Enable: true, + Index: "free", + }, + }, + { + name: "plan not empty on disable", + msg: MsgAutoRenewal{ + Creator: sample.AccAddress(), + Consumer: sample.AccAddress(), + Enable: false, + Index: "free", }, + err: ErrInvalidParameter, }, } for _, tt := range tests { diff --git a/x/subscription/types/query.pb.go b/x/subscription/types/query.pb.go index 9ca70cb14f..2af8ebcf1b 100644 --- a/x/subscription/types/query.pb.go +++ b/x/subscription/types/query.pb.go @@ -370,16 +370,17 @@ func (m *QueryListResponse) GetSubsInfo() []ListInfoStruct { } type ListInfoStruct struct { - Consumer string `protobuf:"bytes,1,opt,name=consumer,proto3" json:"consumer,omitempty"` - Plan string `protobuf:"bytes,2,opt,name=plan,proto3" json:"plan,omitempty"` - DurationBought uint64 `protobuf:"varint,3,opt,name=duration_bought,json=durationBought,proto3" json:"duration_bought,omitempty"` - DurationLeft uint64 `protobuf:"varint,4,opt,name=duration_left,json=durationLeft,proto3" json:"duration_left,omitempty"` - MonthExpiry uint64 `protobuf:"varint,5,opt,name=month_expiry,json=monthExpiry,proto3" json:"month_expiry,omitempty"` - MonthCuTotal uint64 `protobuf:"varint,6,opt,name=month_cu_total,json=monthCuTotal,proto3" json:"month_cu_total,omitempty"` - MonthCuLeft uint64 `protobuf:"varint,7,opt,name=month_cu_left,json=monthCuLeft,proto3" json:"month_cu_left,omitempty"` - Cluster string `protobuf:"bytes,8,opt,name=cluster,proto3" json:"cluster,omitempty"` - DurationTotal uint64 `protobuf:"varint,9,opt,name=duration_total,json=durationTotal,proto3" json:"duration_total,omitempty"` - AutoRenewal bool `protobuf:"varint,10,opt,name=auto_renewal,json=autoRenewal,proto3" json:"auto_renewal,omitempty"` + Consumer string `protobuf:"bytes,1,opt,name=consumer,proto3" json:"consumer,omitempty"` + Plan string `protobuf:"bytes,2,opt,name=plan,proto3" json:"plan,omitempty"` + DurationBought uint64 `protobuf:"varint,3,opt,name=duration_bought,json=durationBought,proto3" json:"duration_bought,omitempty"` + DurationLeft uint64 `protobuf:"varint,4,opt,name=duration_left,json=durationLeft,proto3" json:"duration_left,omitempty"` + MonthExpiry uint64 `protobuf:"varint,5,opt,name=month_expiry,json=monthExpiry,proto3" json:"month_expiry,omitempty"` + MonthCuTotal uint64 `protobuf:"varint,6,opt,name=month_cu_total,json=monthCuTotal,proto3" json:"month_cu_total,omitempty"` + MonthCuLeft uint64 `protobuf:"varint,7,opt,name=month_cu_left,json=monthCuLeft,proto3" json:"month_cu_left,omitempty"` + Cluster string `protobuf:"bytes,8,opt,name=cluster,proto3" json:"cluster,omitempty"` + DurationTotal uint64 `protobuf:"varint,9,opt,name=duration_total,json=durationTotal,proto3" json:"duration_total,omitempty"` + AutoRenewalNextPlan string `protobuf:"bytes,11,opt,name=auto_renewal_next_plan,json=autoRenewalNextPlan,proto3" json:"auto_renewal_next_plan,omitempty"` + FutureSubscription *FutureSubscription `protobuf:"bytes,12,opt,name=future_subscription,json=futureSubscription,proto3" json:"future_subscription,omitempty"` } func (m *ListInfoStruct) Reset() { *m = ListInfoStruct{} } @@ -478,11 +479,18 @@ func (m *ListInfoStruct) GetDurationTotal() uint64 { return 0 } -func (m *ListInfoStruct) GetAutoRenewal() bool { +func (m *ListInfoStruct) GetAutoRenewalNextPlan() string { if m != nil { - return m.AutoRenewal + return m.AutoRenewalNextPlan } - return false + return "" +} + +func (m *ListInfoStruct) GetFutureSubscription() *FutureSubscription { + if m != nil { + return m.FutureSubscription + } + return nil } type QueryNextToMonthExpiryRequest struct { @@ -637,60 +645,62 @@ func init() { } var fileDescriptor_e870698c9d8ccc09 = []byte{ - // 834 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0xcf, 0x4f, 0xdb, 0x48, - 0x18, 0x8d, 0x43, 0x08, 0xe1, 0x4b, 0x80, 0x65, 0x96, 0x83, 0xb1, 0x76, 0x43, 0x62, 0x96, 0xe5, - 0xc7, 0x42, 0xac, 0xc0, 0xae, 0x58, 0x2e, 0x8b, 0x04, 0xda, 0x95, 0x56, 0x62, 0x57, 0x6c, 0x40, - 0xac, 0xd4, 0x8b, 0xe5, 0xb8, 0x93, 0xe0, 0xca, 0xf1, 0x18, 0xcf, 0x98, 0x06, 0x21, 0x2e, 0x3d, - 0xf6, 0x54, 0xb5, 0x7f, 0x41, 0xff, 0x8d, 0xde, 0x7a, 0xe3, 0x54, 0x21, 0xf5, 0xd2, 0x53, 0x5b, - 0x41, 0xff, 0x90, 0xca, 0xe3, 0x71, 0x6a, 0x03, 0x71, 0xd2, 0x9e, 0x92, 0x79, 0x79, 0xdf, 0x7b, - 0xef, 0x9b, 0x1f, 0x5f, 0x60, 0xc1, 0x36, 0x4e, 0x0d, 0x07, 0x33, 0x2d, 0xf8, 0xd4, 0xa8, 0xdf, - 0xa4, 0xa6, 0x67, 0xb9, 0xcc, 0x22, 0x8e, 0x76, 0xe2, 0x63, 0xef, 0xac, 0xe6, 0x7a, 0x84, 0x11, - 0x34, 0x2b, 0x68, 0xb5, 0xe0, 0xb3, 0x16, 0xa7, 0x29, 0x33, 0x6d, 0xd2, 0x26, 0x9c, 0xa5, 0x05, - 0xdf, 0xc2, 0x02, 0xe5, 0x87, 0x36, 0x21, 0x6d, 0x1b, 0x6b, 0x86, 0x6b, 0x69, 0x86, 0xe3, 0x10, - 0x66, 0x04, 0x64, 0x2a, 0x7e, 0x5d, 0x31, 0x09, 0xed, 0x10, 0xaa, 0x35, 0x0d, 0x8a, 0x43, 0x1f, - 0xed, 0xb4, 0xde, 0xc4, 0xcc, 0xa8, 0x6b, 0xae, 0xd1, 0xb6, 0x1c, 0x4e, 0x16, 0xdc, 0x9f, 0xfb, - 0x27, 0x74, 0x0d, 0xcf, 0xe8, 0x44, 0x9a, 0xab, 0xfd, 0x79, 0xf1, 0x45, 0xc8, 0x56, 0x67, 0x00, - 0xfd, 0x17, 0xf8, 0xee, 0x73, 0x89, 0x06, 0x3e, 0xf1, 0x31, 0x65, 0xea, 0x11, 0x7c, 0x9f, 0x40, - 0xa9, 0x4b, 0x1c, 0x8a, 0xd1, 0x36, 0xe4, 0x43, 0x2b, 0x59, 0xaa, 0x48, 0x4b, 0xc5, 0xf5, 0x6a, - 0xad, 0xef, 0x76, 0xd4, 0xc2, 0xd2, 0x9d, 0xdc, 0xe5, 0xfb, 0xb9, 0x4c, 0x43, 0x94, 0xa9, 0x75, - 0xa1, 0xbb, 0xeb, 0x7b, 0x1e, 0x76, 0x98, 0xb0, 0x43, 0x0a, 0x14, 0x4c, 0xe2, 0x50, 0xbf, 0x83, - 0x3d, 0xae, 0x3c, 0xde, 0xe8, 0xad, 0xd5, 0xff, 0x61, 0x26, 0x59, 0xd2, 0xcb, 0x32, 0x42, 0xfd, - 0xa6, 0x08, 0xb2, 0x98, 0x12, 0xe4, 0x20, 0xb6, 0xe0, 0x71, 0xa4, 0x46, 0x50, 0xa9, 0xfe, 0x01, - 0x32, 0x17, 0xde, 0xb3, 0x28, 0xdb, 0xf7, 0xc8, 0x23, 0x6c, 0xb2, 0xa8, 0x7f, 0xa4, 0x42, 0x29, - 0xae, 0x21, 0x42, 0x25, 0x30, 0x75, 0x13, 0x66, 0xef, 0xa9, 0x17, 0xe9, 0x14, 0x28, 0xb8, 0x02, - 0x93, 0xa5, 0xca, 0x48, 0xd0, 0x51, 0xb4, 0x56, 0x11, 0x7c, 0xd7, 0x2b, 0x8c, 0x36, 0xdc, 0x80, - 0xe9, 0x18, 0x26, 0x44, 0xf6, 0x60, 0x3c, 0x70, 0xd4, 0x2d, 0xa7, 0x45, 0xb8, 0x4a, 0x71, 0x7d, - 0x39, 0xa5, 0xd1, 0xa0, 0xf6, 0x6f, 0xa7, 0x45, 0x0e, 0x98, 0xe7, 0x9b, 0x4c, 0xec, 0x7c, 0x21, - 0xa0, 0x04, 0xa8, 0xfa, 0x21, 0x0b, 0x93, 0x49, 0x4a, 0xda, 0xbe, 0x23, 0x04, 0x39, 0xd7, 0x36, - 0x1c, 0x39, 0xcb, 0x71, 0xfe, 0x1d, 0x2d, 0xc2, 0xd4, 0x43, 0xdf, 0xe3, 0x97, 0x52, 0x6f, 0x12, - 0xbf, 0x7d, 0xcc, 0xe4, 0x91, 0x8a, 0xb4, 0x94, 0x6b, 0x4c, 0x46, 0xf0, 0x0e, 0x47, 0xd1, 0x3c, - 0x4c, 0xf4, 0x88, 0x36, 0x6e, 0x31, 0x39, 0xc7, 0x69, 0xa5, 0x08, 0xdc, 0xc3, 0x2d, 0x86, 0xaa, - 0x50, 0xea, 0x10, 0x87, 0x1d, 0xeb, 0xb8, 0xeb, 0x5a, 0xde, 0x99, 0x3c, 0xca, 0x39, 0x45, 0x8e, - 0xfd, 0xc9, 0x21, 0xf4, 0x13, 0x4c, 0x86, 0x14, 0xd3, 0xd7, 0x19, 0x61, 0x86, 0x2d, 0xe7, 0x43, - 0x21, 0x8e, 0xee, 0xfa, 0x87, 0x01, 0x86, 0x54, 0x98, 0xe8, 0xb1, 0xb8, 0xdb, 0x58, 0x4c, 0x69, - 0xd7, 0xe7, 0x66, 0x32, 0x8c, 0x99, 0xb6, 0x4f, 0x19, 0xf6, 0xe4, 0x02, 0xef, 0x28, 0x5a, 0xa2, - 0x05, 0xe8, 0xa5, 0x17, 0x1e, 0xe3, 0xbc, 0xbc, 0xd7, 0x41, 0x68, 0x52, 0x85, 0x92, 0xe1, 0x33, - 0xa2, 0x7b, 0xd8, 0xc1, 0x8f, 0x0d, 0x5b, 0x86, 0x8a, 0xb4, 0x54, 0x68, 0x14, 0x03, 0xac, 0x11, - 0x42, 0xea, 0x1c, 0xfc, 0xc8, 0x0f, 0xf1, 0x5f, 0xdc, 0x65, 0x87, 0xe4, 0x9f, 0x2f, 0x7d, 0x44, - 0xa7, 0xbc, 0x0f, 0x53, 0x87, 0x56, 0x07, 0x7b, 0x21, 0x1a, 0x1c, 0x44, 0xea, 0x11, 0xdc, 0xde, - 0xa0, 0xec, 0x9d, 0x0d, 0x52, 0xbb, 0x50, 0xee, 0x67, 0x29, 0x2e, 0xd1, 0x11, 0x4c, 0xc4, 0x6f, - 0x09, 0x15, 0x17, 0x69, 0x25, 0xe5, 0x22, 0xdd, 0xca, 0x28, 0x6e, 0x52, 0x52, 0x66, 0xfd, 0x4d, - 0x1e, 0x46, 0xb9, 0x35, 0x7a, 0x2e, 0x41, 0x3e, 0x7c, 0xed, 0x68, 0x2d, 0x45, 0xf5, 0xee, 0x98, - 0x51, 0x6a, 0xc3, 0xd2, 0xc3, 0x5e, 0xd4, 0xe5, 0x27, 0x6f, 0x3f, 0xbd, 0xc8, 0xce, 0xa3, 0xaa, - 0x36, 0x68, 0x16, 0xa2, 0x97, 0x12, 0x8c, 0x89, 0x91, 0x81, 0x06, 0xda, 0x24, 0xc7, 0x91, 0xa2, - 0x0d, 0xcd, 0x17, 0xb9, 0x7e, 0xe3, 0xb9, 0x34, 0xb4, 0x96, 0x92, 0xcb, 0x0c, 0x6b, 0xb4, 0xf3, - 0xe8, 0x78, 0x2f, 0xd0, 0x2b, 0x09, 0x4a, 0xf1, 0xe9, 0x81, 0x36, 0x06, 0x19, 0xdf, 0x33, 0xab, - 0x94, 0x5f, 0xbf, 0xae, 0x48, 0x44, 0xde, 0xe6, 0x91, 0xb7, 0xd0, 0x66, 0x4a, 0x64, 0xdb, 0xa2, - 0x4c, 0x8f, 0xc6, 0x96, 0x76, 0x1e, 0xff, 0xed, 0x02, 0x3d, 0x95, 0x20, 0x17, 0x28, 0xa3, 0x5f, - 0x86, 0xf1, 0x8f, 0xc2, 0xae, 0x0e, 0x47, 0x16, 0x21, 0x17, 0x79, 0xc8, 0x2a, 0x9a, 0x1b, 0x10, - 0x12, 0xbd, 0x96, 0x60, 0xfa, 0xce, 0x13, 0x40, 0xbf, 0x0f, 0x32, 0xeb, 0xf7, 0x50, 0x95, 0xad, - 0x6f, 0xa8, 0x14, 0x99, 0x37, 0x79, 0xe6, 0x3a, 0xd2, 0x52, 0x32, 0x3b, 0xb8, 0xcb, 0x74, 0x46, - 0xf4, 0xf8, 0xeb, 0xde, 0xf9, 0xeb, 0xf2, 0xba, 0x2c, 0x5d, 0x5d, 0x97, 0xa5, 0x8f, 0xd7, 0x65, - 0xe9, 0xd9, 0x4d, 0x39, 0x73, 0x75, 0x53, 0xce, 0xbc, 0xbb, 0x29, 0x67, 0x1e, 0xac, 0xb6, 0x2d, - 0x76, 0xec, 0x37, 0x6b, 0x26, 0xe9, 0x24, 0x45, 0xbb, 0x49, 0x59, 0x76, 0xe6, 0x62, 0xda, 0xcc, - 0xf3, 0x3f, 0xf6, 0x8d, 0xcf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x4d, 0x0f, 0x12, 0xfe, 0xd2, 0x08, - 0x00, 0x00, + // 876 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0x51, 0x6f, 0xdb, 0x54, + 0x14, 0xae, 0xdb, 0x2c, 0x4d, 0x4f, 0xd2, 0x6e, 0xbb, 0xad, 0x90, 0x67, 0x41, 0xda, 0x7a, 0x8c, + 0x6e, 0xa3, 0x8b, 0x95, 0x16, 0x54, 0xf6, 0xc2, 0xa4, 0x56, 0x4c, 0x02, 0x15, 0x14, 0xb2, 0x6a, + 0x48, 0x3c, 0x60, 0x39, 0xe6, 0x26, 0x35, 0x72, 0x7c, 0x3d, 0xdf, 0x7b, 0x47, 0xaa, 0x69, 0x2f, + 0x3c, 0xf2, 0x84, 0xe0, 0x17, 0xf0, 0x37, 0x78, 0xe3, 0x6d, 0x4f, 0x68, 0x12, 0x0f, 0xf0, 0x84, + 0x50, 0xcb, 0x0f, 0x41, 0xf7, 0xf8, 0x3a, 0xd8, 0x4b, 0xe3, 0x84, 0x3d, 0xc5, 0xf7, 0xf8, 0x3b, + 0xdf, 0xf7, 0x9d, 0x73, 0x8f, 0x8f, 0x02, 0xb7, 0x42, 0xef, 0xa9, 0x17, 0x51, 0xe1, 0xa8, 0x5f, + 0x87, 0xcb, 0x1e, 0xf7, 0x93, 0x20, 0x16, 0x01, 0x8b, 0x9c, 0x27, 0x92, 0x26, 0x67, 0xad, 0x38, + 0x61, 0x82, 0x91, 0x1b, 0x1a, 0xd6, 0x52, 0xbf, 0xad, 0x3c, 0xcc, 0xda, 0x18, 0xb0, 0x01, 0x43, + 0x94, 0xa3, 0x9e, 0xd2, 0x04, 0xeb, 0xcd, 0x01, 0x63, 0x83, 0x90, 0x3a, 0x5e, 0x1c, 0x38, 0x5e, + 0x14, 0x31, 0xe1, 0x29, 0x30, 0xd7, 0x6f, 0xef, 0xfa, 0x8c, 0x0f, 0x19, 0x77, 0x7a, 0x1e, 0xa7, + 0xa9, 0x8e, 0xf3, 0xb4, 0xdd, 0xa3, 0xc2, 0x6b, 0x3b, 0xb1, 0x37, 0x08, 0x22, 0x04, 0x6b, 0xec, + 0x3b, 0xd3, 0x1d, 0xc6, 0x5e, 0xe2, 0x0d, 0x33, 0xce, 0xdd, 0xe9, 0xb8, 0xfc, 0x21, 0x45, 0xdb, + 0x1b, 0x40, 0x3e, 0x57, 0xba, 0x1d, 0xa4, 0xe8, 0xd2, 0x27, 0x92, 0x72, 0x61, 0x3f, 0x86, 0xf5, + 0x42, 0x94, 0xc7, 0x2c, 0xe2, 0x94, 0x3c, 0x80, 0x6a, 0x2a, 0x65, 0x1a, 0x5b, 0xc6, 0xed, 0xfa, + 0xde, 0x76, 0x6b, 0x6a, 0x3b, 0x5a, 0x69, 0xea, 0x61, 0xe5, 0xc5, 0x5f, 0x9b, 0x0b, 0x5d, 0x9d, + 0x66, 0xb7, 0x35, 0xef, 0x91, 0x4c, 0x12, 0x1a, 0x09, 0x2d, 0x47, 0x2c, 0xa8, 0xf9, 0x2c, 0xe2, + 0x72, 0x48, 0x13, 0x64, 0x5e, 0xe9, 0x8e, 0xcf, 0xf6, 0x17, 0xb0, 0x51, 0x4c, 0x19, 0x7b, 0x59, + 0xe2, 0xb2, 0xa7, 0x8d, 0xec, 0x94, 0x18, 0x79, 0x94, 0x3b, 0xa0, 0x1d, 0xa3, 0xab, 0x32, 0xed, + 0x0f, 0xc1, 0x44, 0xe2, 0xe3, 0x80, 0x8b, 0x4e, 0xc2, 0xbe, 0xa1, 0xbe, 0xc8, 0xea, 0x27, 0x36, + 0x34, 0xf2, 0x1c, 0xda, 0x54, 0x21, 0x66, 0x1f, 0xc0, 0x8d, 0x4b, 0xf2, 0xb5, 0x3b, 0x0b, 0x6a, + 0xb1, 0x8e, 0x99, 0xc6, 0xd6, 0x92, 0xaa, 0x28, 0x3b, 0xdb, 0x04, 0xae, 0x8d, 0x13, 0xb3, 0x86, + 0x7b, 0x70, 0x3d, 0x17, 0xd3, 0x24, 0xc7, 0xb0, 0xa2, 0x14, 0xdd, 0x20, 0xea, 0x33, 0x64, 0xa9, + 0xef, 0xdd, 0x29, 0x29, 0x54, 0xe5, 0x7e, 0x1c, 0xf5, 0xd9, 0x23, 0x91, 0x48, 0x5f, 0xe8, 0xce, + 0xd7, 0x14, 0x44, 0x45, 0xed, 0x3f, 0x96, 0x60, 0xad, 0x08, 0x29, 0xeb, 0x3b, 0x21, 0x50, 0x89, + 0x43, 0x2f, 0x32, 0x17, 0x31, 0x8e, 0xcf, 0x64, 0x07, 0xae, 0x7e, 0x2d, 0x13, 0x1c, 0x4a, 0xb7, + 0xc7, 0xe4, 0xe0, 0x54, 0x98, 0x4b, 0x5b, 0xc6, 0xed, 0x4a, 0x77, 0x2d, 0x0b, 0x1f, 0x62, 0x94, + 0xdc, 0x84, 0xd5, 0x31, 0x30, 0xa4, 0x7d, 0x61, 0x56, 0x10, 0xd6, 0xc8, 0x82, 0xc7, 0xb4, 0x2f, + 0xc8, 0x36, 0x34, 0x86, 0x2c, 0x12, 0xa7, 0x2e, 0x1d, 0xc5, 0x41, 0x72, 0x66, 0x5e, 0x41, 0x4c, + 0x1d, 0x63, 0x1f, 0x61, 0x88, 0xbc, 0x0d, 0x6b, 0x29, 0xc4, 0x97, 0xae, 0x60, 0xc2, 0x0b, 0xcd, + 0x6a, 0x4a, 0x84, 0xd1, 0x23, 0x79, 0xa2, 0x62, 0xc4, 0x86, 0xd5, 0x31, 0x0a, 0xd5, 0x96, 0x73, + 0x4c, 0x47, 0x12, 0xc5, 0x4c, 0x58, 0xf6, 0x43, 0xc9, 0x05, 0x4d, 0xcc, 0x1a, 0x56, 0x94, 0x1d, + 0xc9, 0x2d, 0x18, 0xbb, 0xd7, 0x1a, 0x2b, 0x98, 0x3e, 0xae, 0x20, 0x15, 0xd9, 0x87, 0x37, 0x3c, + 0x29, 0x98, 0x9b, 0xd0, 0x88, 0x7e, 0xeb, 0x85, 0x6e, 0x44, 0x47, 0xc2, 0xc5, 0x0e, 0xd5, 0x91, + 0x6f, 0x5d, 0xbd, 0xed, 0xa6, 0x2f, 0x3f, 0xa3, 0x23, 0xd1, 0x51, 0x0d, 0xfb, 0x0a, 0xd6, 0xfb, + 0x52, 0xc8, 0x84, 0xba, 0x85, 0x71, 0x6a, 0xe0, 0xd0, 0xde, 0x2b, 0xb9, 0xcb, 0x87, 0x98, 0x95, + 0x1f, 0xdd, 0x2e, 0xe9, 0x4f, 0xc4, 0x3e, 0xa9, 0xd4, 0xe0, 0x5a, 0xdd, 0xde, 0x84, 0xb7, 0x70, + 0x78, 0x94, 0xec, 0x09, 0xfb, 0xf4, 0xbf, 0xfe, 0x65, 0xd3, 0xd5, 0x81, 0xab, 0x27, 0xc1, 0x90, + 0x26, 0x69, 0x54, 0x0d, 0x40, 0xe9, 0xd5, 0xbf, 0x7a, 0x31, 0x8b, 0x13, 0x17, 0x63, 0x8f, 0xa0, + 0x39, 0x4d, 0x52, 0x0f, 0xef, 0x63, 0x58, 0xcd, 0x57, 0xc4, 0xf5, 0x00, 0xdf, 0x2d, 0x29, 0xfa, + 0x15, 0x8f, 0x7a, 0x82, 0x8b, 0x34, 0x7b, 0xbf, 0x55, 0xe1, 0x0a, 0x4a, 0x93, 0x1f, 0x0d, 0xa8, + 0xa6, 0x5b, 0x86, 0x94, 0xb5, 0x72, 0x72, 0xbd, 0x59, 0xad, 0x79, 0xe1, 0x69, 0x2d, 0xf6, 0x9d, + 0xef, 0x7e, 0xff, 0xe7, 0xa7, 0xc5, 0x9b, 0x64, 0xdb, 0x99, 0xb5, 0x83, 0xc9, 0xcf, 0x06, 0x2c, + 0xeb, 0x55, 0x45, 0x66, 0xca, 0x14, 0xd7, 0xa0, 0xe5, 0xcc, 0x8d, 0xd7, 0xbe, 0xde, 0x47, 0x5f, + 0x0e, 0xb9, 0x57, 0xe2, 0xcb, 0x4f, 0x73, 0x9c, 0x67, 0xd9, 0xf5, 0x3e, 0x27, 0xbf, 0x18, 0xd0, + 0xc8, 0x6f, 0x2d, 0xb2, 0x3f, 0x4b, 0xf8, 0x92, 0x1d, 0x69, 0xbd, 0xf7, 0xff, 0x92, 0xb4, 0xe5, + 0x07, 0x68, 0xf9, 0x3e, 0x39, 0x28, 0xb1, 0x1c, 0x06, 0x5c, 0xb8, 0xd9, 0xba, 0x74, 0x9e, 0xe5, + 0xdf, 0x3d, 0x27, 0xdf, 0x1b, 0x50, 0x51, 0xcc, 0xe4, 0xdd, 0x79, 0xf4, 0x33, 0xb3, 0xbb, 0xf3, + 0x81, 0xb5, 0xc9, 0x1d, 0x34, 0xb9, 0x4d, 0x36, 0x67, 0x98, 0x24, 0xbf, 0x1a, 0x70, 0x7d, 0xe2, + 0x13, 0x20, 0x1f, 0xcc, 0x12, 0x9b, 0xf6, 0xa1, 0x5a, 0xf7, 0x5f, 0x23, 0x53, 0x7b, 0x3e, 0x40, + 0xcf, 0x6d, 0xe2, 0x94, 0x78, 0xc6, 0x9d, 0x25, 0x98, 0x9b, 0xff, 0xba, 0x0f, 0x1f, 0xbe, 0x38, + 0x6f, 0x1a, 0x2f, 0xcf, 0x9b, 0xc6, 0xdf, 0xe7, 0x4d, 0xe3, 0x87, 0x8b, 0xe6, 0xc2, 0xcb, 0x8b, + 0xe6, 0xc2, 0x9f, 0x17, 0xcd, 0x85, 0x2f, 0x77, 0x07, 0x81, 0x38, 0x95, 0xbd, 0x96, 0xcf, 0x86, + 0x45, 0xd2, 0x51, 0x91, 0x56, 0x9c, 0xc5, 0x94, 0xf7, 0xaa, 0xf8, 0x87, 0x62, 0xff, 0xdf, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x20, 0x4e, 0x3c, 0x4c, 0x4a, 0x09, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1190,15 +1200,24 @@ func (m *ListInfoStruct) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.AutoRenewal { - i-- - if m.AutoRenewal { - dAtA[i] = 1 - } else { - dAtA[i] = 0 + if m.FutureSubscription != nil { + { + size, err := m.FutureSubscription.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x50 + dAtA[i] = 0x62 + } + if len(m.AutoRenewalNextPlan) > 0 { + i -= len(m.AutoRenewalNextPlan) + copy(dAtA[i:], m.AutoRenewalNextPlan) + i = encodeVarintQuery(dAtA, i, uint64(len(m.AutoRenewalNextPlan))) + i-- + dAtA[i] = 0x5a } if m.DurationTotal != 0 { i = encodeVarintQuery(dAtA, i, uint64(m.DurationTotal)) @@ -1494,8 +1513,13 @@ func (m *ListInfoStruct) Size() (n int) { if m.DurationTotal != 0 { n += 1 + sovQuery(uint64(m.DurationTotal)) } - if m.AutoRenewal { - n += 2 + l = len(m.AutoRenewalNextPlan) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + if m.FutureSubscription != nil { + l = m.FutureSubscription.Size() + n += 1 + l + sovQuery(uint64(l)) } return n } @@ -2384,11 +2408,43 @@ func (m *ListInfoStruct) Unmarshal(dAtA []byte) error { break } } - case 10: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field AutoRenewal", wireType) + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AutoRenewalNextPlan", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AutoRenewalNextPlan = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FutureSubscription", wireType) } - var v int + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowQuery @@ -2398,12 +2454,28 @@ func (m *ListInfoStruct) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - v |= int(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - m.AutoRenewal = bool(v != 0) + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.FutureSubscription == nil { + m.FutureSubscription = &FutureSubscription{} + } + if err := m.FutureSubscription.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipQuery(dAtA[iNdEx:]) diff --git a/x/subscription/types/subscription.go b/x/subscription/types/subscription.go index a8fd325916..978ea94efb 100644 --- a/x/subscription/types/subscription.go +++ b/x/subscription/types/subscription.go @@ -8,6 +8,7 @@ import ( const ( MAX_SUBSCRIPTION_DURATION = 12 // max duration of subscription in months + AUTO_RENEWAL_PLAN_NONE = "none" ) // ValidateSubscription validates a subscription object fields @@ -38,3 +39,7 @@ func (sub Subscription) ValidateSubscription() error { return nil } + +func (sub Subscription) IsAutoRenewalOn() bool { + return sub.AutoRenewalNextPlan != AUTO_RENEWAL_PLAN_NONE +} diff --git a/x/subscription/types/subscription.pb.go b/x/subscription/types/subscription.pb.go index f131a31091..b2e388cd9d 100644 --- a/x/subscription/types/subscription.pb.go +++ b/x/subscription/types/subscription.pb.go @@ -23,20 +23,20 @@ var _ = math.Inf const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type Subscription struct { - Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` - Consumer string `protobuf:"bytes,2,opt,name=consumer,proto3" json:"consumer,omitempty"` - Block uint64 `protobuf:"varint,3,opt,name=block,proto3" json:"block,omitempty"` - PlanIndex string `protobuf:"bytes,4,opt,name=plan_index,json=planIndex,proto3" json:"plan_index,omitempty"` - PlanBlock uint64 `protobuf:"varint,5,opt,name=plan_block,json=planBlock,proto3" json:"plan_block,omitempty"` - DurationBought uint64 `protobuf:"varint,6,opt,name=duration_bought,json=durationBought,proto3" json:"duration_bought,omitempty"` - DurationLeft uint64 `protobuf:"varint,7,opt,name=duration_left,json=durationLeft,proto3" json:"duration_left,omitempty"` - MonthExpiryTime uint64 `protobuf:"varint,8,opt,name=month_expiry_time,json=monthExpiryTime,proto3" json:"month_expiry_time,omitempty"` - MonthCuTotal uint64 `protobuf:"varint,10,opt,name=month_cu_total,json=monthCuTotal,proto3" json:"month_cu_total,omitempty"` - MonthCuLeft uint64 `protobuf:"varint,11,opt,name=month_cu_left,json=monthCuLeft,proto3" json:"month_cu_left,omitempty"` - Cluster string `protobuf:"bytes,13,opt,name=cluster,proto3" json:"cluster,omitempty"` - DurationTotal uint64 `protobuf:"varint,14,opt,name=duration_total,json=durationTotal,proto3" json:"duration_total,omitempty"` - AutoRenewal bool `protobuf:"varint,15,opt,name=auto_renewal,json=autoRenewal,proto3" json:"auto_renewal,omitempty"` - FutureSubscription *FutureSubscription `protobuf:"bytes,16,opt,name=future_subscription,json=futureSubscription,proto3" json:"future_subscription,omitempty"` + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + Consumer string `protobuf:"bytes,2,opt,name=consumer,proto3" json:"consumer,omitempty"` + Block uint64 `protobuf:"varint,3,opt,name=block,proto3" json:"block,omitempty"` + PlanIndex string `protobuf:"bytes,4,opt,name=plan_index,json=planIndex,proto3" json:"plan_index,omitempty"` + PlanBlock uint64 `protobuf:"varint,5,opt,name=plan_block,json=planBlock,proto3" json:"plan_block,omitempty"` + DurationBought uint64 `protobuf:"varint,6,opt,name=duration_bought,json=durationBought,proto3" json:"duration_bought,omitempty"` + DurationLeft uint64 `protobuf:"varint,7,opt,name=duration_left,json=durationLeft,proto3" json:"duration_left,omitempty"` + MonthExpiryTime uint64 `protobuf:"varint,8,opt,name=month_expiry_time,json=monthExpiryTime,proto3" json:"month_expiry_time,omitempty"` + MonthCuTotal uint64 `protobuf:"varint,10,opt,name=month_cu_total,json=monthCuTotal,proto3" json:"month_cu_total,omitempty"` + MonthCuLeft uint64 `protobuf:"varint,11,opt,name=month_cu_left,json=monthCuLeft,proto3" json:"month_cu_left,omitempty"` + Cluster string `protobuf:"bytes,13,opt,name=cluster,proto3" json:"cluster,omitempty"` + DurationTotal uint64 `protobuf:"varint,14,opt,name=duration_total,json=durationTotal,proto3" json:"duration_total,omitempty"` + FutureSubscription *FutureSubscription `protobuf:"bytes,16,opt,name=future_subscription,json=futureSubscription,proto3" json:"future_subscription,omitempty"` + AutoRenewalNextPlan string `protobuf:"bytes,17,opt,name=auto_renewal_next_plan,json=autoRenewalNextPlan,proto3" json:"auto_renewal_next_plan,omitempty"` } func (m *Subscription) Reset() { *m = Subscription{} } @@ -156,18 +156,18 @@ func (m *Subscription) GetDurationTotal() uint64 { return 0 } -func (m *Subscription) GetAutoRenewal() bool { +func (m *Subscription) GetFutureSubscription() *FutureSubscription { if m != nil { - return m.AutoRenewal + return m.FutureSubscription } - return false + return nil } -func (m *Subscription) GetFutureSubscription() *FutureSubscription { +func (m *Subscription) GetAutoRenewalNextPlan() string { if m != nil { - return m.FutureSubscription + return m.AutoRenewalNextPlan } - return nil + return "" } type FutureSubscription struct { @@ -248,36 +248,37 @@ func init() { } var fileDescriptor_c3bc5507ca237d79 = []byte{ - // 452 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x93, 0xcf, 0x6e, 0xd3, 0x40, - 0x10, 0xc6, 0xb3, 0xad, 0xdb, 0x3a, 0x93, 0xbf, 0x2c, 0x1c, 0x16, 0x24, 0xac, 0x10, 0x40, 0x44, - 0xa8, 0x38, 0x12, 0xbc, 0x41, 0x10, 0x95, 0xa8, 0x38, 0x99, 0x9e, 0x38, 0x60, 0xd9, 0xee, 0xa6, - 0xb1, 0xb0, 0xbd, 0xd6, 0x7a, 0x16, 0xd2, 0xb7, 0xe0, 0xc2, 0x5b, 0xf0, 0x20, 0x1c, 0x7b, 0xe4, - 0x88, 0x92, 0x17, 0x41, 0x1e, 0x27, 0x56, 0xac, 0x42, 0xd4, 0xd3, 0x6a, 0x7e, 0xf3, 0x7d, 0x1e, - 0xef, 0xce, 0x0c, 0x9c, 0x26, 0xc1, 0xd7, 0x20, 0x93, 0x38, 0x2d, 0xcf, 0x69, 0x61, 0xc2, 0x22, - 0xd2, 0x71, 0x8e, 0xb1, 0xca, 0x1a, 0x81, 0x9b, 0x6b, 0x85, 0x8a, 0x3f, 0xdc, 0xa8, 0xdd, 0xf2, - 0x74, 0x77, 0x05, 0xe3, 0x9f, 0x16, 0x74, 0x3f, 0xee, 0x00, 0x2e, 0xe0, 0x24, 0xd2, 0x32, 0x40, - 0xa5, 0x05, 0x1b, 0xb1, 0x49, 0xdb, 0xdb, 0x86, 0xfc, 0x11, 0xd8, 0x91, 0xca, 0x0a, 0x93, 0x4a, - 0x2d, 0x0e, 0x28, 0x55, 0xc7, 0xfc, 0x01, 0x1c, 0x85, 0x89, 0x8a, 0xbe, 0x88, 0xc3, 0x11, 0x9b, - 0x58, 0x5e, 0x15, 0xf0, 0xc7, 0x00, 0x79, 0x12, 0x64, 0x7e, 0x9c, 0x5d, 0xca, 0xa5, 0xb0, 0xc8, - 0xd3, 0x2e, 0xc9, 0xfb, 0x12, 0xd4, 0xe9, 0xca, 0x79, 0x44, 0x4e, 0x4a, 0xcf, 0xc8, 0xfd, 0x02, - 0x06, 0x97, 0x46, 0x07, 0xe5, 0x5f, 0xf9, 0xa1, 0x32, 0x57, 0x0b, 0x14, 0xc7, 0xa4, 0xe9, 0x6f, - 0xf1, 0x8c, 0x28, 0x7f, 0x0a, 0xbd, 0x5a, 0x98, 0xc8, 0x39, 0x8a, 0x13, 0x92, 0x75, 0xb7, 0xf0, - 0x83, 0x9c, 0x23, 0x7f, 0x09, 0xf7, 0x52, 0x95, 0xe1, 0xc2, 0x97, 0xcb, 0x3c, 0xd6, 0xd7, 0x3e, - 0xc6, 0xa9, 0x14, 0x36, 0x09, 0x07, 0x94, 0x78, 0x47, 0xfc, 0x22, 0x4e, 0x25, 0x7f, 0x06, 0xfd, - 0x4a, 0x1b, 0x19, 0x1f, 0x15, 0x06, 0x89, 0x80, 0xea, 0x8b, 0x44, 0xdf, 0x9a, 0x8b, 0x92, 0xf1, - 0x31, 0xf4, 0x6a, 0x15, 0x95, 0xed, 0x90, 0xa8, 0xb3, 0x11, 0x51, 0xd5, 0xf2, 0x35, 0x13, 0x53, - 0xa0, 0xd4, 0xa2, 0xb7, 0x79, 0xcd, 0x2a, 0xe4, 0xcf, 0xa1, 0xbe, 0xc6, 0xa6, 0x46, 0x9f, 0xec, - 0xf5, 0x55, 0xaa, 0x22, 0x4f, 0xa0, 0x1b, 0x18, 0x54, 0xbe, 0x96, 0x99, 0xfc, 0x16, 0x24, 0x62, - 0x30, 0x62, 0x13, 0xdb, 0xeb, 0x94, 0xcc, 0xab, 0x10, 0xff, 0x0c, 0xf7, 0xe7, 0x06, 0x8d, 0x96, - 0xfe, 0x6e, 0x67, 0xc5, 0x70, 0xc4, 0x26, 0x9d, 0xd7, 0xaf, 0xdc, 0xff, 0xf6, 0xde, 0x3d, 0x23, - 0xd7, 0x6e, 0xf7, 0x3d, 0x3e, 0xbf, 0xc5, 0xce, 0x2d, 0xbb, 0x3d, 0x84, 0x73, 0xcb, 0xee, 0x0e, - 0x7b, 0xe3, 0x1f, 0x0c, 0xf8, 0x6d, 0xdb, 0x9e, 0xa1, 0x69, 0x8e, 0xc0, 0xc1, 0xfe, 0x11, 0x38, - 0xbc, 0xc3, 0x08, 0x58, 0xff, 0x1a, 0x81, 0xd9, 0xd9, 0xaf, 0x95, 0xc3, 0x6e, 0x56, 0x0e, 0xfb, - 0xb3, 0x72, 0xd8, 0xf7, 0xb5, 0xd3, 0xba, 0x59, 0x3b, 0xad, 0xdf, 0x6b, 0xa7, 0xf5, 0xe9, 0xf4, - 0x2a, 0xc6, 0x85, 0x09, 0xdd, 0x48, 0xa5, 0xd3, 0xc6, 0xd2, 0x2c, 0x9b, 0x6b, 0x83, 0xd7, 0xb9, - 0x2c, 0xc2, 0x63, 0x5a, 0x98, 0x37, 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xb1, 0xdc, 0x42, 0x8e, - 0x60, 0x03, 0x00, 0x00, + // 468 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x53, 0xcd, 0x6e, 0xd3, 0x40, + 0x10, 0x8e, 0x5b, 0xb7, 0x4d, 0x26, 0x7f, 0xee, 0x16, 0xa1, 0x05, 0x09, 0x2b, 0x0a, 0x20, 0x22, + 0x54, 0x1c, 0x89, 0xbe, 0x41, 0x10, 0x95, 0x88, 0x10, 0x42, 0xa1, 0x27, 0x0e, 0x58, 0xb6, 0xbb, + 0x69, 0x2c, 0x6c, 0xaf, 0xb5, 0x9e, 0x05, 0xf7, 0x2d, 0xb8, 0xf0, 0x46, 0x1c, 0x38, 0xf6, 0xc8, + 0x11, 0x25, 0x2f, 0x82, 0x76, 0x9c, 0x58, 0x89, 0x0a, 0x15, 0x27, 0x6b, 0xbe, 0x1f, 0xcf, 0xee, + 0xce, 0x37, 0x70, 0x9a, 0x04, 0x5f, 0x82, 0x4c, 0xe0, 0xd8, 0x7c, 0xc7, 0x85, 0x0e, 0x8b, 0x48, + 0xc5, 0x39, 0xc6, 0x32, 0xdb, 0x29, 0xbc, 0x5c, 0x49, 0x94, 0xec, 0xc1, 0x5a, 0xed, 0x99, 0xaf, + 0xb7, 0x2d, 0x18, 0xfe, 0xb0, 0xa1, 0xf3, 0x61, 0x0b, 0x60, 0x1c, 0x8e, 0x22, 0x25, 0x02, 0x94, + 0x8a, 0x5b, 0x03, 0x6b, 0xd4, 0x9a, 0x6d, 0x4a, 0xf6, 0x10, 0x9a, 0x91, 0xcc, 0x0a, 0x9d, 0x0a, + 0xc5, 0xf7, 0x88, 0xaa, 0x6b, 0x76, 0x0f, 0x0e, 0xc2, 0x44, 0x46, 0x9f, 0xf9, 0xfe, 0xc0, 0x1a, + 0xd9, 0xb3, 0xaa, 0x60, 0x8f, 0x00, 0xf2, 0x24, 0xc8, 0xfc, 0x38, 0xbb, 0x14, 0x25, 0xb7, 0xc9, + 0xd3, 0x32, 0xc8, 0x1b, 0x03, 0xd4, 0x74, 0xe5, 0x3c, 0x20, 0x27, 0xd1, 0x13, 0x72, 0x3f, 0x83, + 0xfe, 0xa5, 0x56, 0x81, 0x39, 0x95, 0x1f, 0x4a, 0x7d, 0xb5, 0x40, 0x7e, 0x48, 0x9a, 0xde, 0x06, + 0x9e, 0x10, 0xca, 0x1e, 0x43, 0xb7, 0x16, 0x26, 0x62, 0x8e, 0xfc, 0x88, 0x64, 0x9d, 0x0d, 0xf8, + 0x56, 0xcc, 0x91, 0x3d, 0x87, 0xe3, 0x54, 0x66, 0xb8, 0xf0, 0x45, 0x99, 0xc7, 0xea, 0xda, 0xc7, + 0x38, 0x15, 0xbc, 0x49, 0xc2, 0x3e, 0x11, 0xaf, 0x09, 0xbf, 0x88, 0x53, 0xc1, 0x9e, 0x40, 0xaf, + 0xd2, 0x46, 0xda, 0x47, 0x89, 0x41, 0xc2, 0xa1, 0xfa, 0x23, 0xa1, 0xaf, 0xf4, 0x85, 0xc1, 0xd8, + 0x10, 0xba, 0xb5, 0x8a, 0xda, 0xb6, 0x49, 0xd4, 0x5e, 0x8b, 0xa8, 0xab, 0x79, 0xcd, 0x44, 0x17, + 0x28, 0x14, 0xef, 0xae, 0x5f, 0xb3, 0x2a, 0xd9, 0x53, 0xa8, 0xaf, 0xb1, 0xee, 0xd1, 0x23, 0x7b, + 0x7d, 0x95, 0xaa, 0xc9, 0x27, 0x38, 0x99, 0x6b, 0xd4, 0x4a, 0xf8, 0xdb, 0x63, 0xe3, 0xce, 0xc0, + 0x1a, 0xb5, 0x5f, 0xbe, 0xf0, 0xfe, 0x39, 0x58, 0xef, 0x9c, 0x5c, 0xdb, 0xa3, 0x9d, 0xb1, 0xf9, + 0x2d, 0x8c, 0x9d, 0xc1, 0xfd, 0x40, 0xa3, 0xf4, 0x95, 0xc8, 0xc4, 0xd7, 0x20, 0xf1, 0x33, 0x51, + 0xa2, 0x6f, 0x66, 0xc0, 0x8f, 0xe9, 0xbc, 0x27, 0x86, 0x9d, 0x55, 0xe4, 0x3b, 0x51, 0xe2, 0xfb, + 0x24, 0xc8, 0xa6, 0x76, 0xb3, 0xe5, 0xc0, 0xd4, 0x6e, 0x76, 0x9c, 0xee, 0xd4, 0x6e, 0xf6, 0x1d, + 0x67, 0xf8, 0xdd, 0x02, 0x76, 0xbb, 0xe3, 0x1d, 0x61, 0xda, 0x8d, 0xc6, 0xde, 0xdd, 0xd1, 0xd8, + 0xff, 0x8f, 0x68, 0xd8, 0x7f, 0x8b, 0xc6, 0xe4, 0xfc, 0xe7, 0xd2, 0xb5, 0x6e, 0x96, 0xae, 0xf5, + 0x7b, 0xe9, 0x5a, 0xdf, 0x56, 0x6e, 0xe3, 0x66, 0xe5, 0x36, 0x7e, 0xad, 0xdc, 0xc6, 0xc7, 0xd3, + 0xab, 0x18, 0x17, 0x3a, 0xf4, 0x22, 0x99, 0x8e, 0x77, 0x96, 0xa9, 0xdc, 0x5d, 0x27, 0xbc, 0xce, + 0x45, 0x11, 0x1e, 0xd2, 0x22, 0x9d, 0xfd, 0x09, 0x00, 0x00, 0xff, 0xff, 0xad, 0xec, 0x4c, 0x89, + 0x78, 0x03, 0x00, 0x00, } func (m *Subscription) Marshal() (dAtA []byte, err error) { @@ -300,6 +301,15 @@ func (m *Subscription) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.AutoRenewalNextPlan) > 0 { + i -= len(m.AutoRenewalNextPlan) + copy(dAtA[i:], m.AutoRenewalNextPlan) + i = encodeVarintSubscription(dAtA, i, uint64(len(m.AutoRenewalNextPlan))) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x8a + } if m.FutureSubscription != nil { { size, err := m.FutureSubscription.MarshalToSizedBuffer(dAtA[:i]) @@ -314,16 +324,6 @@ func (m *Subscription) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x82 } - if m.AutoRenewal { - i-- - if m.AutoRenewal { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x78 - } if m.DurationTotal != 0 { i = encodeVarintSubscription(dAtA, i, uint64(m.DurationTotal)) i-- @@ -499,13 +499,14 @@ func (m *Subscription) Size() (n int) { if m.DurationTotal != 0 { n += 1 + sovSubscription(uint64(m.DurationTotal)) } - if m.AutoRenewal { - n += 2 - } if m.FutureSubscription != nil { l = m.FutureSubscription.Size() n += 2 + l + sovSubscription(uint64(l)) } + l = len(m.AutoRenewalNextPlan) + if l > 0 { + n += 2 + l + sovSubscription(uint64(l)) + } return n } @@ -847,11 +848,11 @@ func (m *Subscription) Unmarshal(dAtA []byte) error { break } } - case 15: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field AutoRenewal", wireType) + case 16: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FutureSubscription", wireType) } - var v int + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowSubscription @@ -861,17 +862,33 @@ func (m *Subscription) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - v |= int(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - m.AutoRenewal = bool(v != 0) - case 16: + if msglen < 0 { + return ErrInvalidLengthSubscription + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSubscription + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.FutureSubscription == nil { + m.FutureSubscription = &FutureSubscription{} + } + if err := m.FutureSubscription.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 17: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field FutureSubscription", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field AutoRenewalNextPlan", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowSubscription @@ -881,27 +898,23 @@ func (m *Subscription) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthSubscription } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthSubscription } if postIndex > l { return io.ErrUnexpectedEOF } - if m.FutureSubscription == nil { - m.FutureSubscription = &FutureSubscription{} - } - if err := m.FutureSubscription.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.AutoRenewalNextPlan = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex diff --git a/x/subscription/types/tx.pb.go b/x/subscription/types/tx.pb.go index d7c5cbbbf7..c61435b249 100644 --- a/x/subscription/types/tx.pb.go +++ b/x/subscription/types/tx.pb.go @@ -326,8 +326,10 @@ func (m *MsgDelProjectResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgDelProjectResponse proto.InternalMessageInfo type MsgAutoRenewal struct { - Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` - Enable bool `protobuf:"varint,2,opt,name=enable,proto3" json:"enable,omitempty"` + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + Enable bool `protobuf:"varint,2,opt,name=enable,proto3" json:"enable,omitempty"` + Consumer string `protobuf:"bytes,3,opt,name=consumer,proto3" json:"consumer,omitempty"` + Index string `protobuf:"bytes,4,opt,name=index,proto3" json:"index,omitempty"` } func (m *MsgAutoRenewal) Reset() { *m = MsgAutoRenewal{} } @@ -377,6 +379,20 @@ func (m *MsgAutoRenewal) GetEnable() bool { return false } +func (m *MsgAutoRenewal) GetConsumer() string { + if m != nil { + return m.Consumer + } + return "" +} + +func (m *MsgAutoRenewal) GetIndex() string { + if m != nil { + return m.Index + } + return "" +} + type MsgAutoRenewalResponse struct { } @@ -429,38 +445,39 @@ func init() { } var fileDescriptor_b1bb075a6865b817 = []byte{ - // 490 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0xc1, 0x6e, 0xd3, 0x40, - 0x10, 0x8d, 0x89, 0xeb, 0x86, 0x49, 0x81, 0x68, 0x55, 0x8a, 0xf1, 0xc1, 0xa4, 0xe6, 0x92, 0x4a, - 0xc8, 0x86, 0x72, 0xe6, 0xd0, 0xa8, 0xe2, 0x00, 0x8a, 0x54, 0x99, 0x1b, 0x97, 0x68, 0x63, 0xaf, - 0x9c, 0x40, 0xb2, 0x6b, 0xed, 0xae, 0x43, 0xfa, 0x17, 0xdc, 0xf9, 0x1d, 0x0e, 0x3d, 0xf6, 0xc8, - 0x09, 0xa1, 0xe4, 0x47, 0x90, 0xd7, 0xeb, 0xc4, 0x06, 0xb5, 0xce, 0x69, 0x67, 0x66, 0xdf, 0xbc, - 0x99, 0x79, 0xb3, 0x5a, 0xf0, 0xe6, 0x78, 0x89, 0x29, 0x91, 0x41, 0x7e, 0x06, 0x22, 0x9b, 0x88, - 0x88, 0xcf, 0x52, 0x39, 0x63, 0x34, 0x90, 0x2b, 0x3f, 0xe5, 0x4c, 0x32, 0xf4, 0x5c, 0x63, 0xfc, - 0xfc, 0xf4, 0xab, 0x18, 0xe7, 0x65, 0x2d, 0x3d, 0xe5, 0xec, 0x0b, 0x89, 0xa4, 0x28, 0x8d, 0x22, - 0xdf, 0x39, 0x4e, 0x58, 0xc2, 0x94, 0x19, 0xe4, 0x56, 0x11, 0xf5, 0x7e, 0x1a, 0x60, 0x8d, 0x44, - 0x32, 0xcc, 0xae, 0x91, 0x0d, 0x87, 0x11, 0x27, 0x58, 0x32, 0x6e, 0x1b, 0x7d, 0x63, 0xf0, 0x30, - 0x2c, 0x5d, 0xe4, 0x40, 0x27, 0x62, 0x54, 0x64, 0x0b, 0xc2, 0xed, 0x07, 0xea, 0x6a, 0xeb, 0xa3, - 0x63, 0x38, 0x98, 0xd1, 0x98, 0xac, 0xec, 0xb6, 0xba, 0x28, 0x9c, 0x3c, 0x23, 0xce, 0x38, 0xce, - 0xbb, 0xb3, 0xcd, 0xbe, 0x31, 0x30, 0xc3, 0xad, 0x8f, 0x4e, 0xe1, 0x08, 0x67, 0x92, 0x8d, 0x39, - 0xa1, 0xe4, 0x1b, 0x9e, 0xdb, 0x56, 0xdf, 0x18, 0x74, 0xc2, 0x6e, 0x1e, 0x0b, 0x8b, 0x10, 0x3a, - 0x83, 0x1e, 0x8e, 0x97, 0x98, 0x46, 0x64, 0x9c, 0x66, 0x3c, 0x9a, 0x62, 0x41, 0xec, 0x43, 0x05, - 0x7b, 0xa2, 0xe3, 0x57, 0x3a, 0xfc, 0xc1, 0xec, 0x1c, 0xf4, 0x2c, 0xaf, 0x07, 0x8f, 0x8b, 0x29, - 0x42, 0x22, 0x52, 0x46, 0x05, 0xf1, 0x96, 0xf0, 0x68, 0x24, 0x92, 0x8b, 0x38, 0xbe, 0x2a, 0x54, - 0xb8, 0x67, 0xbc, 0x8f, 0x70, 0xa4, 0xa5, 0x1a, 0xc7, 0x58, 0x62, 0x35, 0x62, 0xf7, 0xdc, 0xf3, - 0x6b, 0x82, 0x97, 0xaa, 0xfa, 0x9a, 0xef, 0x12, 0x4b, 0x3c, 0x34, 0x6f, 0x7e, 0xbf, 0x68, 0x85, - 0xdd, 0x74, 0x17, 0xf2, 0x9e, 0xc1, 0xd3, 0x5a, 0xdd, 0x6d, 0x43, 0xef, 0x54, 0x43, 0x97, 0x64, - 0xde, 0xdc, 0x10, 0x02, 0x93, 0xe2, 0x05, 0xd1, 0x5a, 0x2b, 0x5b, 0xf3, 0xee, 0xd2, 0xb7, 0xbc, - 0x43, 0x35, 0xfa, 0x45, 0x45, 0xbd, 0xbb, 0x89, 0x4f, 0xc0, 0x22, 0x14, 0x4f, 0xe6, 0x05, 0x75, - 0x27, 0xd4, 0x9e, 0x67, 0xc3, 0x49, 0x9d, 0xa3, 0x64, 0x3f, 0xff, 0xd1, 0x86, 0xf6, 0x48, 0x24, - 0xe8, 0x13, 0xb4, 0xf3, 0x37, 0x72, 0xea, 0xdf, 0xf9, 0x0a, 0xfd, 0x62, 0x01, 0xce, 0x59, 0x23, - 0xa4, 0x24, 0x47, 0x53, 0x80, 0xca, 0x82, 0x06, 0xf7, 0x27, 0xee, 0x90, 0xce, 0xeb, 0x7d, 0x91, - 0xd5, 0x4a, 0x15, 0xe5, 0x1b, 0x2a, 0xed, 0x90, 0x4d, 0x95, 0xfe, 0x5f, 0x07, 0xfa, 0x0a, 0xdd, - 0xea, 0x2e, 0x1a, 0xd4, 0xa8, 0x40, 0x9d, 0x37, 0x7b, 0x43, 0xcb, 0x62, 0xc3, 0xf7, 0x37, 0x6b, - 0xd7, 0xb8, 0x5d, 0xbb, 0xc6, 0x9f, 0xb5, 0x6b, 0x7c, 0xdf, 0xb8, 0xad, 0xdb, 0x8d, 0xdb, 0xfa, - 0xb5, 0x71, 0x5b, 0x9f, 0x5f, 0x25, 0x33, 0x39, 0xcd, 0x26, 0x7e, 0xc4, 0x16, 0x41, 0xed, 0x77, - 0x58, 0xfd, 0xf3, 0xbd, 0x5c, 0xa7, 0x44, 0x4c, 0x2c, 0xf5, 0x19, 0xbc, 0xfd, 0x1b, 0x00, 0x00, - 0xff, 0xff, 0x9e, 0x2a, 0x4b, 0x16, 0x88, 0x04, 0x00, 0x00, + // 498 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0x3f, 0x6f, 0xd3, 0x40, + 0x14, 0x8f, 0xb1, 0xeb, 0x86, 0x97, 0x02, 0xd1, 0xa9, 0x14, 0xe3, 0xc1, 0xa4, 0x66, 0x49, 0x25, + 0x64, 0x43, 0x99, 0x19, 0x1a, 0x55, 0x0c, 0xa0, 0x48, 0x95, 0xd9, 0x58, 0xa2, 0x8b, 0x7d, 0x72, + 0x02, 0xc9, 0x9d, 0x75, 0x77, 0x0e, 0xe9, 0xb7, 0x60, 0xe7, 0xeb, 0x30, 0x74, 0xec, 0xc8, 0x84, + 0x50, 0xf2, 0x45, 0x90, 0xcf, 0x76, 0x6c, 0x83, 0x52, 0x77, 0xba, 0xf7, 0xde, 0xfd, 0xde, 0xbf, + 0xdf, 0xef, 0x74, 0xe0, 0x2e, 0xf0, 0x0a, 0x53, 0x22, 0xfd, 0xec, 0xf4, 0x45, 0x3a, 0x15, 0x21, + 0x9f, 0x27, 0x72, 0xce, 0xa8, 0x2f, 0xd7, 0x5e, 0xc2, 0x99, 0x64, 0xe8, 0x79, 0x81, 0xf1, 0xb2, + 0xd3, 0xab, 0x63, 0xec, 0x97, 0x8d, 0xf4, 0x84, 0xb3, 0x2f, 0x24, 0x94, 0xa2, 0x34, 0xf2, 0x7c, + 0xfb, 0x38, 0x66, 0x31, 0x53, 0xa6, 0x9f, 0x59, 0x79, 0xd4, 0xfd, 0xa9, 0x81, 0x39, 0x16, 0xf1, + 0x28, 0xbd, 0x46, 0x16, 0x1c, 0x86, 0x9c, 0x60, 0xc9, 0xb8, 0xa5, 0x0d, 0xb4, 0xe1, 0xc3, 0xa0, + 0x74, 0x91, 0x0d, 0xdd, 0x90, 0x51, 0x91, 0x2e, 0x09, 0xb7, 0x1e, 0xa8, 0xab, 0x9d, 0x8f, 0x8e, + 0xe1, 0x60, 0x4e, 0x23, 0xb2, 0xb6, 0x74, 0x75, 0x91, 0x3b, 0x59, 0x46, 0x94, 0x72, 0x9c, 0x4d, + 0x67, 0x19, 0x03, 0x6d, 0x68, 0x04, 0x3b, 0x1f, 0x9d, 0xc2, 0x11, 0x4e, 0x25, 0x9b, 0x70, 0x42, + 0xc9, 0x37, 0xbc, 0xb0, 0xcc, 0x81, 0x36, 0xec, 0x06, 0xbd, 0x2c, 0x16, 0xe4, 0x21, 0x74, 0x06, + 0x7d, 0x1c, 0xad, 0x30, 0x0d, 0xc9, 0x24, 0x49, 0x79, 0x38, 0xc3, 0x82, 0x58, 0x87, 0x0a, 0xf6, + 0xa4, 0x88, 0x5f, 0x15, 0xe1, 0x0f, 0x46, 0xf7, 0xa0, 0x6f, 0xba, 0x7d, 0x78, 0x9c, 0x6f, 0x11, + 0x10, 0x91, 0x30, 0x2a, 0x88, 0xbb, 0x82, 0x47, 0x63, 0x11, 0x5f, 0x44, 0xd1, 0x55, 0xce, 0xc2, + 0x1d, 0xeb, 0x7d, 0x84, 0xa3, 0x82, 0xaa, 0x49, 0x84, 0x25, 0x56, 0x2b, 0xf6, 0xce, 0x5d, 0xaf, + 0x41, 0x78, 0xc9, 0xaa, 0x57, 0xd4, 0xbb, 0xc4, 0x12, 0x8f, 0x8c, 0x9b, 0xdf, 0x2f, 0x3a, 0x41, + 0x2f, 0xa9, 0x42, 0xee, 0x33, 0x78, 0xda, 0xe8, 0xbb, 0x1b, 0xe8, 0x9d, 0x1a, 0xe8, 0x92, 0x2c, + 0xda, 0x07, 0x42, 0x60, 0x50, 0xbc, 0x24, 0x05, 0xd7, 0xca, 0x2e, 0xea, 0x56, 0xe9, 0xbb, 0xba, + 0x52, 0xad, 0x7e, 0x51, 0x63, 0x6f, 0x7f, 0xe1, 0x13, 0x30, 0x09, 0xc5, 0xd3, 0x45, 0x5e, 0xba, + 0x1b, 0x14, 0x5e, 0x43, 0x60, 0x7d, 0x9f, 0xc0, 0x46, 0x4d, 0x60, 0xd7, 0x82, 0x93, 0x66, 0xd7, + 0x72, 0x9e, 0xf3, 0x1f, 0x3a, 0xe8, 0x63, 0x11, 0xa3, 0x4f, 0xa0, 0x67, 0xaf, 0xea, 0xd4, 0xdb, + 0xfb, 0x6e, 0xbd, 0x5c, 0x32, 0xfb, 0xac, 0x15, 0x52, 0x16, 0x47, 0x33, 0x80, 0x9a, 0xa4, 0xc3, + 0xbb, 0x13, 0x2b, 0xa4, 0xfd, 0xfa, 0xbe, 0xc8, 0x7a, 0xa7, 0x9a, 0x56, 0x2d, 0x9d, 0x2a, 0x64, + 0x5b, 0xa7, 0xff, 0x05, 0x44, 0x5f, 0xa1, 0x57, 0x57, 0xaf, 0x85, 0x8d, 0x1a, 0xd4, 0x7e, 0x73, + 0x6f, 0x68, 0xd9, 0x6c, 0xf4, 0xfe, 0x66, 0xe3, 0x68, 0xb7, 0x1b, 0x47, 0xfb, 0xb3, 0x71, 0xb4, + 0xef, 0x5b, 0xa7, 0x73, 0xbb, 0x75, 0x3a, 0xbf, 0xb6, 0x4e, 0xe7, 0xf3, 0xab, 0x78, 0x2e, 0x67, + 0xe9, 0xd4, 0x0b, 0xd9, 0xd2, 0x6f, 0xfc, 0x27, 0xeb, 0x7f, 0x3e, 0xa4, 0xeb, 0x84, 0x88, 0xa9, + 0xa9, 0xbe, 0x8f, 0xb7, 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xf0, 0x95, 0xe6, 0xe6, 0xba, 0x04, + 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -886,6 +903,20 @@ func (m *MsgAutoRenewal) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.Index) > 0 { + i -= len(m.Index) + copy(dAtA[i:], m.Index) + i = encodeVarintTx(dAtA, i, uint64(len(m.Index))) + i-- + dAtA[i] = 0x22 + } + if len(m.Consumer) > 0 { + i -= len(m.Consumer) + copy(dAtA[i:], m.Consumer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Consumer))) + i-- + dAtA[i] = 0x1a + } if m.Enable { i-- if m.Enable { @@ -1042,6 +1073,14 @@ func (m *MsgAutoRenewal) Size() (n int) { if m.Enable { n += 2 } + l = len(m.Consumer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Index) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } return n } @@ -1725,6 +1764,70 @@ func (m *MsgAutoRenewal) Unmarshal(dAtA []byte) error { } } m.Enable = bool(v != 0) + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Consumer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Consumer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Index", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Index = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) diff --git a/x/subscription/types/types.go b/x/subscription/types/types.go index 5dce2d01b0..313b18da30 100644 --- a/x/subscription/types/types.go +++ b/x/subscription/types/types.go @@ -4,6 +4,7 @@ const ( BuySubscriptionEventName = "buy_subscription_event" AdvancedBuySubscriptionEventName = "advanced_buy_subscription_event" AdvancedBuyUpgradeSubscriptionEventName = "advanced_buy_upgrade_subscription_event" + SubscriptionAutoRenewChangeEventName = "subscription_auto_renew_change_event" UpgradeSubscriptionEventName = "upgrade_subscription_event" ExpireSubscriptionEventName = "expire_subscription_event" AddProjectEventName = "add_project_to_subscription_event"