Skip to content

Commit d3d8d4d

Browse files
authored
Merge pull request #17 from gitopia/release-v6
Improved slashing mechanics and other improvements in the storage module
2 parents 76c7e31 + 0d074c7 commit d3d8d4d

56 files changed

Lines changed: 31506 additions & 12727 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22

33
All notable changes will be documented here.
44

5+
## [6.0.0] - 2025-09-02
6+
7+
- implement storage module to manage storage providers, storage information and storage challenges
8+
- handle race conditions in repository update transactions by including repository state in the transaction
9+
- implement storage update proposal and approval process
10+
- implement charging for storage usage beyond free limit
11+
512
## [5.1.0] - 2024-11-30
613

714
- fix errors in pull request merge messages

app/keepers/keepers.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,7 @@ func NewAppKeeper(
353353
appKeepers.SlashingKeeper,
354354
)
355355

356+
// Initialize GitopiaKeeper with nil StorageKeeper to break circular dependency
356357
appKeepers.GitopiaKeeper = *gitopiakeeper.NewKeeper(
357358
appCodec,
358359
appKeepers.keys[gitopiatypes.StoreKey],
@@ -365,6 +366,7 @@ func NewAppKeeper(
365366
appKeepers.MintKeeper,
366367
appKeepers.DistrKeeper,
367368
appKeepers.GroupKeeper,
369+
nil, // StorageKeeper will be set later
368370
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
369371
)
370372
appKeepers.RewardKeeper = *rewardskeeper.NewKeeper(
@@ -390,6 +392,9 @@ func NewAppKeeper(
390392
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
391393
)
392394

395+
// Set StorageKeeper on GitopiaKeeper to complete the circular dependency resolution
396+
appKeepers.GitopiaKeeper.SetStorageKeeper(appKeepers.StorageKeeper)
397+
393398
return appKeepers
394399
}
395400

proto/gitopia/gitopia/gitopia/tx.proto

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ service Msg {
5454
rpc UpdatePullRequestDescription(MsgUpdatePullRequestDescription) returns (MsgUpdatePullRequestDescriptionResponse);
5555
rpc InvokeMergePullRequest(MsgInvokeMergePullRequest) returns (MsgInvokeMergePullRequestResponse);
5656
rpc InvokeDaoMergePullRequest(MsgInvokeDaoMergePullRequest) returns (MsgInvokeDaoMergePullRequestResponse);
57+
rpc MergePullRequest(MsgMergePullRequest) returns (MsgMergePullRequestResponse);
5758
rpc SetPullRequestState(MsgSetPullRequestState) returns (MsgSetPullRequestStateResponse);
5859
rpc AddPullRequestReviewers(MsgAddPullRequestReviewers) returns (MsgAddPullRequestReviewersResponse);
5960
rpc RemovePullRequestReviewers(MsgRemovePullRequestReviewers) returns (MsgRemovePullRequestReviewersResponse);
@@ -196,6 +197,10 @@ message MsgSetBranch {
196197
string name = 1;
197198
string sha = 2;
198199
}
200+
201+
// cid of repository packfile
202+
// only proceed with the set branch if the current packfile cid matches the expected packfile cid
203+
string packfile_cid = 4;
199204
}
200205

201206
message MsgSetBranchResponse {}
@@ -216,6 +221,10 @@ message MsgMultiSetBranch {
216221
string name = 1;
217222
string sha = 2;
218223
}
224+
225+
// cid of repository packfile
226+
// only proceed with the set branch if the current packfile cid matches the expected packfile cid
227+
string packfile_cid = 4;
219228
}
220229

221230
message MsgMultiSetBranchResponse { }
@@ -244,6 +253,10 @@ message MsgSetTag {
244253
string name = 1;
245254
string sha = 2;
246255
}
256+
257+
// cid of repository packfile
258+
// only proceed with the set tag if the current packfile cid matches the expected packfile cid
259+
string packfile_cid = 4;
247260
}
248261

249262
message MsgSetTagResponse { }
@@ -256,6 +269,10 @@ message MsgMultiSetTag {
256269
string name = 1;
257270
string sha = 2;
258271
}
272+
273+
// cid of repository packfile
274+
// only proceed with the set tag if the current packfile cid matches the expected packfile cid
275+
string packfile_cid = 4;
259276
}
260277

261278
message MsgMultiSetTagResponse { }
@@ -397,6 +414,10 @@ message MsgInvokeMergePullRequest {
397414
uint64 repositoryId = 2;
398415
uint64 iid = 3;
399416
string provider = 4;
417+
418+
// commit sha of base branch
419+
// only proceed with the merge if the current commit sha matches the expected commit sha
420+
string base_commit_sha = 5;
400421
}
401422

