Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions proto/pocket/application/event.proto
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,41 @@ message EventApplicationUnbondingEnd {
int64 unbonding_end_height = 4 [(gogoproto.jsontag) = "unbonding_height"];
}

// EventApplicationStakeStuckInModulePool is emitted when EndBlockerUnbondApplications
// (via UnbondApplication) could NOT return the application's escrowed stake to its
// owner account (e.g., a blocked module account, the bank module rejected the send).
// The application is removed from state anyway to keep the chain making progress,
// but the coins remain stranded in the application module pool. Indexers should
// track these events so governance can propose a reclaim transfer; without this
// event the loss would be invisible to off-chain observers.
//
// Mirror of EventSupplierStakeStuckInModulePool (see pocket/supplier/event.proto).
// Before v0.1.34 the application path returned the bank-send error from
// EndBlockerUnbondApplications, which halts the chain when a legacy
// module-account-owned application exists. This event replaces that halt vector
// with an indexer-visible signal + continue, matching the supplier-side fix.
//
// Expected occurrences on a healthy mainnet: zero. Non-zero count post-upgrade
// indicates pre-existing legacy state (module-account-owned applications); the
// new stake-time module-account-owner check blocks NEW occurrences.
message EventApplicationStakeStuckInModulePool {
// application_address identifies the removed application.
string application_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];

// stuck_coin is the coin that remains in the application module pool with no
// owner to claim it.
cosmos.base.v1beta1.Coin stuck_coin = 2 [(gogoproto.jsontag) = "stuck_coin"];

// reason is the bank-module error string captured at the time of the failed
// send. Free-form, intended for human triage.
string reason = 3 [(gogoproto.jsontag) = "reason"];

// session_end_height is the session-end height of the EndBlocker that
// attempted (and failed) the return-of-stake. Useful for correlating with
// settlement events in the same block.
int64 session_end_height = 4 [(gogoproto.jsontag) = "session_end_height"];
}

// EventApplicationUnbondingCanceled is emitted when an application which was unbonding
// successfully (re-)stakes before the unbonding period has elapsed. An EventApplicationStaked
// event will also be emitted immediately after this event.
Expand Down
4 changes: 4 additions & 0 deletions proto/pocket/application/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ message MsgStakeApplication {
cosmos.base.v1beta1.Coin stake = 2; // The total amount of uPOKT the application has staked. Must be ≥ to the current amount that the application has staked (if any)
repeated pocket.shared.ApplicationServiceConfig services = 3; // The list of services this application is staked to request service for

// Optional per-session spend limit in uPOKT.
// Three-way semantics: nil/omitted = preserve existing limit, zero = clear limit, positive = set new limit.
cosmos.base.v1beta1.Coin per_session_spend_limit = 4;

// TODO_POST_MAINNET: Consider allowing applications to delegate
// to gateways at time of staking for a better developer experience.
// repeated string gateway_address
Expand Down
35 changes: 35 additions & 0 deletions proto/pocket/application/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,41 @@ message Application {

// Information about pending application transfers
PendingApplicationTransfer pending_transfer = 7;

// Optional per-session spend limit in uPOKT. When set, caps the maximum
// amount of stake consumed per session. Nil = no limit (default).
cosmos.base.v1beta1.Coin per_session_spend_limit = 8;

// List of historical service configuration updates, tracking the application's
// service config changes and their corresponding activation heights.
//
// Mirrors the supplier `service_config_history` pattern to support
// deterministic historical session queries (GetSession at a past height must
// return the service config that was active at that height, not the latest).
//
// This history is NOT pruned: applications are orders of magnitude fewer than
// supplier service rows, so the storage cost is negligible, and keeping it
// forever avoids the pruning-induced historical-query non-determinism observed
// on the supplier side (see session_mutation_analysis).
repeated ApplicationServiceConfigUpdate service_config_history = 9;
}

// ApplicationServiceConfigUpdate tracks a change in an application's service
// configuration at a specific block height, enabling deterministic
// reconstruction of which service an application was staked for at any height.
message ApplicationServiceConfigUpdate {
// Address of the application corresponding to the service configuration change
string application_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];

// The specific service configuration that was added or scheduled for removal
pocket.shared.ApplicationServiceConfig service = 2;

// Block height at which this service configuration became active in the network
int64 activation_height = 3;

// Block height at which this service configuration was deactivated (0 if still active).
// For configs scheduled for deactivation, this stores the height when deactivation occurs.
int64 deactivation_height = 4;
}

