|
5 | 5 | * 2023-01-17: Initial Draft (@alexanderbez) |
6 | 6 | * 2023-04-06: Add upgrading section (@alexanderbez) |
7 | 7 | * 2023-04-10: Simplify vote extension state persistence (@alexanderbez) |
| 8 | +* 2023-07-07: Revise vote extension state persistence (@alexanderbez) |
8 | 9 |
|
9 | 10 | ## Status |
10 | 11 |
|
@@ -279,32 +280,22 @@ decision based on the vote extensions. |
279 | 280 | #### Vote Extension Persistence |
280 | 281 |
|
281 | 282 | In certain contexts, it may be useful or necessary for applications to persist |
282 | | -data derived from vote extensions. In order to facilitate this use case, we |
283 | | -propose to allow application developers to manually retrieve the `finalizeState` |
284 | | -context (see [`FinalizeBlock`](#finalizeblock-1) below). Using this context, |
285 | | -state can be directly written to `finalizeState`, which will be used during |
286 | | -`FinalizeBlock` and eventually committed to the application state. Note, since |
287 | | -`ProcessProposal` can timeout and thus require another round of consensus, we |
288 | | -will reset `finalizeState` in the beginning of `ProcessProposal`. |
| 283 | +data derived from vote extensions. In order to facilitate this use case, we propose |
| 284 | +to allow app developers to define a pre-FinalizeBlock hook which will be called |
| 285 | +at the very beginning of `FinalizeBlock`, i.e. before `BeginBlock` (see below). |
289 | 286 |
|
290 | | -A `ProcessProposal` handler could look like the following: |
| 287 | +Note, we cannot allow applications to directly write to the application state |
| 288 | +during `ProcessProposal` because during replay, CometBFT will NOT call `ProcessProposal`, |
| 289 | +which would result in an incomplete state view. |
291 | 290 |
|
292 | 291 | ```go |
293 | | -func (h MyHandler) ProcessProposalHandler() sdk.ProcessProposalHandler { |
294 | | - return func(ctx sdk.Context, req abci.RequestProcessProposal) abci.ResponseProcessProposal { |
295 | | - for _, txBytes := range req.Txs { |
296 | | - _, err := h.app.ProcessProposalVerifyTx(txBytes) |
297 | | - if err != nil { |
298 | | - return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT} |
299 | | - } |
300 | | - } |
301 | | - |
302 | | - fCtx := h.app.GetFinalizeState() |
303 | | - |
304 | | - // Any state changes that occur on the provided fCtx WILL be written to state! |
305 | | - h.myKeeper.SetVoteExtResult(fCtx, ...) |
| 292 | +func (a MyApp) PreFinalizeBlockHook(ctx sdk.Context, req.RequestFinalizeBlock) error { |
| 293 | + voteExts := GetVoteExtensions(ctx, req.Txs) |
306 | 294 |
|
307 | | - return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT} |
| 295 | + // Process and perform some compute on vote extensions, storing any resulting |
| 296 | + // state. |
| 297 | + if err a.processVoteExtensions(ctx, voteExts); if err != nil { |
| 298 | + return err |
308 | 299 | } |
309 | 300 | } |
310 | 301 | ``` |
@@ -347,9 +338,14 @@ legacy ABCI types, e.g. `LegacyBeginBlockRequest` and `LegacyEndBlockRequest`. O |
347 | 338 | we can come up with new types and names altogether. |
348 | 339 |
|
349 | 340 | ```go |
350 | | -func (app *BaseApp) FinalizeBlock(req abci.RequestFinalizeBlock) abci.ResponseFinalizeBlock { |
351 | | - // merge any state changes from ProcessProposal into the FinalizeBlock state |
352 | | - app.MergeProcessProposalState() |
| 341 | +func (app *BaseApp) FinalizeBlock(req abci.RequestFinalizeBlock) (*abci.ResponseFinalizeBlock, error) { |
| 342 | + ctx := ... |
| 343 | + |
| 344 | + if app.preFinalizeBlockHook != nil { |
| 345 | + if err := app.preFinalizeBlockHook(ctx, req); err != nil { |
| 346 | + return nil, err |
| 347 | + } |
| 348 | + } |
353 | 349 |
|
354 | 350 | beginBlockResp := app.beginBlock(ctx, req) |
355 | 351 | appendBlockEventAttr(beginBlockResp.Events, "begin_block") |
|
0 commit comments