402423
message MsgInvokeMergePullRequestResponse { }
@@ -410,10 +431,28 @@ message MsgInvokeDaoMergePullRequest {
410431
uint64 repositoryId = 2;
411432
uint64 iid = 3;
412433
string provider = 4;
434+
435+
// commit sha of base branch
436+
// only proceed with the merge if the current commit sha matches the expected commit sha
437+
string base_commit_sha = 5;
413438
}
414439

415440
message MsgInvokeDaoMergePullRequestResponse { }
416441

442+
// MsgMergePullRequest defines a message for completing a pull request merge
443+
message MsgMergePullRequest {
444+
string creator = 1;
445+
uint64 repository_id = 2;
446+
uint64 pull_request_iid = 3;
447+
string merge_commit_sha = 4;
448+
449+
// cid of repository packfile
450+
// only proceed with the merge if the current packfile cid matches the expected packfile cid
451+
string packfile_cid = 5;
452+
}
453+
454+
message MsgMergePullRequestResponse {}
455+
417456
message MsgSetPullRequestState {
418457
string creator = 1;
419458
uint64 repositoryId = 2;

proto/gitopia/gitopia/storage/events.proto

Lines changed: 43 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import "google/protobuf/timestamp.proto";
55
import "gogoproto/gogo.proto";
66
import "cosmos/base/v1beta1/coin.proto";
77
import "amino/amino.proto";
8+
import "gitopia/gitopia/storage/types.proto";
89

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

@@ -27,33 +28,16 @@ message EventPackfileUpdated {
2728
string old_cid = 3;
2829
string new_name = 4;
2930
string old_name = 5;
31+
string provider = 6;
32+
bool deleted = 7;
3033
}
3134

32-
// EventPackfileDeleted is emitted when a packfile is deleted
33-
message EventPackfileDeleted {
34-
uint64 repository_id = 1;
35-
string name = 2;
36-
string cid = 3;
37-
}
38-
39-
// EventReleaseAssetUpdated is emitted when a release asset is updated
40-
message EventReleaseAssetUpdated {
35+
// EventReleaseAssetsUpdated is emitted when release assets are updated
36+
message EventReleaseAssetsUpdated {
4137
uint64 repository_id = 1;
4238
string tag = 2;
43-
string name = 3;
44-
string new_cid = 4;
45-
string old_cid = 5;
46-
string new_sha256 = 6;
47-
string old_sha256 = 7;
48-
}
49-
50-
// EventReleaseAssetDeleted is emitted when a release asset is deleted
51-
message EventReleaseAssetDeleted {
52-
uint64 repository_id = 1;
53-
string tag = 2;
54-
string name = 3;
55-
string cid = 4;
56-
string sha256 = 5;
39+
repeated ReleaseAssetUpdate assets = 3;
40+
string provider = 4;
5741
}
5842

5943
// EventChallengeCreated is emitted when a new challenge is created
@@ -88,36 +72,48 @@ message EventProviderUnstakeCompleted {
8872
];
8973
}
9074

91-
// EventMergePullRequest is emitted when a pull request is merged
92-
message EventMergePullRequest {
93-
string creator = 1;
94-
uint64 pull_request_id = 2;
95-
uint64 pull_request_iid = 3;
96-
string state = 4;
97-
string merge_commit_sha = 5;
98-
uint64 task_id = 6;
99-
string task_state = 7;
100-
string repo_name = 8;
101-
uint64 repo_id = 9;
102-
string repo_owner_id = 10;
103-
string repo_owner_type = 11;
104-
string pull_request_head = 14;
105-
string repo_branch = 15;
106-
string merged_by = 16;
107-
int64 updated_at = 17;
108-
int64 merged_at = 18;
109-
}
110-
11175
// EventLFSObjectUpdated is emitted when an LFS object is updated
11276
message EventLFSObjectUpdated {
11377
uint64 repository_id = 1;
11478
string oid = 2;
11579
string cid = 3;
80+
string provider = 4;
81+
bool deleted = 5;
11682
}
11783

118-
// EventLFSObjectDeleted is emitted when an LFS object is deleted
119-
message EventLFSObjectDeleted {
84+
// EventDeleteStorageObject is emitted when older storage objects are deleted
85+
message EventDeleteStorageObject {
86+
repeated string cids = 1;
87+
uint64 repository_id = 2;
88+
string provider = 3;
89+
}
90+
91+
// EventRepositoryDeleted is emitted when a repository is deleted
92+
message EventRepositoryDeleted {
12093
uint64 repository_id = 1;
121-
string oid = 2;
122-
string cid = 3;
94+
string provider = 2;
95+
string packfile_cid = 3;
96+
string packfile_name = 4;
97+
repeated ReleaseAssetInfo release_assets = 5;
98+
repeated LFSObjectInfo lfs_objects = 6;
99+
}
100+
101+
// EventProposalTimeout is emitted when a storage update proposal times out
102+
message EventProposalTimeout {
103+
string provider = 1;
104+
repeated string cids = 2;
105+
}
106+
107+
// ReleaseAssetInfo contains minimal information about a release asset
108+
message ReleaseAssetInfo {
109+
string name = 1;
110+
string cid = 2;
111+
string sha256 = 3;
112+
string tag = 4;
113+
}
114+
115+
// LFSObjectInfo contains minimal information about an LFS object
116+
message LFSObjectInfo {
117+
string oid = 1;
118+
string cid = 2;
123119
}

proto/gitopia/gitopia/storage/params.proto

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package gitopia.gitopia.storage;
44
import "gogoproto/gogo.proto";
55
import "cosmos/base/v1beta1/coin.proto";
66
import "google/protobuf/duration.proto";
7+
import "amino/amino.proto";
78

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

@@ -13,18 +14,48 @@ message Params {
1314

1415
uint64 min_stake_amount = 1 [(gogoproto.moretags) = "yaml:\"min_stake_amount\""];
1516
uint64 challenge_interval_blocks = 2 [(gogoproto.moretags) = "yaml:\"challenge_interval_blocks\""];
16-
google.protobuf.Duration challenge_period = 3 [(gogoproto.stdduration) = true, (gogoproto.moretags) = "yaml:\"challenge_period\""];
17+
google.protobuf.Duration challenge_period = 3 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true, (gogoproto.moretags) = "yaml:\"challenge_period\""];
1718
cosmos.base.v1beta1.Coin reward_per_day = 4 [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"reward_per_day\""];
18-
cosmos.base.v1beta1.Coin challenge_slash_amount = 5 [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"challenge_slash_amount\""];
19-
uint64 consecutive_fails_threshold = 6 [(gogoproto.moretags) = "yaml:\"consecutive_fails_threshold\""];
20-
uint64 consecutive_fails_slash_percentage = 7 [(gogoproto.moretags) = "yaml:\"consecutive_fails_slash_percentage\""];
21-
uint64 unstake_cooldown_blocks = 8 [(gogoproto.moretags) = "yaml:\"unstake_cooldown_blocks\""];
19+
uint64 unstake_cooldown_blocks = 5 [(gogoproto.moretags) = "yaml:\"unstake_cooldown_blocks\""];
2220

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

2826
// max providers
29-
uint64 max_providers = 11 [(gogoproto.moretags) = "yaml:\"max_providers\""];
27+
uint64 max_providers = 8 [(gogoproto.moretags) = "yaml:\"max_providers\""];
28+
29+
// Liveness tracking parameters
30+
// Number of challenges to track for liveness calculation (sliding window)
31+
uint64 liveness_window_challenges = 9 [(gogoproto.moretags) = "yaml:\"liveness_window_challenges\""];
32+
// Minimum liveness ratio required (e.g., 67 = 67%)
33+
bytes min_liveness_per_window = 10 [
34+
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
35+
(gogoproto.nullable) = false,
36+
(amino.dont_omitempty) = true
37+
];
38+
39+
// Liveness fault slashing parameters (less severe)
40+
cosmos.base.v1beta1.Coin liveness_slash_amount = 11 [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"liveness_slash_amount\""];
41+
bytes liveness_slash_fraction = 12 [
42+
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
43+
(gogoproto.nullable) = false,
44+
(amino.dont_omitempty) = true,
45+
(gogoproto.moretags) = "yaml:\"liveness_slash_fraction\""
46+
];
47+
google.protobuf.Duration liveness_jail_time = 13 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true, (gogoproto.moretags) = "yaml:\"liveness_jail_time\""];
48+
49+
// Proof fault slashing parameters (more severe for assigned provider)
50+
cosmos.base.v1beta1.Coin proof_fault_slash_amount = 14 [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"proof_fault_slash_amount\""];
51+
bytes proof_fault_slash_fraction = 15 [
52+
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
53+
(gogoproto.nullable) = false,
54+
(amino.dont_omitempty) = true,
55+
(gogoproto.moretags) = "yaml:\"proof_fault_slash_fraction\""
56+
];
57+
google.protobuf.Duration proof_fault_jail_time = 16 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true, (gogoproto.moretags) = "yaml:\"proof_fault_jail_time\""];
58+
59+
// Maximum number of consecutive proof faults before suspension
60+
uint64 max_proof_faults = 17 [(gogoproto.moretags) = "yaml:\"max_proof_faults\""];
3061
}

0 commit comments

Comments
 (0)