Skip to content

Commit 8f7999c

Browse files
committed
feat(x/batching): implementation of batching module pruning
We add a new map from batch number to its data results to x/batching state in order to support simple pruning. In simple pruning we remove a batch and all its associated data if necessary to keep the number of batches at the module parameter NumBatchesToKeep.
1 parent 87b427e commit 8f7999c

26 files changed

+1951
-590
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package v1
2+
3+
import (
4+
"context"
5+
_ "embed"
6+
7+
storetypes "cosmossdk.io/store/types"
8+
upgradetypes "cosmossdk.io/x/upgrade/types"
9+
10+
sdk "github.com/cosmos/cosmos-sdk/types"
11+
"github.com/cosmos/cosmos-sdk/types/module"
12+
13+
"github.com/sedaprotocol/seda-chain/app/keepers"
14+
"github.com/sedaprotocol/seda-chain/app/upgrades"
15+
)
16+
17+
const (
18+
UpgradeName = "v" // TODO Update name and register this handler.
19+
)
20+
21+
var Upgrade = upgrades.Upgrade{
22+
UpgradeName: UpgradeName,
23+
CreateUpgradeHandler: CreateUpgradeHandler,
24+
StoreUpgrades: storetypes.StoreUpgrades{
25+
Added: []string{},
26+
Deleted: []string{},
27+
},
28+
}
29+
30+
func CreateUpgradeHandler(
31+
mm upgrades.ModuleManager,
32+
configurator module.Configurator,
33+
keepers *keepers.AppKeepers,
34+
) upgradetypes.UpgradeHandler {
35+
return func(context context.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
36+
ctx := sdk.UnwrapSDKContext(context)
37+
38+
// Run module migrations.
39+
migrations, err := mm.RunMigrations(ctx, configurator, fromVM)
40+
if err != nil {
41+
return nil, err
42+
}
43+
44+
err = keepers.BatchingKeeper.SetBatchNumberAtUpgrade(ctx)
45+
if err != nil {
46+
return nil, err
47+
}
48+
err = keepers.BatchingKeeper.SetHasPruningCaughtUp(ctx, false)
49+
if err != nil {
50+
return nil, err
51+
}
52+
53+
return migrations, nil
54+
}
55+
}

proto/sedachain/batching/v1/batching.proto

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,19 @@ message DataResult {
8686
bool consensus = 12 [ (gogoproto.jsontag) = "consensus" ];
8787
}
8888

