github.com/aakash4dev/cometbft@v0.38.2/state/execution.go (about) 1 package state 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "time" 8 9 abci "github.com/aakash4dev/cometbft/abci/types" 10 cryptoenc "github.com/aakash4dev/cometbft/crypto/encoding" 11 "github.com/aakash4dev/cometbft/libs/fail" 12 "github.com/aakash4dev/cometbft/libs/log" 13 "github.com/aakash4dev/cometbft/mempool" 14 cmtproto "github.com/aakash4dev/cometbft/proto/tendermint/types" 15 "github.com/aakash4dev/cometbft/proxy" 16 "github.com/aakash4dev/cometbft/types" 17 ) 18 19 //----------------------------------------------------------------------------- 20 // BlockExecutor handles block execution and state updates. 21 // It exposes ApplyBlock(), which validates & executes the block, updates state w/ ABCI responses, 22 // then commits and updates the mempool atomically, then saves state. 23 24 // BlockExecutor provides the context and accessories for properly executing a block. 25 type BlockExecutor struct { 26 // save state, validators, consensus params, abci responses here 27 store Store 28 29 // use blockstore for the pruning functions. 30 blockStore BlockStore 31 32 // execute the app against this 33 proxyApp proxy.AppConnConsensus 34 35 // events 36 eventBus types.BlockEventPublisher 37 38 // manage the mempool lock during commit 39 // and update both with block results after commit. 40 mempool mempool.Mempool 41 evpool EvidencePool 42 43 logger log.Logger 44 45 metrics *Metrics 46 } 47 48 type BlockExecutorOption func(executor *BlockExecutor) 49 50 func BlockExecutorWithMetrics(metrics *Metrics) BlockExecutorOption { 51 return func(blockExec *BlockExecutor) { 52 blockExec.metrics = metrics 53 } 54 } 55 56 // NewBlockExecutor returns a new BlockExecutor with a NopEventBus. 57 // Call SetEventBus to provide one. 58 func NewBlockExecutor( 59 stateStore Store, 60 logger log.Logger, 61 proxyApp proxy.AppConnConsensus, 62 mempool mempool.Mempool, 63 evpool EvidencePool, 64 blockStore BlockStore, 65 options ...BlockExecutorOption, 66 ) *BlockExecutor { 67 res := &BlockExecutor{ 68 store: stateStore, 69 proxyApp: proxyApp, 70 eventBus: types.NopEventBus{}, 71 mempool: mempool, 72 evpool: evpool, 73 logger: logger, 74 metrics: NopMetrics(), 75 blockStore: blockStore, 76 } 77 78 for _, option := range options { 79 option(res) 80 } 81 82 return res 83 } 84 85 func (blockExec *BlockExecutor) Store() Store { 86 return blockExec.store 87 } 88 89 // SetEventBus - sets the event bus for publishing block related events. 90 // If not called, it defaults to types.NopEventBus. 91 func (blockExec *BlockExecutor) SetEventBus(eventBus types.BlockEventPublisher) { 92 blockExec.eventBus = eventBus 93 } 94 95 // CreateProposalBlock calls state.MakeBlock with evidence from the evpool 96 // and txs from the mempool. The max bytes must be big enough to fit the commit. 97 // The block space is first allocated to outstanding evidence. 98 // The rest is given to txs, up to the max gas. 99 // 100 // Contract: application will not return more bytes than are sent over the wire. 101 func (blockExec *BlockExecutor) CreateProposalBlock( 102 ctx context.Context, 103 height int64, 104 state State, 105 lastExtCommit *types.ExtendedCommit, 106 proposerAddr []byte, 107 ) (*types.Block, error) { 108 109 maxBytes := state.ConsensusParams.Block.MaxBytes 110 emptyMaxBytes := maxBytes == -1 111 if emptyMaxBytes { 112 maxBytes = int64(types.MaxBlockSizeBytes) 113 } 114 115 maxGas := state.ConsensusParams.Block.MaxGas 116 117 evidence, evSize := blockExec.evpool.PendingEvidence(state.ConsensusParams.Evidence.MaxBytes) 118 119 // Fetch a limited amount of valid txs 120 maxDataBytes := types.MaxDataBytes(maxBytes, evSize, state.Validators.Size()) 121 maxReapBytes := maxDataBytes 122 if emptyMaxBytes { 123 maxReapBytes = -1 124 } 125 126 txs := blockExec.mempool.ReapMaxBytesMaxGas(maxReapBytes, maxGas) 127 commit := lastExtCommit.ToCommit() 128 block := state.MakeBlock(height, txs, commit, evidence, proposerAddr) 129 rpp, err := blockExec.proxyApp.PrepareProposal( 130 ctx, 131 &abci.RequestPrepareProposal{ 132 MaxTxBytes: maxDataBytes, 133 Txs: block.Txs.ToSliceOfBytes(), 134 LocalLastCommit: buildExtendedCommitInfo(lastExtCommit, blockExec.store, state.InitialHeight, state.ConsensusParams.ABCI), 135 Misbehavior: block.Evidence.Evidence.ToABCI(), 136 Height: block.Height, 137 Time: block.Time, 138 NextValidatorsHash: block.NextValidatorsHash, 139 ProposerAddress: block.ProposerAddress, 140 }, 141 ) 142 if err != nil { 143 // The App MUST ensure that only valid (and hence 'processable') transactions 144 // enter the mempool. Hence, at this point, we can't have any non-processable 145 // transaction causing an error. 146 // 147 // Also, the App can simply skip any transaction that could cause any kind of trouble. 148 // Either way, we cannot recover in a meaningful way, unless we skip proposing 149 // this block, repair what caused the error and try again. Hence, we return an 150 // error for now (the production code calling this function is expected to panic). 151 return nil, err 152 } 153 154 txl := types.ToTxs(rpp.Txs) 155 if err := txl.Validate(maxDataBytes); err != nil { 156 return nil, err 157 } 158 159 return state.MakeBlock(height, txl, commit, evidence, proposerAddr), nil 160 } 161 162 func (blockExec *BlockExecutor) ProcessProposal( 163 block *types.Block, 164 state State, 165 ) (bool, error) { 166 resp, err := blockExec.proxyApp.ProcessProposal(context.TODO(), &abci.RequestProcessProposal{ 167 Hash: block.Header.Hash(), 168 Height: block.Header.Height, 169 Time: block.Header.Time, 170 Txs: block.Data.Txs.ToSliceOfBytes(), 171 ProposedLastCommit: buildLastCommitInfo(block, blockExec.store, state.InitialHeight), 172 Misbehavior: block.Evidence.Evidence.ToABCI(), 173 ProposerAddress: block.ProposerAddress, 174 NextValidatorsHash: block.NextValidatorsHash, 175 }) 176 if err != nil { 177 return false, err 178 } 179 if resp.IsStatusUnknown() { 180 panic(fmt.Sprintf("ProcessProposal responded with status %s", resp.Status.String())) 181 } 182 183 return resp.IsAccepted(), nil 184 } 185 186 // ValidateBlock validates the given block against the given state. 187 // If the block is invalid, it returns an error. 188 // Validation does not mutate state, but does require historical information from the stateDB, 189 // ie. to verify evidence from a validator at an old height. 190 func (blockExec *BlockExecutor) ValidateBlock(state State, block *types.Block) error { 191 err := validateBlock(state, block) 192 if err != nil { 193 return err 194 } 195 return blockExec.evpool.CheckEvidence(block.Evidence.Evidence) 196 } 197 198 // ApplyBlock validates the block against the state, executes it against the app, 199 // fires the relevant events, commits the app, and saves the new state and responses. 200 // It returns the new state. 201 // It's the only function that needs to be called 202 // from outside this package to process and commit an entire block. 203 // It takes a blockID to avoid recomputing the parts hash. 204 func (blockExec *BlockExecutor) ApplyBlock( 205 state State, blockID types.BlockID, block *types.Block, 206 ) (State, error) { 207 208 if err := validateBlock(state, block); err != nil { 209 return state, ErrInvalidBlock(err) 210 } 211 212 commitInfo := buildLastCommitInfo(block, blockExec.store, state.InitialHeight) 213 214 startTime := time.Now().UnixNano() 215 abciResponse, err := blockExec.proxyApp.FinalizeBlock(context.TODO(), &abci.RequestFinalizeBlock{ 216 Hash: block.Hash(), 217 NextValidatorsHash: block.NextValidatorsHash, 218 ProposerAddress: block.ProposerAddress, 219 Height: block.Height, 220 Time: block.Time, 221 DecidedLastCommit: commitInfo, 222 Misbehavior: block.Evidence.Evidence.ToABCI(), 223 Txs: block.Txs.ToSliceOfBytes(), 224 }) 225 endTime := time.Now().UnixNano() 226 blockExec.metrics.BlockProcessingTime.Observe(float64(endTime-startTime) / 1000000) 227 if err != nil { 228 blockExec.logger.Error("error in proxyAppConn.FinalizeBlock", "err", err) 229 return state, err 230 } 231 232 blockExec.logger.Info( 233 "finalized block", 234 "height", block.Height, 235 "num_txs_res", len(abciResponse.TxResults), 236 "num_val_updates", len(abciResponse.ValidatorUpdates), 237 "block_app_hash", fmt.Sprintf("%X", abciResponse.AppHash), 238 ) 239 240 // Assert that the application correctly returned tx results for each of the transactions provided in the block 241 if len(block.Data.Txs) != len(abciResponse.TxResults) { 242 return state, fmt.Errorf("expected tx results length to match size of transactions in block. Expected %d, got %d", len(block.Data.Txs), len(abciResponse.TxResults)) 243 } 244 245 blockExec.logger.Info("executed block", "height", block.Height, "app_hash", abciResponse.AppHash) 246 247 fail.Fail() // XXX 248 249 // Save the results before we commit. 250 if err := blockExec.store.SaveFinalizeBlockResponse(block.Height, abciResponse); err != nil { 251 return state, err 252 } 253 254 fail.Fail() // XXX 255 256 // validate the validator updates and convert to CometBFT types 257 err = validateValidatorUpdates(abciResponse.ValidatorUpdates, state.ConsensusParams.Validator) 258 if err != nil { 259 return state, fmt.Errorf("error in validator updates: %v", err) 260 } 261 262 validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponse.ValidatorUpdates) 263 if err != nil { 264 return state, err 265 } 266 if len(validatorUpdates) > 0 { 267 blockExec.logger.Debug("updates to validators", "updates", types.ValidatorListString(validatorUpdates)) 268 blockExec.metrics.ValidatorSetUpdates.Add(1) 269 } 270 if abciResponse.ConsensusParamUpdates != nil { 271 blockExec.metrics.ConsensusParamUpdates.Add(1) 272 } 273 274 // Update the state with the block and responses. 275 state, err = updateState(state, blockID, &block.Header, abciResponse, validatorUpdates) 276 if err != nil { 277 return state, fmt.Errorf("commit failed for application: %v", err) 278 } 279 280 // Lock mempool, commit app state, update mempoool. 281 retainHeight, err := blockExec.Commit(state, block, abciResponse) 282 if err != nil { 283 return state, fmt.Errorf("commit failed for application: %v", err) 284 } 285 286 // Update evpool with the latest state. 287 blockExec.evpool.Update(state, block.Evidence.Evidence) 288 289 fail.Fail() // XXX 290 291 // Update the app hash and save the state. 292 state.AppHash = abciResponse.AppHash 293 if err := blockExec.store.Save(state); err != nil { 294 return state, err 295 } 296 297 fail.Fail() // XXX 298 299 // Prune old heights, if requested by ABCI app. 300 if retainHeight > 0 { 301 pruned, err := blockExec.pruneBlocks(retainHeight, state) 302 if err != nil { 303 blockExec.logger.Error("failed to prune blocks", "retain_height", retainHeight, "err", err) 304 } else { 305 blockExec.logger.Debug("pruned blocks", "pruned", pruned, "retain_height", retainHeight) 306 } 307 } 308 309 // Events are fired after everything else. 310 // NOTE: if we crash between Commit and Save, events wont be fired during replay 311 fireEvents(blockExec.logger, blockExec.eventBus, block, blockID, abciResponse, validatorUpdates) 312 313 return state, nil 314 } 315 316 func (blockExec *BlockExecutor) ExtendVote(ctx context.Context, vote *types.Vote) ([]byte, error) { 317 req := abci.RequestExtendVote{ 318 Hash: vote.BlockID.Hash, 319 Height: vote.Height, 320 } 321 322 resp, err := blockExec.proxyApp.ExtendVote(ctx, &req) 323 if err != nil { 324 panic(fmt.Errorf("ExtendVote call failed: %w", err)) 325 } 326 return resp.VoteExtension, nil 327 } 328 329 func (blockExec *BlockExecutor) VerifyVoteExtension(ctx context.Context, vote *types.Vote) error { 330 req := abci.RequestVerifyVoteExtension{ 331 Hash: vote.BlockID.Hash, 332 ValidatorAddress: vote.ValidatorAddress, 333 Height: vote.Height, 334 VoteExtension: vote.Extension, 335 } 336 337 resp, err := blockExec.proxyApp.VerifyVoteExtension(ctx, &req) 338 if err != nil { 339 panic(fmt.Errorf("VerifyVoteExtension call failed: %w", err)) 340 } 341 if resp.IsStatusUnknown() { 342 panic(fmt.Sprintf("VerifyVoteExtension responded with status %s", resp.Status.String())) 343 } 344 345 if !resp.IsAccepted() { 346 return types.ErrInvalidVoteExtension 347 } 348 return nil 349 } 350 351 // Commit locks the mempool, runs the ABCI Commit message, and updates the 352 // mempool. 353 // It returns the result of calling abci.Commit which is the height to retain (if any)). 354 // The application is expected to have persisted its state (if any) before returning 355 // from the ABCI Commit call. This is the only place where the application should 356 // persist its state. 357 // The Mempool must be locked during commit and update because state is 358 // typically reset on Commit and old txs must be replayed against committed 359 // state before new txs are run in the mempool, lest they be invalid. 360 func (blockExec *BlockExecutor) Commit( 361 state State, 362 block *types.Block, 363 abciResponse *abci.ResponseFinalizeBlock, 364 ) (int64, error) { 365 blockExec.mempool.Lock() 366 defer blockExec.mempool.Unlock() 367 368 // while mempool is Locked, flush to ensure all async requests have completed 369 // in the ABCI app before Commit. 370 err := blockExec.mempool.FlushAppConn() 371 if err != nil { 372 blockExec.logger.Error("client error during mempool.FlushAppConn", "err", err) 373 return 0, err 374 } 375 376 // Commit block, get hash back 377 res, err := blockExec.proxyApp.Commit(context.TODO()) 378 if err != nil { 379 blockExec.logger.Error("client error during proxyAppConn.CommitSync", "err", err) 380 return 0, err 381 } 382 383 // ResponseCommit has no error code - just data 384 blockExec.logger.Info( 385 "committed state", 386 "height", block.Height, 387 "block_app_hash", fmt.Sprintf("%X", block.AppHash), 388 ) 389 390 // Update mempool. 391 err = blockExec.mempool.Update( 392 block.Height, 393 block.Txs, 394 abciResponse.TxResults, 395 TxPreCheck(state), 396 TxPostCheck(state), 397 ) 398 399 return res.RetainHeight, err 400 } 401 402 //--------------------------------------------------------- 403 // Helper functions for executing blocks and updating state 404 405 func buildLastCommitInfo(block *types.Block, store Store, initialHeight int64) abci.CommitInfo { 406 if block.Height == initialHeight { 407 // there is no last commit for the initial height. 408 // return an empty value. 409 return abci.CommitInfo{} 410 } 411 412 lastValSet, err := store.LoadValidators(block.Height - 1) 413 if err != nil { 414 panic(fmt.Errorf("failed to load validator set at height %d: %w", block.Height-1, err)) 415 } 416 417 var ( 418 commitSize = block.LastCommit.Size() 419 valSetLen = len(lastValSet.Validators) 420 ) 421 422 // ensure that the size of the validator set in the last commit matches 423 // the size of the validator set in the state store. 424 if commitSize != valSetLen { 425 panic(fmt.Sprintf( 426 "commit size (%d) doesn't match validator set length (%d) at height %d\n\n%v\n\n%v", 427 commitSize, valSetLen, block.Height, block.LastCommit.Signatures, lastValSet.Validators, 428 )) 429 } 430 431 votes := make([]abci.VoteInfo, block.LastCommit.Size()) 432 for i, val := range lastValSet.Validators { 433 commitSig := block.LastCommit.Signatures[i] 434 votes[i] = abci.VoteInfo{ 435 Validator: types.TM2PB.Validator(val), 436 BlockIdFlag: cmtproto.BlockIDFlag(commitSig.BlockIDFlag), 437 } 438 } 439 440 return abci.CommitInfo{ 441 Round: block.LastCommit.Round, 442 Votes: votes, 443 } 444 } 445 446 // buildExtendedCommitInfo populates an ABCI extended commit from the 447 // corresponding CometBFT extended commit ec, using the stored validator set 448 // from ec. It requires ec to include the original precommit votes along with 449 // the vote extensions from the last commit. 450 // 451 // For heights below the initial height, for which we do not have the required 452 // data, it returns an empty record. 453 // 454 // Assumes that the commit signatures are sorted according to validator index. 455 func buildExtendedCommitInfo(ec *types.ExtendedCommit, store Store, initialHeight int64, ap types.ABCIParams) abci.ExtendedCommitInfo { 456 if ec.Height < initialHeight { 457 // There are no extended commits for heights below the initial height. 458 return abci.ExtendedCommitInfo{} 459 } 460 461 valSet, err := store.LoadValidators(ec.Height) 462 if err != nil { 463 panic(fmt.Errorf("failed to load validator set at height %d, initial height %d: %w", ec.Height, initialHeight, err)) 464 } 465 466 var ( 467 ecSize = ec.Size() 468 valSetLen = len(valSet.Validators) 469 ) 470 471 // Ensure that the size of the validator set in the extended commit matches 472 // the size of the validator set in the state store. 473 if ecSize != valSetLen { 474 panic(fmt.Errorf( 475 "extended commit size (%d) does not match validator set length (%d) at height %d\n\n%v\n\n%v", 476 ecSize, valSetLen, ec.Height, ec.ExtendedSignatures, valSet.Validators, 477 )) 478 } 479 480 votes := make([]abci.ExtendedVoteInfo, ecSize) 481 for i, val := range valSet.Validators { 482 ecs := ec.ExtendedSignatures[i] 483 484 // Absent signatures have empty validator addresses, but otherwise we 485 // expect the validator addresses to be the same. 486 if ecs.BlockIDFlag != types.BlockIDFlagAbsent && !bytes.Equal(ecs.ValidatorAddress, val.Address) { 487 panic(fmt.Errorf("validator address of extended commit signature in position %d (%s) does not match the corresponding validator's at height %d (%s)", 488 i, ecs.ValidatorAddress, ec.Height, val.Address, 489 )) 490 } 491 492 // Check if vote extensions were enabled during the commit's height: ec.Height. 493 // ec is the commit from the previous height, so if extensions were enabled 494 // during that height, we ensure they are present and deliver the data to 495 // the proposer. If they were not enabled during this previous height, we 496 // will not deliver extension data. 497 if err := ecs.EnsureExtension(ap.VoteExtensionsEnabled(ec.Height)); err != nil { 498 panic(fmt.Errorf("commit at height %d has problems with vote extension data; err %w", ec.Height, err)) 499 } 500 501 votes[i] = abci.ExtendedVoteInfo{ 502 Validator: types.TM2PB.Validator(val), 503 BlockIdFlag: cmtproto.BlockIDFlag(ecs.BlockIDFlag), 504 VoteExtension: ecs.Extension, 505 ExtensionSignature: ecs.ExtensionSignature, 506 } 507 } 508 509 return abci.ExtendedCommitInfo{ 510 Round: ec.Round, 511 Votes: votes, 512 } 513 } 514 515 func validateValidatorUpdates(abciUpdates []abci.ValidatorUpdate, 516 params types.ValidatorParams) error { 517 for _, valUpdate := range abciUpdates { 518 if valUpdate.GetPower() < 0 { 519 return fmt.Errorf("voting power can't be negative %v", valUpdate) 520 } else if valUpdate.GetPower() == 0 { 521 // continue, since this is deleting the validator, and thus there is no 522 // pubkey to check 523 continue 524 } 525 526 // Check if validator's pubkey matches an ABCI type in the consensus params 527 pk, err := cryptoenc.PubKeyFromProto(valUpdate.PubKey) 528 if err != nil { 529 return err 530 } 531 532 if !types.IsValidPubkeyType(params, pk.Type()) { 533 return fmt.Errorf("validator %v is using pubkey %s, which is unsupported for consensus", 534 valUpdate, pk.Type()) 535 } 536 } 537 return nil 538 } 539 540 // updateState returns a new State updated according to the header and responses. 541 func updateState( 542 state State, 543 blockID types.BlockID, 544 header *types.Header, 545 abciResponse *abci.ResponseFinalizeBlock, 546 validatorUpdates []*types.Validator, 547 ) (State, error) { 548 549 // Copy the valset so we can apply changes from EndBlock 550 // and update s.LastValidators and s.Validators. 551 nValSet := state.NextValidators.Copy() 552 553 // Update the validator set with the latest abciResponse. 554 lastHeightValsChanged := state.LastHeightValidatorsChanged 555 if len(validatorUpdates) > 0 { 556 err := nValSet.UpdateWithChangeSet(validatorUpdates) 557 if err != nil { 558 return state, fmt.Errorf("changing validator set: %w", err) 559 } 560 // Change results from this height but only applies to the next next height. 561 lastHeightValsChanged = header.Height + 1 + 1 562 } 563 564 // Update validator proposer priority and set state variables. 565 nValSet.IncrementProposerPriority(1) 566 567 // Update the params with the latest abciResponse. 568 nextParams := state.ConsensusParams 569 lastHeightParamsChanged := state.LastHeightConsensusParamsChanged 570 if abciResponse.ConsensusParamUpdates != nil { 571 // NOTE: must not mutate state.ConsensusParams 572 nextParams = state.ConsensusParams.Update(abciResponse.ConsensusParamUpdates) 573 err := nextParams.ValidateBasic() 574 if err != nil { 575 return state, fmt.Errorf("validating new consensus params: %w", err) 576 } 577 578 err = state.ConsensusParams.ValidateUpdate(abciResponse.ConsensusParamUpdates, header.Height) 579 if err != nil { 580 return state, fmt.Errorf("updating consensus params: %w", err) 581 } 582 583 state.Version.Consensus.App = nextParams.Version.App 584 585 // Change results from this height but only applies to the next height. 586 lastHeightParamsChanged = header.Height + 1 587 } 588 589 nextVersion := state.Version 590 591 // NOTE: the AppHash and the VoteExtension has not been populated. 592 // It will be filled on state.Save. 593 return State{ 594 Version: nextVersion, 595 ChainID: state.ChainID, 596 InitialHeight: state.InitialHeight, 597 LastBlockHeight: header.Height, 598 LastBlockID: blockID, 599 LastBlockTime: header.Time, 600 NextValidators: nValSet, 601 Validators: state.NextValidators.Copy(), 602 LastValidators: state.Validators.Copy(), 603 LastHeightValidatorsChanged: lastHeightValsChanged, 604 ConsensusParams: nextParams, 605 LastHeightConsensusParamsChanged: lastHeightParamsChanged, 606 LastResultsHash: TxResultsHash(abciResponse.TxResults), 607 AppHash: nil, 608 }, nil 609 } 610 611 // Fire NewBlock, NewBlockHeader. 612 // Fire TxEvent for every tx. 613 // NOTE: if CometBFT crashes before commit, some or all of these events may be published again. 614 func fireEvents( 615 logger log.Logger, 616 eventBus types.BlockEventPublisher, 617 block *types.Block, 618 blockID types.BlockID, 619 abciResponse *abci.ResponseFinalizeBlock, 620 validatorUpdates []*types.Validator, 621 ) { 622 if err := eventBus.PublishEventNewBlock(types.EventDataNewBlock{ 623 Block: block, 624 BlockID: blockID, 625 ResultFinalizeBlock: *abciResponse, 626 }); err != nil { 627 logger.Error("failed publishing new block", "err", err) 628 } 629 630 if err := eventBus.PublishEventNewBlockHeader(types.EventDataNewBlockHeader{ 631 Header: block.Header, 632 }); err != nil { 633 logger.Error("failed publishing new block header", "err", err) 634 } 635 636 if err := eventBus.PublishEventNewBlockEvents(types.EventDataNewBlockEvents{ 637 Height: block.Height, 638 Events: abciResponse.Events, 639 NumTxs: int64(len(block.Txs)), 640 }); err != nil { 641 logger.Error("failed publishing new block events", "err", err) 642 } 643 644 if len(block.Evidence.Evidence) != 0 { 645 for _, ev := range block.Evidence.Evidence { 646 if err := eventBus.PublishEventNewEvidence(types.EventDataNewEvidence{ 647 Evidence: ev, 648 Height: block.Height, 649 }); err != nil { 650 logger.Error("failed publishing new evidence", "err", err) 651 } 652 } 653 } 654 655 for i, tx := range block.Data.Txs { 656 if err := eventBus.PublishEventTx(types.EventDataTx{TxResult: abci.TxResult{ 657 Height: block.Height, 658 Index: uint32(i), 659 Tx: tx, 660 Result: *(abciResponse.TxResults[i]), 661 }}); err != nil { 662 logger.Error("failed publishing event TX", "err", err) 663 } 664 } 665 666 if len(validatorUpdates) > 0 { 667 if err := eventBus.PublishEventValidatorSetUpdates( 668 types.EventDataValidatorSetUpdates{ValidatorUpdates: validatorUpdates}); err != nil { 669 logger.Error("failed publishing event", "err", err) 670 } 671 } 672 } 673 674 //---------------------------------------------------------------------------------------------------- 675 // Execute block without state. TODO: eliminate 676 677 // ExecCommitBlock executes and commits a block on the proxyApp without validating or mutating the state. 678 // It returns the application root hash (result of abci.Commit). 679 func ExecCommitBlock( 680 appConnConsensus proxy.AppConnConsensus, 681 block *types.Block, 682 logger log.Logger, 683 store Store, 684 initialHeight int64, 685 ) ([]byte, error) { 686 commitInfo := buildLastCommitInfo(block, store, initialHeight) 687 688 resp, err := appConnConsensus.FinalizeBlock(context.TODO(), &abci.RequestFinalizeBlock{ 689 Hash: block.Hash(), 690 NextValidatorsHash: block.NextValidatorsHash, 691 ProposerAddress: block.ProposerAddress, 692 Height: block.Height, 693 Time: block.Time, 694 DecidedLastCommit: commitInfo, 695 Misbehavior: block.Evidence.Evidence.ToABCI(), 696 Txs: block.Txs.ToSliceOfBytes(), 697 }) 698 if err != nil { 699 logger.Error("error in proxyAppConn.FinalizeBlock", "err", err) 700 return nil, err 701 } 702 703 // Assert that the application correctly returned tx results for each of the transactions provided in the block 704 if len(block.Data.Txs) != len(resp.TxResults) { 705 return nil, fmt.Errorf("expected tx results length to match size of transactions in block. Expected %d, got %d", len(block.Data.Txs), len(resp.TxResults)) 706 } 707 708 logger.Info("executed block", "height", block.Height, "app_hash", resp.AppHash) 709 710 // Commit block 711 _, err = appConnConsensus.Commit(context.TODO()) 712 if err != nil { 713 logger.Error("client error during proxyAppConn.Commit", "err", err) 714 return nil, err 715 } 716 717 // ResponseCommit has no error or log 718 return resp.AppHash, nil 719 } 720 721 func (blockExec *BlockExecutor) pruneBlocks(retainHeight int64, state State) (uint64, error) { 722 base := blockExec.blockStore.Base() 723 if retainHeight <= base { 724 return 0, nil 725 } 726 727 amountPruned, prunedHeaderHeight, err := blockExec.blockStore.PruneBlocks(retainHeight, state) 728 if err != nil { 729 return 0, fmt.Errorf("failed to prune block store: %w", err) 730 } 731 732 err = blockExec.Store().PruneStates(base, retainHeight, prunedHeaderHeight) 733 if err != nil { 734 return 0, fmt.Errorf("failed to prune state store: %w", err) 735 } 736 return amountPruned, nil 737 }