// UndelegatingGatewayList is used as the Value of `pending_undelegations`.
Expand Down
36 changes: 32 additions & 4 deletions proto/pocket/proof/event.proto
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import "gogoproto/gogo.proto";
import "pocket/proof/types.proto";

message EventClaimCreated {
// Next index: 13
// Next index: 14

// pocket.proof.Claim claim = 1 [(gogoproto.jsontag) = "claim"];
// cosmos.base.v1beta1.Coin claimed_upokt = 6 [(gogoproto.jsontag) = "claimed_upokt"];
Expand Down Expand Up @@ -42,11 +42,18 @@ message EventClaimCreated {

// The operator address of the supplier which submitted the claim.
string supplier_operator_address = 12 [(cosmos_proto.scalar) = "cosmos.AddressString"];

// The probabilistic estimate of the total number of relays served this session.
// num_estimated_relays = num_estimated_compute_units / compute_units_per_relay.
// Mirrors EventClaimSettled.num_estimated_relays so indexers do not have to
// re-derive it; the off-chain derivation divides by num_relays and breaks when
// num_relays == 0 (e.g. empty claims), which this field avoids.
uint64 num_estimated_relays = 13 [(gogoproto.jsontag) = "num_estimated_relays"];
}

// TODO_TEST: Add coverage for claim updates.
message EventClaimUpdated {
// Next index: 13
// Next index: 14

// pocket.proof.Claim claim = 1 [(gogoproto.jsontag) = "claim"];
// cosmos.base.v1beta1.Coin claimed_upokt = 6 [(gogoproto.jsontag) = "claimed_upokt"];
Expand Down Expand Up @@ -79,10 +86,17 @@ message EventClaimUpdated {

// The operator address of the supplier which updated the claim.
string supplier_operator_address = 12 [(cosmos_proto.scalar) = "cosmos.AddressString"];

// The probabilistic estimate of the total number of relays served this session.
// num_estimated_relays = num_estimated_compute_units / compute_units_per_relay.
// Mirrors EventClaimSettled.num_estimated_relays so indexers do not have to
// re-derive it; the off-chain derivation divides by num_relays and breaks when
// num_relays == 0 (e.g. empty claims), which this field avoids.
uint64 num_estimated_relays = 13 [(gogoproto.jsontag) = "num_estimated_relays"];
}

message EventProofSubmitted {
// Next index: 13
// Next index: 14

// pocket.proof.Claim claim = 1 [(gogoproto.jsontag) = "claim"];
// cosmos.base.v1beta1.Coin claimed_upokt = 6 [(gogoproto.jsontag) = "claimed_upokt"];
Expand Down Expand Up @@ -115,11 +129,18 @@ message EventProofSubmitted {

// The operator address of the supplier which submitted the proof.
string supplier_operator_address = 12 [(cosmos_proto.scalar) = "cosmos.AddressString"];

// The probabilistic estimate of the total number of relays served this session.
// num_estimated_relays = num_estimated_compute_units / compute_units_per_relay.
// Mirrors EventClaimSettled.num_estimated_relays so indexers do not have to
// re-derive it; the off-chain derivation divides by num_relays and breaks when
// num_relays == 0 (e.g. empty claims), which this field avoids.
uint64 num_estimated_relays = 13 [(gogoproto.jsontag) = "num_estimated_relays"];
}

// TODO_TEST: Add coverage for proof updates.
message EventProofUpdated {
// Next index: 13
// Next index: 14

// pocket.proof.Claim claim = 1 [(gogoproto.jsontag) = "claim"];
// cosmos.base.v1beta1.Coin claimed_upokt = 6 [(gogoproto.jsontag) = "claimed_upokt"];
Expand Down Expand Up @@ -152,6 +173,13 @@ message EventProofUpdated {

// The operator address of the supplier which updated the proof.
string supplier_operator_address = 12 [(cosmos_proto.scalar) = "cosmos.AddressString"];

// The probabilistic estimate of the total number of relays served this session.
// num_estimated_relays = num_estimated_compute_units / compute_units_per_relay.
// Mirrors EventClaimSettled.num_estimated_relays so indexers do not have to
// re-derive it; the off-chain derivation divides by num_relays and breaks when
// num_relays == 0 (e.g. empty claims), which this field avoids.
uint64 num_estimated_relays = 13 [(gogoproto.jsontag) = "num_estimated_relays"];
}

// Event emitted after a proof has been checked for validity in the proof module's
Expand Down
15 changes: 14 additions & 1 deletion proto/pocket/service/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ service Msg {
// parameters. The authority defaults to the x/gov module account.
rpc UpdateParams (MsgUpdateParams) returns (MsgUpdateParamsResponse);
rpc UpdateParam (MsgUpdateParam ) returns (MsgUpdateParamResponse );
rpc AddService (MsgAddService ) returns (MsgAddServiceResponse );
rpc AddService (MsgAddService ) returns (MsgAddServiceResponse );
rpc TransferService (MsgTransferService ) returns (MsgTransferServiceResponse );
}
// MsgUpdateParams is the Msg/UpdateParams request type.
message MsgUpdateParams {
Expand Down Expand Up @@ -78,3 +79,15 @@ message MsgAddServiceResponse {
// pocket.shared.Service service = 1;
reserved 1;
}

// MsgTransferService transfers ownership of a service to a new address.
// Only the current owner can initiate the transfer.
message MsgTransferService {
option (cosmos.msg.v1.signer) = "owner_address";
string owner_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; // The Bech32 address of the current service owner (signer).
string service_id = 2; // The unique identifier of the service to transfer.
string new_owner_address = 3 [(cosmos_proto.scalar) = "cosmos.AddressString"]; // The Bech32 address of the new service owner.
}

// MsgTransferServiceResponse is the response to a MsgTransferService message.
message MsgTransferServiceResponse {}
2 changes: 2 additions & 0 deletions proto/pocket/session/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ import "pocket/session/params.proto";
message GenesisState {
// params defines all the parameters of the module.
Params params = 1 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true];
// params_history contains historical params snapshots for height-based lookups.
repeated ParamsUpdate params_history = 2 [(gogoproto.nullable) = false];
}
2 changes: 2 additions & 0 deletions proto/pocket/shared/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@ message GenesisState {
(gogoproto.nullable) = false,
(amino.dont_omitempty) = true
];
// params_history contains historical params snapshots for height-based lookups.
repeated ParamsUpdate params_history = 2 [(gogoproto.nullable) = false];
}
16 changes: 15 additions & 1 deletion proto/pocket/shared/params.proto
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,20 @@ message Params {
// ongoing sessions. This prevents sessions from settling using parameters that
// were not in effect during their creation.
uint64 compute_unit_cost_granularity = 11 [(gogoproto.jsontag) = "compute_unit_cost_granularity", (gogoproto.moretags) = "yaml:\"compute_unit_cost_granularity\""];

// session_grid_anchor_height is the block height at which this params epoch's session
// grid begins. Boundary math is computed relative to this anchor instead of block 1, so
// that changing num_blocks_per_session does not misalign in-flight sessions (#543).
// DERIVED metadata, NOT governable: set by the param-update handler to the next session
// boundary; any value supplied via governance is ignored/overwritten. A zero value falls
// back to the genesis block-1 grid (legacy behavior).
uint64 session_grid_anchor_height = 12 [(gogoproto.jsontag) = "session_grid_anchor_height"];

// session_number_at_anchor is the session number of the session starting at
// session_grid_anchor_height. Used to keep GetSessionNumber monotonic across epochs
// (epoch-relative numbering would otherwise reset at each change).
// DERIVED metadata, NOT governable.
uint64 session_number_at_anchor = 13 [(gogoproto.jsontag) = "session_number_at_anchor"];
}

// ParamsUpdate stores a snapshot of shared parameters
Expand All @@ -95,4 +109,4 @@ message ParamsUpdate {

// params is the snapshot of shared params that were effective starting at effective_height.
Params params = 2 [(gogoproto.jsontag) = "params"];
}
}
23 changes: 23 additions & 0 deletions proto/pocket/shared/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ service Query {
rpc Params(QueryParamsRequest) returns (QueryParamsResponse) {
option (google.api.http).get = "/pokt-network/poktroll/shared/params";
}

// ParamsAtHeight queries the shared parameters that were effective at a given block
// height. Used by off-chain clients (e.g. the RelayMiner) to compute a session's
// claim/proof windows using the num_blocks_per_session that was in effect when that
// session started, rather than the live value — see the anchored session grid (#543).
rpc ParamsAtHeight(QueryParamsAtHeightRequest) returns (QueryParamsAtHeightResponse) {
option (google.api.http).get = "/pokt-network/poktroll/shared/params/{height}";
}
}

// QueryParamsRequest is request type for the Query/Params RPC method.
Expand All @@ -29,3 +37,18 @@ message QueryParamsResponse {
(amino.dont_omitempty) = true
];
}

// QueryParamsAtHeightRequest is request type for the Query/ParamsAtHeight RPC method.
message QueryParamsAtHeightRequest {
// height is the block height at which to look up the effective shared params.
int64 height = 1;
}

// QueryParamsAtHeightResponse is response type for the Query/ParamsAtHeight RPC method.
message QueryParamsAtHeightResponse {
// params holds the shared parameters that were effective at the requested height.
Params params = 1 [
(gogoproto.nullable) = false,
(amino.dont_omitempty) = true
];
}
33 changes: 33 additions & 0 deletions proto/pocket/supplier/event.proto
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,39 @@ message EventSupplierUnbondingCanceled {
int64 session_end_height = 2 [(gogoproto.jsontag) = "session_end_height"];
}

// EventSupplierStakeStuckInModulePool is emitted when EndBlockerUnbondSuppliers
// could NOT return the supplier's bonded stake to its owner account (e.g., the
// owner is a blocked module account, the bank module rejected the send). The
// supplier is removed from state anyway to keep the chain making progress, but
// the coins remain stranded in the supplier module pool. Indexers should track
// these events so governance can propose a reclaim transfer; without this event
// the loss would be invisible to off-chain observers.
//
// Pre-v0.1.34 the same scenario only produced a Logger().Error line — easy to
// miss in operator workflows. The new stake-time module-account-owner check
// prevents NEW occurrences, so this event should fire only for legacy state.
message EventSupplierStakeStuckInModulePool {
// operator_address identifies the removed supplier.
string operator_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];

// owner_address is the address the bank module refused to send to. Either a
// blocked module account or an otherwise rejected recipient.
string owner_address = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"];

// stuck_coin is the coin that remains in the supplier module pool with no
// owner to claim it.
cosmos.base.v1beta1.Coin stuck_coin = 3 [(gogoproto.jsontag) = "stuck_coin"];

// reason is the bank-module error string captured at the time of the failed
// send. Free-form, intended for human triage.
string reason = 4 [(gogoproto.jsontag) = "reason"];

// session_end_height is the session-end height of the EndBlocker that
// attempted (and failed) the return-of-stake. Useful for correlating with
// settlement events in the same block.
int64 session_end_height = 5 [(gogoproto.jsontag) = "session_end_height"];
}

// EventSupplierServiceConfigActivated is emitted when a supplier service configuration
// becomes effective at a specific block height.
message EventSupplierServiceConfigActivated {
Expand Down
Loading
Loading