Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
97 commits
Select commit Hold shift + click to select a range
885be00
Fix reset of provider address in rewards and update provider rewards …
faza Jul 23, 2025
28c10c5
Implement cli queries for storage module
faza Jul 23, 2025
924a5ac
Add governance transaction to clawback provider stake
faza Jul 23, 2025
a418de5
No need of this additional set provider
faza Jul 23, 2025
1398dde
Add logs for slashing event
faza Jul 23, 2025
300947d
remove duplicate log
faza Jul 23, 2025
60d6f2d
Implement optimistic concurrency control for all the update transacti…
faza Jul 24, 2025
6fff4cf
Update proto definitions of transactions where state check is require…
faza Jul 25, 2025
c9fdfff
Keep track of previous cid in packfile
faza Jul 25, 2025
f951964
Add storage keeper to gitopia keeper and do state check in branch and…
faza Jul 25, 2025
51ded66
Implement tendermint style provider slashing system
faza Jul 26, 2025
72c44f3
Add qeuries for provider liveness
faza Jul 27, 2025
60c48e3
Fix type of jail_until
faza Jul 28, 2025
dd19fff
Add message definition for unjail provider
faza Jul 28, 2025
513c259
Simplify status type of provider and change the jail logic to happen …
faza Jul 28, 2025
74c501e
Update the active provider condition
faza Jul 28, 2025
9b2295d
Allow active providers to submit challenge response but only reward t…
faza Jul 28, 2025
acc471a
The provider liveness window should only include challenge blocks
faza Jul 28, 2025
97729ef
Fix inactive condition in submit challenge response handler
faza Jul 28, 2025
6109357
Set storage keeper in gitopia keeper properly
faza Jul 28, 2025
5000f09
Remove the ProcessChallengeForLiveness method call inside GenerateCha…
faza Jul 29, 2025
b14b9e7
Fixes in provider liveness tracking
faza Jul 29, 2025
f9a60fc
Remove Reactive provider transaction since Unjail transaction will be…
faza Jul 29, 2025
3b6a72f
Remove unused provider attributes
faza Jul 29, 2025
8d70878
Remove unused param attributes
faza Jul 29, 2025
39bfa80
Add unjail cli command
faza Jul 29, 2025
b1d5229
Add minimum stake requirement check and max providers check in unjail…
faza Jul 29, 2025
784531d
Check provider jail status in message handler and cleanup code
faza Jul 30, 2025
ecbea31
Remove duplicate query
faza Jul 30, 2025
155b149
In the liveness tracking, slash only when minimum liveness requiremen…
faza Jul 30, 2025
59e1327
Fix validation of liveness tracking params
faza Jul 30, 2025
ebbd7a7
Use time duration instead of blocks in jail time configuration in params
faza Jul 30, 2025
c5f7412
Move last liveness check attribute from provider type to provider liv…
faza Jul 30, 2025
2cfbd7a
Propose and approve flow for storage updates
faza Aug 2, 2025
085db78
Implement required queries and event
faza Aug 2, 2025
c181873
Emit events from new message handlers
faza Aug 2, 2025
f000bb2
remove expired storage update proposals
faza Aug 3, 2025
98cd2f1
Add query to filter a single lfs object update request by oid
faza Aug 4, 2025
37ee5a8
No need of task to track merge progress
faza Aug 4, 2025
c127a69
Add state check in merge pull request transaction
faza Aug 4, 2025
8d84be1
Include provider address in storage update approved events
faza Aug 4, 2025
244a9b3
Don't expire the proposals in get methods
faza Aug 4, 2025
2119cca
Don't return when challenge count is zero in EndBlock
faza Aug 4, 2025
3791b60
Fix proposal id validation and increase the expiry
faza Aug 5, 2025
dd401eb
Don't allow creation of proposals when there is a pending proposal fo…
faza Aug 5, 2025
d2004b8
Remove the storage update proposal once it is approved
faza Aug 6, 2025
41e49dd
Add the missing merge commit sha attribute in the packfile update pro…
faza Aug 6, 2025
ff1b2b8
Track the user who initiated the request in the storage proposal
faza Aug 6, 2025
8cb0a85
Add creater field in MsgInvokeDaoMergePullRequest
faza Aug 7, 2025
064f01b
Add creator field in dao create release proposal message
faza Aug 7, 2025
6069272
Handle deletion of release assets in the propose storage update flow …
faza Aug 8, 2025
3e63977
Handle deletion in update repository packfile and lfs proposal
faza Aug 8, 2025
3d77f64
Emit new event EventDeleteStorageObject so that provider can unpin ol…
faza Aug 8, 2025
941c527
Only emit EventDeleteStorageObject event if there is at least a singl…
faza Aug 12, 2025
6cf3ee3
Improve storage events and clean up code
faza Aug 12, 2025
48e8330
Implement MsgProposeRepositoryDelete and MsgApproveRepositoryDelete f…
faza Aug 13, 2025
abb6d2d
Remove failed storage update proposals in all message handlers
faza Aug 13, 2025
29d5377
Add queries for repository delete proposals and expire old proposals …
faza Aug 13, 2025
e7749a1
Emit EventRepositoryDeleted in ApproveRepositoryDelete message handler
faza Aug 13, 2025
6459c3a
Don't send entire packfile, release assets and lfs objects informatio…
faza Aug 13, 2025
72efc66
Include old sha256 attribute in ReleaseAssetUpdate
faza Aug 13, 2025
3305599
Purge the repository from gitopia module only after approve repositor…
faza Aug 13, 2025
8d9855f
Emit new event EventProposalTimeout when storage update proposals tim…
faza Aug 14, 2025
d89c602
Remove creator field from dao merge and release message
faza Aug 16, 2025
8389572
fix initialization of user quota in approve storage update message ha…
faza Aug 16, 2025
b752978
Reset repository archive status when repository delete proposal timeouts
faza Aug 16, 2025
81b206f
Add missing ReleaseAttachments attribute in DaoCreateRelease event
faza Aug 19, 2025
314a2cf
Total submissions in window should be set to window size when sliding…
faza Aug 19, 2025
40ea196
Fix provider liveness ratio calculation
faza Aug 19, 2025
79abd02
No need to initialize provider liveness separately in begin block, it…
faza Aug 19, 2025
964fbec
No need to clean up liveness data
faza Aug 19, 2025
fe8e26d
Use sdk.Dec instead of uint64 for configuring slashing percentages an…
faza Aug 19, 2025
4caeb50
Update slashing logic with the new param changes and clean up unused …
faza Aug 19, 2025
ae8b548
Properly set the liveness info when new window starts
faza Aug 19, 2025
26b257c
Slide the provider liveness window after every challenge
faza Aug 20, 2025
ee76b05
Update liveness type and current liveness ratio calculation
faza Aug 20, 2025
361708f
Add unit test for storage params
faza Aug 20, 2025
4f6ce43
Fix validation of time.Duration fields in storage params
faza Aug 20, 2025
937895c
Handle slashing for proof fault in process challenge timeout
faza Aug 20, 2025
6b36d88
Fix processing of challenge timeouts
faza Aug 20, 2025
96efcec
Add comment regarding correct configuration of challenge interval blo…
faza Aug 20, 2025
2da0b0d
Set minChallengeId to 0 initially
faza Aug 20, 2025
09393c3
wrong proof submission should be tracked as missed challenge
faza Aug 20, 2025
182cd94
Pending status should be checked only in case of assigned provider in…
faza Aug 20, 2025
60735d6
Reset ConsecutiveProofFaults on successful challenge submission by th…
faza Aug 20, 2025
1197f45
Avoid setting the same store key again and again in the same message …
faza Aug 20, 2025
a1f7ab1
Jail the provider correctly in the clawback scenario
faza Aug 20, 2025
6adee77
Configure storage update proposal expiry globally and comment guidelines
faza Aug 20, 2025
97aff61
Keep track of last processed challenge after deadline to avoid proces…
faza Aug 21, 2025
4fb308a
s/GetSize_()/Size_
faza Aug 21, 2025
131e942
Configure storage params for production
faza Aug 21, 2025
b7ddeb1
Update current dollar values in param comments
faza Aug 21, 2025
b269378
Use more standard price per gb param instead of price per mb
faza Aug 21, 2025
09e243f
Update the upgrade time used in storage fee calculation
faza Sep 2, 2025
62fcf70
Remove the test value of minJoinTime in storage reward calculation
faza Sep 2, 2025
7a41d6e
Update changelog
faza Sep 2, 2025
0d074c7
Update storage params
faza Sep 2, 2025
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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

