Commit the current state at the current height.
(&self)
| 975 | |
| 976 | /// Commit the current state at the current height. |
| 977 | async fn commit(&self) -> AbciResult<response::Commit> { |
| 978 | let exec_state = self |
| 979 | .take_exec_state() |
| 980 | .await |
| 981 | .context("failed to load execution state")?; |
| 982 | |
| 983 | let block_height = exec_state.block_height(); |
| 984 | let timestamp = exec_state.timestamp(); |
| 985 | let (state_root, params, _) = exec_state.commit().context("failed to commit FVM")?; |
| 986 | |
| 987 | let mut c = self.light_client_commitments.lock().await; |
| 988 | // because of the take, no need to *c = None |
| 989 | let state = |
| 990 | self.project_post_exec_state(block_height, timestamp, state_root, params, c.take())?; |
| 991 | |
| 992 | let app_hash = state.app_hash(); |
| 993 | let block_height = state.app_state.block_height; |
| 994 | |
| 995 | // Tell CometBFT how much of the block history it can forget. |
| 996 | let retain_height = if self.state_hist_size == 0 { |
| 997 | Default::default() |
| 998 | } else { |
| 999 | block_height.saturating_sub(self.state_hist_size) |
| 1000 | }; |
| 1001 | |
| 1002 | tracing::debug!( |
| 1003 | block_height, |
| 1004 | state_root = state.app_state.state_params.state_root.to_string(), |
| 1005 | app_hash = app_hash.to_string(), |
| 1006 | timestamp = state.app_state.state_params.timestamp.0, |
| 1007 | "commit state" |
| 1008 | ); |
| 1009 | |
| 1010 | // TODO: We can defer committing changes the resolution pool to this point. |
| 1011 | // For example if a checkpoint is successfully executed, that's when we want to remove |
| 1012 | // that checkpoint from the pool, and not propose it to other validators again. |
| 1013 | // However, once Tendermint starts delivering the transactions, the commit will surely |
| 1014 | // follow at the end, so we can also remove these checkpoints from memory at the time |
| 1015 | // the transaction is delivered, rather than when the whole thing is committed. |
| 1016 | // It is only important to the persistent database changes as an atomic step in the |
| 1017 | // commit in case the block execution fails somewhere in the middle for uknown reasons. |
| 1018 | // But if that happened, we will have to restart the application again anyway, and |
| 1019 | // repopulate the in-memory checkpoints based on the last committed ledger. |
| 1020 | // So, while the pool is theoretically part of the evolving state and we can pass |
| 1021 | // it in and out, unless we want to defer commit to here (which the interpreters aren't |
| 1022 | // notified about), we could add it to the `ChainMessageInterpreter` as a constructor argument, |
| 1023 | // a sort of "ambient state", and not worry about in in the `App` at all. |
| 1024 | |
| 1025 | // Notify the snapshotter. It wasn't clear whether this should be done in `commit` or `begin_block`, |
| 1026 | // that is, whether the _height_ of the snapshot should be `block_height` or `block_height+1`. |
| 1027 | // When CometBFT calls `offer_snapshot` it sends an `app_hash` in it that we compare to the CID |
| 1028 | // of the `state_params`. Based on end-to-end testing it looks like it gives the `app_hash` from |
| 1029 | // the *next* block, so we have to do it here. |
| 1030 | // For example: |
| 1031 | // a) Notify in `begin_block`: say we are at committing block 899, then we notify in `begin_block` |
| 1032 | // that block 900 has this state (so we use `block_height+1` in notification); |
| 1033 | // CometBFT is going to offer it with the `app_hash` of block 901, which won't match, because |
| 1034 | // by then the timestamp will be different in the state params after committing block 900. |
nothing calls this directly
no test coverage detected