89+
// DataRequestIDHeights is a collection of DataRequestIDHeight objects.
90+
message DataRequestIDHeights {
91+
repeated DataRequestIDHeight data_request_id_heights = 1 [ (gogoproto.nullable) = false ];
92+
}
93+
94+
// DataRequestIDHeight is a pair of data request ID and its posted height.
95+
message DataRequestIDHeight {
96+
// DataRequestID is the hex-encoded data request ID.
97+
string data_request_id = 1;
98+
// DataRequestHeight is the height at which the data request was submitted.
99+
uint64 data_request_height = 2;
100+
}
101+
89102
// Params defines the parameters for the batching module.
90103
message Params {
91104
// NumBatchesToKeep is the number of batches to keep in the state without
@@ -94,7 +107,7 @@ message Params {
94107
// MaxBatchPrunePerBlock is the maximum number of batches to prune per
95108
// block.
96109
uint64 max_batch_prune_per_block = 2;
97-
// MaxDataResultsToCheckForPrune is the maximum number of data results to
110+
// MaxDataResultPrunePerBlock is the maximum number of data results to
98111
// check for pruning per block.
99-
uint64 max_data_results_to_check_for_prune = 3;
112+
uint64 max_data_result_prune_per_block = 3;
100113
}

proto/sedachain/batching/v1/genesis.proto

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ message GenesisState {
1717
repeated BatchAssignment batch_assignments = 5
1818
[ (gogoproto.nullable) = false ];
1919
Params params = 6 [ (gogoproto.nullable) = false ];
20+
repeated GenesisDataResult legacy_data_results = 7 [ (gogoproto.nullable) = false ];
21+
bool has_pruning_caught_up = 8;
22+
uint64 batch_number_at_upgrade = 9;
2023
}
2124

2225
// BatchAssignment represents a batch assignment for genesis export

x/batching/README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,19 @@ The batching module collects data rseults, current validators, and their signatu
55

66
## State
77
```
8-
0x00 | is_batched | data_request_id | data_request_height -> data_result
8+
0x00 | is_batched | data_request_id | data_request_height -> legacy_data_results
99
0x01 | data_request_id | data_request_height -> batch_number
1010
0x02 -> current_batch_number
1111
0x03 | block_height -> batch
1212
0x04 | batch_number -> batch
1313
0x05 | batch_number | validator_address -> validator_tree_entries
1414
0x06 | batch_number -> data_tree_entries
1515
0x07 | batch_number | validator_address -> batch_signature
16+
0x08 -> parameters
17+
0x09 | is_batched | data_request_id | data_request_height -> data_result
18+
0x10 | batch_number -> data_request_id | data_request_height
19+
0x11 -> batch_number_at_upgrade
20+
0x12 -> has_pruning_caught_up
1621
```
1722

1823
### Batches

x/batching/keeper/batch.go

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -34,47 +34,48 @@ func (k Keeper) setBatch(ctx context.Context, batch types.Batch) error {
3434
return k.batches.Set(ctx, batch.BlockHeight, batch)
3535
}
3636

37-
// SetNewBatch increments the current batch number and stores a given
38-
// batch at that index. It also stores the given data result tree
39-
// entries, validator tree entries, and batch signature entries (at
40-
// the next batch index, to be populated with signatures later). It
41-
// returns an error if a batch already exists at the given batch's
42-
// block height or if the given batch's batch number does not match
43-
// the next batch number.
44-
func (k Keeper) SetNewBatch(ctx context.Context, batch types.Batch, dataEntries types.DataResultTreeEntries, valEntries []types.ValidatorTreeEntry) error {
37+
// SetNewBatch stores a new batch and its associated data at current batch number
38+
// and increments the current batch number. If successful, it returns the batch number
39+
// of the newly created batch.
40+
func (k Keeper) SetNewBatch(ctx sdk.Context, batch types.Batch, dataEntries types.DataResultTreeEntries, valEntries []types.ValidatorTreeEntry) (uint64, error) {
4541
found, err := k.batches.Has(ctx, batch.BlockHeight)
4642
if err != nil {
47-
return err
43+
return 0, err
4844
}
4945
if found {
50-
return types.ErrBatchAlreadyExists.Wrapf("batch block height %d", batch.BlockHeight)
46+
return 0, types.ErrBatchAlreadyExists.Wrapf("batch block height %d", batch.BlockHeight)
5147
}
5248

5349
batchNum, err := k.GetCurrentBatchNum(ctx)
5450
if err != nil {
55-
return err
51+
return 0, err
5652
}
5753
if batch.BatchNumber != batchNum {
58-
return types.ErrInvalidBatchNumber.Wrapf("got %d; expected %d", batch.BatchNumber, batchNum)
54+
return 0, types.ErrInvalidBatchNumber.Wrapf("got %d; expected %d", batch.BatchNumber, batchNum)
5955
}
6056

6157
err = k.setDataResultTreeEntry(ctx, batchNum, dataEntries)
6258
if err != nil {
63-
return err
59+
return 0, err
6460
}
6561

6662
for _, valEntry := range valEntries {
6763
err = k.setValidatorTreeEntry(ctx, batchNum, valEntry)
6864
if err != nil {
69-
return err
65+
return 0, err
7066
}
7167
}
7268

7369
_, err = k.incrementCurrentBatchNum(ctx)
7470
if err != nil {
75-
return err
71+
return 0, err
7672
}
77-
return k.batches.Set(ctx, batch.BlockHeight, batch)
73+
74+
err = k.batches.Set(ctx, batch.BlockHeight, batch)
75+
if err != nil {
76+
return 0, err
77+
}
78+
return batchNum, nil
7879
}
7980

8081
func (k Keeper) GetBatchForHeight(ctx context.Context, blockHeight int64) (types.Batch, error) {
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package keeper
2+
3+
import (
4+
"context"
5+
"errors"
6+
7+
"cosmossdk.io/collections"
8+
9+
"github.com/sedaprotocol/seda-chain/x/batching/types"
10+
)
11+
12+
// SetBatchAssignment stores mapping between data request ID - posted height pair
13+
// and assigned batch number in both directions.
14+
func (k Keeper) SetBatchAssignment(ctx context.Context, dataReqID string, dataReqHeight, batchNumber uint64) error {
15+
items, err := k.batchDataResults.Get(ctx, batchNumber)
16+
if err != nil {
17+
if !errors.Is(err, collections.ErrNotFound) {
18+
return err
19+
}
20+
items.DataRequestIdHeights = make([]types.DataRequestIDHeight, 0)
21+
}
22+
items.DataRequestIdHeights = append(items.DataRequestIdHeights, types.DataRequestIDHeight{
23+
DataRequestId: dataReqID,
24+
DataRequestHeight: dataReqHeight,
25+
})
26+
err = k.batchDataResults.Set(ctx, batchNumber, items)
27+
if err != nil {
28+
return err
29+
}
30+
31+
return k.batchAssignments.Set(ctx, collections.Join(dataReqID, dataReqHeight), batchNumber)
32+
}
33+
34+
func (k Keeper) GetBatchAssignment(ctx context.Context, dataReqID string, dataReqHeight uint64) (uint64, error) {
35+
return k.batchAssignments.Get(ctx, collections.Join(dataReqID, dataReqHeight))
36+
}
37+
38+
func (k Keeper) RemoveBatchAssignment(ctx context.Context, dataReqID string, dataReqHeight uint64) error {
39+
return k.batchAssignments.Remove(ctx, collections.Join(dataReqID, dataReqHeight))
40+
}
41+
42+
// getAllBatchAssignments retrieves all batch assignments from the store.
43+
// Used for genesis export.
44+
func (k Keeper) getAllBatchAssignments(ctx context.Context) ([]types.BatchAssignment, error) {
45+
var batchAssignments []types.BatchAssignment
46+
err := k.batchAssignments.Walk(ctx, nil, func(key collections.Pair[string, uint64], value uint64) (stop bool, err error) {
47+
batchAssignments = append(batchAssignments, types.BatchAssignment{
48+
BatchNumber: value,
49+
DataRequestId: key.K1(),
50+
DataRequestHeight: key.K2(),
51+
})
52+
return false, nil
53+
})
54+
return batchAssignments, err
55+
}
56+
57+
func (k Keeper) RemoveBatchDataResults(ctx context.Context, batchNumber uint64) error {
58+
return k.batchDataResults.Remove(ctx, batchNumber)
59+
}

x/batching/keeper/benchmark_endblock_test.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,17 @@ func BenchmarkBatchPruning(b *testing.B) {
2121
require.NoError(b, err)
2222
batch, dataEntries, valEntries, err := f.batchingKeeper.ConstructBatch(f.Context())
2323
require.NoError(b, err)
24-
err = f.batchingKeeper.SetNewBatch(f.Context(), batch, dataEntries, valEntries)
24+
_, err = f.batchingKeeper.SetNewBatch(f.Context(), batch, dataEntries, valEntries)
2525
require.NoError(b, err)
2626
}
2727

2828
for b.Loop() {
29-
_, err := f.batchingKeeper.PruneBatches(f.Context(), numBatchesToKeep, maxBatchPrunePerBlock)
29+
_, err := f.batchingKeeper.BatchPruneBatches(f.Context(), numBatchesToKeep, maxBatchPrunePerBlock)
3030
require.NoError(b, err)
3131
}
3232
}
3333

34+
/*
3435
func BenchmarkDataResultPruning(b *testing.B) {
3536
f := initFixture(b)
3637
@@ -53,7 +54,8 @@ func BenchmarkDataResultPruning(b *testing.B) {
5354
f.AddBlock()
5455
f.SetRandomLastCommitHash()
5556
56-
err := f.batchingKeeper.PruneDataResults(f.Context(), maxDataResultsToCheckForPrune, 2000)
57+
err := f.batchingKeeper.BatchPruneDataResults(f.Context(), maxDataResultsToCheckForPrune, 2000)
5758
require.NoError(b, err)
5859
}
5960
}
61+
*/

0 commit comments

Comments
 (0)