All notable changes will be documented here.

## [6.0.0] - 2025-09-02

- implement storage module to manage storage providers, storage information and storage challenges
- handle race conditions in repository update transactions by including repository state in the transaction
- implement storage update proposal and approval process
- implement charging for storage usage beyond free limit

## [5.1.0] - 2024-11-30

- fix errors in pull request merge messages
Expand Down
5 changes: 5 additions & 0 deletions app/keepers/keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ func NewAppKeeper(
appKeepers.SlashingKeeper,
)

// Initialize GitopiaKeeper with nil StorageKeeper to break circular dependency
appKeepers.GitopiaKeeper = *gitopiakeeper.NewKeeper(
appCodec,
appKeepers.keys[gitopiatypes.StoreKey],
Expand All @@ -365,6 +366,7 @@ func NewAppKeeper(
appKeepers.MintKeeper,
appKeepers.DistrKeeper,
appKeepers.GroupKeeper,
nil, // StorageKeeper will be set later
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)
appKeepers.RewardKeeper = *rewardskeeper.NewKeeper(
Expand All @@ -390,6 +392,9 @@ func NewAppKeeper(
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)

// Set StorageKeeper on GitopiaKeeper to complete the circular dependency resolution
appKeepers.GitopiaKeeper.SetStorageKeeper(appKeepers.StorageKeeper)

return appKeepers
}

Expand Down
39 changes: 39 additions & 0 deletions proto/gitopia/gitopia/gitopia/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ service Msg {
rpc UpdatePullRequestDescription(MsgUpdatePullRequestDescription) returns (MsgUpdatePullRequestDescriptionResponse);
rpc InvokeMergePullRequest(MsgInvokeMergePullRequest) returns (MsgInvokeMergePullRequestResponse);
rpc InvokeDaoMergePullRequest(MsgInvokeDaoMergePullRequest) returns (MsgInvokeDaoMergePullRequestResponse);
rpc MergePullRequest(MsgMergePullRequest) returns (MsgMergePullRequestResponse);
rpc SetPullRequestState(MsgSetPullRequestState) returns (MsgSetPullRequestStateResponse);
rpc AddPullRequestReviewers(MsgAddPullRequestReviewers) returns (MsgAddPullRequestReviewersResponse);
rpc RemovePullRequestReviewers(MsgRemovePullRequestReviewers) returns (MsgRemovePullRequestReviewersResponse);
Expand Down Expand Up @@ -196,6 +197,10 @@ message MsgSetBranch {
string name = 1;
string sha = 2;
}

// cid of repository packfile
// only proceed with the set branch if the current packfile cid matches the expected packfile cid
string packfile_cid = 4;
}

message MsgSetBranchResponse {}
Expand All @@ -216,6 +221,10 @@ message MsgMultiSetBranch {
string name = 1;
string sha = 2;
}

// cid of repository packfile
// only proceed with the set branch if the current packfile cid matches the expected packfile cid
string packfile_cid = 4;
}

message MsgMultiSetBranchResponse { }
Expand Down Expand Up @@ -244,6 +253,10 @@ message MsgSetTag {
string name = 1;
string sha = 2;
}

// cid of repository packfile
// only proceed with the set tag if the current packfile cid matches the expected packfile cid
string packfile_cid = 4;
}

message MsgSetTagResponse { }
Expand All @@ -256,6 +269,10 @@ message MsgMultiSetTag {
string name = 1;
string sha = 2;
}

// cid of repository packfile
// only proceed with the set tag if the current packfile cid matches the expected packfile cid
string packfile_cid = 4;
}

message MsgMultiSetTagResponse { }
Expand Down Expand Up @@ -397,6 +414,10 @@ message MsgInvokeMergePullRequest {
uint64 repositoryId = 2;
uint64 iid = 3;
string provider = 4;

// commit sha of base branch
// only proceed with the merge if the current commit sha matches the expected commit sha
string base_commit_sha = 5;
}

message MsgInvokeMergePullRequestResponse { }
Expand All @@ -410,10 +431,28 @@ message MsgInvokeDaoMergePullRequest {
uint64 repositoryId = 2;
uint64 iid = 3;
string provider = 4;

// commit sha of base branch
// only proceed with the merge if the current commit sha matches the expected commit sha
string base_commit_sha = 5;
}

message MsgInvokeDaoMergePullRequestResponse { }

// MsgMergePullRequest defines a message for completing a pull request merge
message MsgMergePullRequest {
string creator = 1;
uint64 repository_id = 2;
uint64 pull_request_iid = 3;
string merge_commit_sha = 4;

// cid of repository packfile
// only proceed with the merge if the current packfile cid matches the expected packfile cid
string packfile_cid = 5;
}

message MsgMergePullRequestResponse {}

message MsgSetPullRequestState {
string creator = 1;
uint64 repositoryId = 2;
Expand Down
90 changes: 43 additions & 47 deletions proto/gitopia/gitopia/storage/events.proto
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import "google/protobuf/timestamp.proto";
import "gogoproto/gogo.proto";
import "cosmos/base/v1beta1/coin.proto";
import "amino/amino.proto";
import "gitopia/gitopia/storage/types.proto";

option go_package = "github.com/gitopia/gitopia/v6/x/storage/types";

Expand All @@ -27,33 +28,16 @@ message EventPackfileUpdated {
string old_cid = 3;
string new_name = 4;
string old_name = 5;
string provider = 6;
bool deleted = 7;
}

// EventPackfileDeleted is emitted when a packfile is deleted
message EventPackfileDeleted {
uint64 repository_id = 1;
string name = 2;
string cid = 3;
}

// EventReleaseAssetUpdated is emitted when a release asset is updated
message EventReleaseAssetUpdated {
// EventReleaseAssetsUpdated is emitted when release assets are updated
message EventReleaseAssetsUpdated {
uint64 repository_id = 1;
string tag = 2;
string name = 3;
string new_cid = 4;
string old_cid = 5;
string new_sha256 = 6;
string old_sha256 = 7;
}

// EventReleaseAssetDeleted is emitted when a release asset is deleted
message EventReleaseAssetDeleted {
uint64 repository_id = 1;
string tag = 2;
string name = 3;
string cid = 4;
string sha256 = 5;
repeated ReleaseAssetUpdate assets = 3;
string provider = 4;
}

// EventChallengeCreated is emitted when a new challenge is created
Expand Down Expand Up @@ -88,36 +72,48 @@ message EventProviderUnstakeCompleted {
];
}

// EventMergePullRequest is emitted when a pull request is merged
message EventMergePullRequest {
string creator = 1;
uint64 pull_request_id = 2;
uint64 pull_request_iid = 3;
string state = 4;
string merge_commit_sha = 5;
uint64 task_id = 6;
string task_state = 7;
string repo_name = 8;
uint64 repo_id = 9;
string repo_owner_id = 10;
string repo_owner_type = 11;
string pull_request_head = 14;
string repo_branch = 15;
string merged_by = 16;
int64 updated_at = 17;
int64 merged_at = 18;
}

// EventLFSObjectUpdated is emitted when an LFS object is updated
message EventLFSObjectUpdated {
uint64 repository_id = 1;
string oid = 2;
string cid = 3;
string provider = 4;
bool deleted = 5;
}

// EventLFSObjectDeleted is emitted when an LFS object is deleted
message EventLFSObjectDeleted {
// EventDeleteStorageObject is emitted when older storage objects are deleted
message EventDeleteStorageObject {
repeated string cids = 1;
uint64 repository_id = 2;
string provider = 3;
}

// EventRepositoryDeleted is emitted when a repository is deleted
message EventRepositoryDeleted {
uint64 repository_id = 1;
string oid = 2;
string cid = 3;
string provider = 2;
string packfile_cid = 3;
string packfile_name = 4;
repeated ReleaseAssetInfo release_assets = 5;
repeated LFSObjectInfo lfs_objects = 6;
}

// EventProposalTimeout is emitted when a storage update proposal times out
message EventProposalTimeout {
string provider = 1;
repeated string cids = 2;
}

// ReleaseAssetInfo contains minimal information about a release asset
message ReleaseAssetInfo {
string name = 1;
string cid = 2;
string sha256 = 3;
string tag = 4;
}

// LFSObjectInfo contains minimal information about an LFS object
message LFSObjectInfo {
string oid = 1;
string cid = 2;
}
49 changes: 40 additions & 9 deletions proto/gitopia/gitopia/storage/params.proto
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package gitopia.gitopia.storage;
import "gogoproto/gogo.proto";
import "cosmos/base/v1beta1/coin.proto";
import "google/protobuf/duration.proto";
import "amino/amino.proto";

option go_package = "github.com/gitopia/gitopia/v6/x/storage/types";

Expand All @@ -13,18 +14,48 @@ message Params {

uint64 min_stake_amount = 1 [(gogoproto.moretags) = "yaml:\"min_stake_amount\""];
uint64 challenge_interval_blocks = 2 [(gogoproto.moretags) = "yaml:\"challenge_interval_blocks\""];
google.protobuf.Duration challenge_period = 3 [(gogoproto.stdduration) = true, (gogoproto.moretags) = "yaml:\"challenge_period\""];
google.protobuf.Duration challenge_period = 3 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true, (gogoproto.moretags) = "yaml:\"challenge_period\""];
cosmos.base.v1beta1.Coin reward_per_day = 4 [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"reward_per_day\""];
cosmos.base.v1beta1.Coin challenge_slash_amount = 5 [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"challenge_slash_amount\""];
uint64 consecutive_fails_threshold = 6 [(gogoproto.moretags) = "yaml:\"consecutive_fails_threshold\""];
uint64 consecutive_fails_slash_percentage = 7 [(gogoproto.moretags) = "yaml:\"consecutive_fails_slash_percentage\""];
uint64 unstake_cooldown_blocks = 8 [(gogoproto.moretags) = "yaml:\"unstake_cooldown_blocks\""];
uint64 unstake_cooldown_blocks = 5 [(gogoproto.moretags) = "yaml:\"unstake_cooldown_blocks\""];

// cost per MB of storage
cosmos.base.v1beta1.Coin storage_price_per_mb = 9 [(gogoproto.nullable) = false];
// cost per GB of storage
cosmos.base.v1beta1.Coin storage_price_per_gb = 6 [(gogoproto.nullable) = false];
// free storage in MB
uint64 free_storage_mb = 10 [(gogoproto.moretags) = "yaml:\"free_storage_mb\""];
uint64 free_storage_mb = 7 [(gogoproto.moretags) = "yaml:\"free_storage_mb\""];

// max providers
uint64 max_providers = 11 [(gogoproto.moretags) = "yaml:\"max_providers\""];
uint64 max_providers = 8 [(gogoproto.moretags) = "yaml:\"max_providers\""];

// Liveness tracking parameters
// Number of challenges to track for liveness calculation (sliding window)
uint64 liveness_window_challenges = 9 [(gogoproto.moretags) = "yaml:\"liveness_window_challenges\""];
// Minimum liveness ratio required (e.g., 67 = 67%)
bytes min_liveness_per_window = 10 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false,
(amino.dont_omitempty) = true
];

// Liveness fault slashing parameters (less severe)
cosmos.base.v1beta1.Coin liveness_slash_amount = 11 [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"liveness_slash_amount\""];
bytes liveness_slash_fraction = 12 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false,
(amino.dont_omitempty) = true,
(gogoproto.moretags) = "yaml:\"liveness_slash_fraction\""
];
google.protobuf.Duration liveness_jail_time = 13 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true, (gogoproto.moretags) = "yaml:\"liveness_jail_time\""];

// Proof fault slashing parameters (more severe for assigned provider)
cosmos.base.v1beta1.Coin proof_fault_slash_amount = 14 [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"proof_fault_slash_amount\""];
bytes proof_fault_slash_fraction = 15 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false,
(amino.dont_omitempty) = true,
(gogoproto.moretags) = "yaml:\"proof_fault_slash_fraction\""
];
google.protobuf.Duration proof_fault_jail_time = 16 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true, (gogoproto.moretags) = "yaml:\"proof_fault_jail_time\""];

// Maximum number of consecutive proof faults before suspension
uint64 max_proof_faults = 17 [(gogoproto.moretags) = "yaml:\"max_proof_faults\""];
}
Loading
Loading