github.com/ari-anchor/sei-tendermint@v0.0.0-20230519144642-dc826b7b56bb/internal/state/execution.go (about) 1 package state 2 3 import ( 4 "bytes" 5 "context" 6 "errors" 7 "fmt" 8 "math" 9 "time" 10 11 abciclient "github.com/ari-anchor/sei-tendermint/abci/client" 12 abci "github.com/ari-anchor/sei-tendermint/abci/types" 13 "github.com/ari-anchor/sei-tendermint/crypto/encoding" 14 "github.com/ari-anchor/sei-tendermint/crypto/merkle" 15 "github.com/ari-anchor/sei-tendermint/internal/eventbus" 16 "github.com/ari-anchor/sei-tendermint/internal/mempool" 17 "github.com/ari-anchor/sei-tendermint/libs/log" 18 tmtypes "github.com/ari-anchor/sei-tendermint/proto/tendermint/types" 19 "github.com/ari-anchor/sei-tendermint/types" 20 otrace "go.opentelemetry.io/otel/trace" 21 ) 22 23 //----------------------------------------------------------------------------- 24 // BlockExecutor handles block execution and state updates. 25 // It exposes ApplyBlock(), which validates & executes the block, updates state w/ ABCI responses, 26 // then commits and updates the mempool atomically, then saves state. 27 28 // BlockExecutor provides the context and accessories for properly executing a block. 29 type BlockExecutor struct { 30 // save state, validators, consensus params, abci responses here 31 store Store 32 33 // use blockstore for the pruning functions. 34 blockStore BlockStore 35 36 // execute the app against this 37 appClient abciclient.Client 38 39 // events 40 eventBus types.BlockEventPublisher 41 42 // manage the mempool lock during commit 43 // and update both with block results after commit. 44 mempool mempool.Mempool 45 evpool EvidencePool 46 47 logger log.Logger 48 metrics *Metrics 49 50 // cache the verification results over a single height 51 cache map[string]struct{} 52 } 53 54 // NewBlockExecutor returns a new BlockExecutor with the passed-in EventBus. 55 func NewBlockExecutor( 56 stateStore Store, 57 logger log.Logger, 58 appClient abciclient.Client, 59 pool mempool.Mempool, 60 evpool EvidencePool, 61 blockStore BlockStore, 62 eventBus *eventbus.EventBus, 63 metrics *Metrics, 64 ) *BlockExecutor { 65 return &BlockExecutor{ 66 eventBus: eventBus, 67 store: stateStore, 68 appClient: appClient, 69 mempool: pool, 70 evpool: evpool, 71 logger: logger, 72 metrics: metrics, 73 cache: make(map[string]struct{}), 74 blockStore: blockStore, 75 } 76 } 77 78 func (blockExec *BlockExecutor) Store() Store { 79 return blockExec.store 80 } 81 82 // CreateProposalBlock calls state.MakeBlock with evidence from the evpool 83 // and txs from the mempool. The max bytes must be big enough to fit the commit. 84 // Up to 1/10th of the block space is allcoated for maximum sized evidence. 85 // The rest is given to txs, up to the max gas. 86 // 87 // Contract: application will not return more bytes than are sent over the wire. 88 func (blockExec *BlockExecutor) CreateProposalBlock( 89 ctx context.Context, 90 height int64, 91 state State, 92 lastExtCommit *types.ExtendedCommit, 93 proposerAddr []byte, 94 ) (*types.Block, error) { 95 96 maxBytes := state.ConsensusParams.Block.MaxBytes 97 maxGas := state.ConsensusParams.Block.MaxGas 98 99 evidence, evSize := blockExec.evpool.PendingEvidence(state.ConsensusParams.Evidence.MaxBytes) 100 101 // Fetch a limited amount of valid txs 102 maxDataBytes := types.MaxDataBytes(maxBytes, evSize, state.Validators.Size()) 103 104 txs := blockExec.mempool.ReapMaxBytesMaxGas(maxDataBytes, maxGas) 105 commit := lastExtCommit.ToCommit() 106 block := state.MakeBlock(height, txs, commit, evidence, proposerAddr) 107 rpp, err := blockExec.appClient.PrepareProposal( 108 ctx, 109 &abci.RequestPrepareProposal{ 110 MaxTxBytes: maxDataBytes, 111 Txs: block.Txs.ToSliceOfBytes(), 112 LocalLastCommit: buildExtendedCommitInfo(lastExtCommit, blockExec.store, state.InitialHeight, state.ConsensusParams.ABCI), 113 ByzantineValidators: block.Evidence.ToABCI(), 114 Height: block.Height, 115 Time: block.Time, 116 NextValidatorsHash: block.NextValidatorsHash, 117 ProposerAddress: block.ProposerAddress, 118 AppHash: block.AppHash, 119 ValidatorsHash: block.ValidatorsHash, 120 ConsensusHash: block.ConsensusHash, 121 DataHash: block.DataHash, 122 EvidenceHash: block.EvidenceHash, 123 LastBlockHash: block.LastBlockID.Hash, 124 LastBlockPartSetTotal: int64(block.LastBlockID.PartSetHeader.Total), 125 LastBlockPartSetHash: block.LastBlockID.Hash, 126 LastCommitHash: block.LastCommitHash, 127 LastResultsHash: block.LastResultsHash, 128 }, 129 ) 130 if err != nil { 131 // The App MUST ensure that only valid (and hence 'processable') transactions 132 // enter the mempool. Hence, at this point, we can't have any non-processable 133 // transaction causing an error. 134 // 135 // Also, the App can simply skip any transaction that could cause any kind of trouble. 136 // Either way, we cannot recover in a meaningful way, unless we skip proposing 137 // this block, repair what caused the error and try again. Hence, we return an 138 // error for now (the production code calling this function is expected to panic). 139 return nil, err 140 } 141 txrSet := types.NewTxRecordSet(rpp.TxRecords) 142 143 if err := txrSet.Validate(maxDataBytes, block.Txs); err != nil { 144 return nil, err 145 } 146 147 for _, rtx := range txrSet.RemovedTxs() { 148 if err := blockExec.mempool.RemoveTxByKey(rtx.Key()); err != nil { 149 blockExec.logger.Debug("error removing transaction from the mempool", "error", err, "tx hash", rtx.Hash()) 150 } 151 } 152 itxs := txrSet.IncludedTxs() 153 return state.MakeBlock(height, itxs, commit, evidence, proposerAddr), nil 154 } 155 156 func (blockExec *BlockExecutor) GetTxsForKeys(txKeys []types.TxKey) types.Txs { 157 return blockExec.mempool.GetTxsForKeys(txKeys) 158 } 159 160 func (blockExec *BlockExecutor) ProcessProposal( 161 ctx context.Context, 162 block *types.Block, 163 state State, 164 ) (bool, error) { 165 txs := block.Data.Txs.ToSliceOfBytes() 166 resp, err := blockExec.appClient.ProcessProposal(ctx, &abci.RequestProcessProposal{ 167 Hash: block.Header.Hash(), 168 Height: block.Header.Height, 169 Time: block.Header.Time, 170 Txs: txs, 171 ProposedLastCommit: buildLastCommitInfo(block, blockExec.store, state.InitialHeight), 172 ByzantineValidators: block.Evidence.ToABCI(), 173 ProposerAddress: block.ProposerAddress, 174 NextValidatorsHash: block.NextValidatorsHash, 175 AppHash: block.AppHash, 176 ValidatorsHash: block.ValidatorsHash, 177 ConsensusHash: block.ConsensusHash, 178 DataHash: block.DataHash, 179 EvidenceHash: block.EvidenceHash, 180 LastBlockHash: block.LastBlockID.Hash, 181 LastBlockPartSetTotal: int64(block.LastBlockID.PartSetHeader.Total), 182 LastBlockPartSetHash: block.LastBlockID.Hash, 183 LastCommitHash: block.LastCommitHash, 184 LastResultsHash: block.LastResultsHash, 185 }) 186 if err != nil { 187 return false, ErrInvalidBlock(err) 188 } 189 if resp.IsStatusUnknown() { 190 panic(fmt.Sprintf("ProcessProposal responded with status %s", resp.Status.String())) 191 } 192 193 return resp.IsAccepted(), nil 194 } 195 196 // ValidateBlock validates the given block against the given state. 197 // If the block is invalid, it returns an error. 198 // Validation does not mutate state, but does require historical information from the stateDB, 199 // ie. to verify evidence from a validator at an old height. 200 func (blockExec *BlockExecutor) ValidateBlock(ctx context.Context, state State, block *types.Block) error { 201 hash := block.Hash() 202 if _, ok := blockExec.cache[hash.String()]; ok { 203 return nil 204 } 205 206 err := validateBlock(state, block) 207 if err != nil { 208 return err 209 } 210 211 err = blockExec.evpool.CheckEvidence(ctx, block.Evidence) 212 if err != nil { 213 return err 214 } 215 216 blockExec.cache[hash.String()] = struct{}{} 217 return nil 218 } 219 220 // ApplyBlock validates the block against the state, executes it against the app, 221 // fires the relevant events, commits the app, and saves the new state and responses. 222 // It returns the new state. 223 // It's the only function that needs to be called 224 // from outside this package to process and commit an entire block. 225 // It takes a blockID to avoid recomputing the parts hash. 226 func (blockExec *BlockExecutor) ApplyBlock( 227 ctx context.Context, 228 state State, 229 blockID types.BlockID, block *types.Block, tracer otrace.Tracer) (State, error) { 230 if tracer != nil { 231 spanCtx, span := tracer.Start(ctx, "cs.state.ApplyBlock") 232 ctx = spanCtx 233 defer span.End() 234 } 235 // validate the block if we haven't already 236 if err := blockExec.ValidateBlock(ctx, state, block); err != nil { 237 return state, ErrInvalidBlock(err) 238 } 239 startTime := time.Now() 240 defer func() { 241 blockExec.metrics.BlockProcessingTime.Observe(time.Since(startTime).Seconds()) 242 }() 243 var finalizeBlockSpan otrace.Span = nil 244 if tracer != nil { 245 _, finalizeBlockSpan = tracer.Start(ctx, "cs.state.ApplyBlock.FinalizeBlock") 246 defer finalizeBlockSpan.End() 247 } 248 txs := block.Data.Txs.ToSliceOfBytes() 249 fBlockRes, err := blockExec.appClient.FinalizeBlock( 250 ctx, 251 &abci.RequestFinalizeBlock{ 252 Hash: block.Hash(), 253 Height: block.Header.Height, 254 Time: block.Header.Time, 255 Txs: txs, 256 DecidedLastCommit: buildLastCommitInfo(block, blockExec.store, state.InitialHeight), 257 ByzantineValidators: block.Evidence.ToABCI(), 258 ProposerAddress: block.ProposerAddress, 259 NextValidatorsHash: block.NextValidatorsHash, 260 AppHash: block.AppHash, 261 ValidatorsHash: block.ValidatorsHash, 262 ConsensusHash: block.ConsensusHash, 263 DataHash: block.DataHash, 264 EvidenceHash: block.EvidenceHash, 265 LastBlockHash: block.LastBlockID.Hash, 266 LastBlockPartSetTotal: int64(block.LastBlockID.PartSetHeader.Total), 267 LastBlockPartSetHash: block.LastBlockID.Hash, 268 LastCommitHash: block.LastCommitHash, 269 LastResultsHash: block.LastResultsHash, 270 }, 271 ) 272 if finalizeBlockSpan != nil { 273 finalizeBlockSpan.End() 274 } 275 if err != nil { 276 return state, ErrProxyAppConn(err) 277 } 278 279 blockExec.logger.Info( 280 "finalized block", 281 "height", block.Height, 282 "latency_ms", time.Now().Sub(startTime).Milliseconds(), 283 "num_txs_res", len(fBlockRes.TxResults), 284 "num_val_updates", len(fBlockRes.ValidatorUpdates), 285 "block_app_hash", fmt.Sprintf("%X", fBlockRes.AppHash), 286 ) 287 288 // Save the results before we commit. 289 err = blockExec.store.SaveFinalizeBlockResponses(block.Height, fBlockRes) 290 if err != nil && !errors.Is(err, ErrNoFinalizeBlockResponsesForHeight{block.Height}) { 291 // It is correct to have an empty ResponseFinalizeBlock for ApplyBlock, 292 // but not for saving it to the state store 293 return state, err 294 } 295 296 // validate the validator updates and convert to tendermint types 297 err = validateValidatorUpdates(fBlockRes.ValidatorUpdates, state.ConsensusParams.Validator) 298 if err != nil { 299 return state, fmt.Errorf("error in validator updates: %w", err) 300 } 301 302 validatorUpdates, err := types.PB2TM.ValidatorUpdates(fBlockRes.ValidatorUpdates) 303 if err != nil { 304 return state, err 305 } 306 if len(validatorUpdates) > 0 { 307 blockExec.logger.Debug("updates to validators", "updates", types.ValidatorListString(validatorUpdates)) 308 blockExec.metrics.ValidatorSetUpdates.Add(1) 309 } 310 if fBlockRes.ConsensusParamUpdates != nil { 311 blockExec.metrics.ConsensusParamUpdates.Add(1) 312 } 313 314 // Update the state with the block and responses. 315 rs, err := abci.MarshalTxResults(fBlockRes.TxResults) 316 if err != nil { 317 return state, fmt.Errorf("marshaling TxResults: %w", err) 318 } 319 h := merkle.HashFromByteSlices(rs) 320 state, err = state.Update(blockID, &block.Header, h, fBlockRes.ConsensusParamUpdates, validatorUpdates) 321 if err != nil { 322 return state, fmt.Errorf("commit failed for application: %w", err) 323 } 324 325 var commitSpan otrace.Span = nil 326 if tracer != nil { 327 _, commitSpan = tracer.Start(ctx, "cs.state.ApplyBlock.Commit") 328 defer commitSpan.End() 329 } 330 // Lock mempool, commit app state, update mempoool. 331 retainHeight, err := blockExec.Commit(ctx, state, block, fBlockRes.TxResults) 332 if err != nil { 333 return state, fmt.Errorf("commit failed for application: %w", err) 334 } 335 if commitSpan != nil { 336 commitSpan.End() 337 } 338 339 // Update evpool with the latest state. 340 blockExec.evpool.Update(ctx, state, block.Evidence) 341 342 // Update the app hash and save the state. 343 state.AppHash = fBlockRes.AppHash 344 if err := blockExec.store.Save(state); err != nil { 345 return state, err 346 } 347 348 // Prune old heights, if requested by ABCI app. 349 if retainHeight > 0 { 350 pruned, err := blockExec.pruneBlocks(retainHeight) 351 if err != nil { 352 blockExec.logger.Error("failed to prune blocks", "retain_height", retainHeight, "err", err) 353 } else { 354 blockExec.logger.Debug("pruned blocks", "pruned", pruned, "retain_height", retainHeight) 355 } 356 } 357 358 // reset the verification cache 359 blockExec.cache = make(map[string]struct{}) 360 361 // Events are fired after everything else. 362 // NOTE: if we crash between Commit and Save, events wont be fired during replay 363 fireEvents(blockExec.logger, blockExec.eventBus, block, blockID, fBlockRes, validatorUpdates) 364 365 return state, nil 366 } 367 368 func (blockExec *BlockExecutor) ExtendVote(ctx context.Context, vote *types.Vote) ([]byte, error) { 369 resp, err := blockExec.appClient.ExtendVote(ctx, &abci.RequestExtendVote{ 370 Hash: vote.BlockID.Hash, 371 Height: vote.Height, 372 }) 373 if err != nil { 374 panic(fmt.Errorf("ExtendVote call failed: %w", err)) 375 } 376 return resp.VoteExtension, nil 377 } 378 379 func (blockExec *BlockExecutor) VerifyVoteExtension(ctx context.Context, vote *types.Vote) error { 380 resp, err := blockExec.appClient.VerifyVoteExtension(ctx, &abci.RequestVerifyVoteExtension{ 381 Hash: vote.BlockID.Hash, 382 ValidatorAddress: vote.ValidatorAddress, 383 Height: vote.Height, 384 VoteExtension: vote.Extension, 385 }) 386 if err != nil { 387 panic(fmt.Errorf("VerifyVoteExtension call failed: %w", err)) 388 } 389 390 if !resp.IsOK() { 391 return errors.New("invalid vote extension") 392 } 393 394 return nil 395 } 396 397 // Commit locks the mempool, runs the ABCI Commit message, and updates the 398 // mempool. 399 // It returns the result of calling abci.Commit (the AppHash) and the height to retain (if any). 400 // The Mempool must be locked during commit and update because state is 401 // typically reset on Commit and old txs must be replayed against committed 402 // state before new txs are run in the mempool, lest they be invalid. 403 func (blockExec *BlockExecutor) Commit( 404 ctx context.Context, 405 state State, 406 block *types.Block, 407 txResults []*abci.ExecTxResult, 408 ) (int64, error) { 409 blockExec.mempool.Lock() 410 defer blockExec.mempool.Unlock() 411 412 // while mempool is Locked, flush to ensure all async requests have completed 413 // in the ABCI app before Commit. 414 start := time.Now() 415 err := blockExec.mempool.FlushAppConn(ctx) 416 if err != nil { 417 blockExec.logger.Error("client error during mempool.FlushAppConn", "err", err) 418 return 0, err 419 } 420 blockExec.metrics.FlushAppConnectionTime.Observe(float64(time.Since(start))) 421 422 // Commit block, get hash back 423 start = time.Now() 424 res, err := blockExec.appClient.Commit(ctx) 425 if err != nil { 426 blockExec.logger.Error("client error during proxyAppConn.Commit", "err", err) 427 return 0, err 428 } 429 blockExec.metrics.ApplicationCommitTime.Observe(float64(time.Since(start))) 430 431 // ResponseCommit has no error code - just data 432 blockExec.logger.Info( 433 "committed state", 434 "height", block.Height, 435 "num_txs", len(block.Txs), 436 "block_app_hash", fmt.Sprintf("%X", block.AppHash), 437 "time", time.Now().UnixMilli(), 438 ) 439 440 // Update mempool. 441 start = time.Now() 442 err = blockExec.mempool.Update( 443 ctx, 444 block.Height, 445 block.Txs, 446 txResults, 447 TxPreCheckForState(state), 448 TxPostCheckForState(state), 449 state.ConsensusParams.ABCI.RecheckTx, 450 ) 451 blockExec.metrics.UpdateMempoolTime.Observe(float64(time.Since(start))) 452 453 return res.RetainHeight, err 454 } 455 456 func (blockExec *BlockExecutor) GetMissingTxs(txKeys []types.TxKey) []types.TxKey { 457 var missingTxKeys []types.TxKey 458 for _, txKey := range txKeys { 459 if !blockExec.mempool.HasTx(txKey) { 460 missingTxKeys = append(missingTxKeys, txKey) 461 } 462 } 463 return missingTxKeys 464 } 465 466 func (blockExec *BlockExecutor) CheckTxFromPeerProposal(ctx context.Context, tx types.Tx) { 467 // Ignore errors from CheckTx because there could be benign errors due to the same tx being 468 // inserted into the mempool from gossiping. Since such simultaneous insertion could result in 469 // multiple different kinds of errors, we will ignore them all here, and verify in the consensus 470 // state machine whether all txs in the proposal are present in the mempool at a later time. 471 if err := blockExec.mempool.CheckTx(ctx, tx, func(rct *abci.ResponseCheckTx) {}, mempool.TxInfo{ 472 SenderID: math.MaxUint16, 473 }); err != nil { 474 blockExec.logger.Info(fmt.Sprintf("CheckTx for proposal tx from peer raised error %s. This could be ignored if the error is because the tx is added to the mempool while this check was happening", err)) 475 } 476 } 477 478 func buildLastCommitInfo(block *types.Block, store Store, initialHeight int64) abci.CommitInfo { 479 if block.Height == initialHeight { 480 // there is no last commit for the initial height. 481 // return an empty value. 482 return abci.CommitInfo{} 483 } 484 485 lastValSet, err := store.LoadValidators(block.Height - 1) 486 if err != nil { 487 panic(fmt.Errorf("failed to load validator set at height %d: %w", block.Height-1, err)) 488 } 489 490 var ( 491 commitSize = block.LastCommit.Size() 492 valSetLen = len(lastValSet.Validators) 493 ) 494 495 // ensure that the size of the validator set in the last commit matches 496 // the size of the validator set in the state store. 497 if commitSize != valSetLen { 498 panic(fmt.Sprintf( 499 "commit size (%d) doesn't match validator set length (%d) at height %d\n\n%v\n\n%v", 500 commitSize, valSetLen, block.Height, block.LastCommit.Signatures, lastValSet.Validators, 501 )) 502 } 503 504 votes := make([]abci.VoteInfo, block.LastCommit.Size()) 505 for i, val := range lastValSet.Validators { 506 commitSig := block.LastCommit.Signatures[i] 507 votes[i] = abci.VoteInfo{ 508 Validator: types.TM2PB.Validator(val), 509 SignedLastBlock: commitSig.BlockIDFlag != types.BlockIDFlagAbsent, 510 } 511 } 512 513 return abci.CommitInfo{ 514 Round: block.LastCommit.Round, 515 Votes: votes, 516 } 517 } 518 519 // buildExtendedCommitInfo populates an ABCI extended commit from the 520 // corresponding Tendermint extended commit ec, using the stored validator set 521 // from ec. It requires ec to include the original precommit votes along with 522 // the vote extensions from the last commit. 523 // 524 // For heights below the initial height, for which we do not have the required 525 // data, it returns an empty record. 526 // 527 // Assumes that the commit signatures are sorted according to validator index. 528 func buildExtendedCommitInfo(ec *types.ExtendedCommit, store Store, initialHeight int64, ap types.ABCIParams) abci.ExtendedCommitInfo { 529 if ec.Height < initialHeight { 530 // There are no extended commits for heights below the initial height. 531 return abci.ExtendedCommitInfo{} 532 } 533 534 valSet, err := store.LoadValidators(ec.Height) 535 if err != nil { 536 panic(fmt.Errorf("failed to load validator set at height %d, initial height %d: %w", ec.Height, initialHeight, err)) 537 } 538 539 var ( 540 ecSize = ec.Size() 541 valSetLen = len(valSet.Validators) 542 ) 543 544 // Ensure that the size of the validator set in the extended commit matches 545 // the size of the validator set in the state store. 546 if ecSize != valSetLen { 547 panic(fmt.Errorf( 548 "extended commit size (%d) does not match validator set length (%d) at height %d\n\n%v\n\n%v", 549 ecSize, valSetLen, ec.Height, ec.ExtendedSignatures, valSet.Validators, 550 )) 551 } 552 553 votes := make([]abci.ExtendedVoteInfo, ecSize) 554 for i, val := range valSet.Validators { 555 ecs := ec.ExtendedSignatures[i] 556 557 // Absent signatures have empty validator addresses, but otherwise we 558 // expect the validator addresses to be the same. 559 if ecs.BlockIDFlag != types.BlockIDFlagAbsent && !bytes.Equal(ecs.ValidatorAddress, val.Address) { 560 panic(fmt.Errorf("validator address of extended commit signature in position %d (%s) does not match the corresponding validator's at height %d (%s)", 561 i, ecs.ValidatorAddress, ec.Height, val.Address, 562 )) 563 } 564 565 var ext []byte 566 // Check if vote extensions were enabled during the commit's height: ec.Height. 567 // ec is the commit from the previous height, so if extensions were enabled 568 // during that height, we ensure they are present and deliver the data to 569 // the proposer. If they were not enabled during this previous height, we 570 // will not deliver extension data. 571 if ap.VoteExtensionsEnabled(ec.Height) && ecs.BlockIDFlag == types.BlockIDFlagCommit { 572 if err := ecs.EnsureExtension(); err != nil { 573 panic(fmt.Errorf("commit at height %d received with missing vote extensions data", ec.Height)) 574 } 575 ext = ecs.Extension 576 } 577 578 votes[i] = abci.ExtendedVoteInfo{ 579 Validator: types.TM2PB.Validator(val), 580 SignedLastBlock: ecs.BlockIDFlag != types.BlockIDFlagAbsent, 581 VoteExtension: ext, 582 } 583 } 584 585 return abci.ExtendedCommitInfo{ 586 Round: ec.Round, 587 Votes: votes, 588 } 589 } 590 591 func validateValidatorUpdates(abciUpdates []abci.ValidatorUpdate, 592 params types.ValidatorParams) error { 593 for _, valUpdate := range abciUpdates { 594 if valUpdate.GetPower() < 0 { 595 return fmt.Errorf("voting power can't be negative %v", valUpdate) 596 } else if valUpdate.GetPower() == 0 { 597 // continue, since this is deleting the validator, and thus there is no 598 // pubkey to check 599 continue 600 } 601 602 // Check if validator's pubkey matches an ABCI type in the consensus params 603 pk, err := encoding.PubKeyFromProto(valUpdate.PubKey) 604 if err != nil { 605 return err 606 } 607 608 if !params.IsValidPubkeyType(pk.Type()) { 609 return fmt.Errorf("validator %v is using pubkey %s, which is unsupported for consensus", 610 valUpdate, pk.Type()) 611 } 612 } 613 return nil 614 } 615 616 // Update returns a copy of state with the fields set using the arguments passed in. 617 func (state State) Update( 618 blockID types.BlockID, 619 header *types.Header, 620 resultsHash []byte, 621 consensusParamUpdates *tmtypes.ConsensusParams, 622 validatorUpdates []*types.Validator, 623 ) (State, error) { 624 625 // Copy the valset so we can apply changes from FinalizeBlock 626 // and update s.LastValidators and s.Validators. 627 nValSet := state.NextValidators.Copy() 628 629 // Update the validator set with the latest responses to FinalizeBlock. 630 lastHeightValsChanged := state.LastHeightValidatorsChanged 631 if len(validatorUpdates) > 0 { 632 err := nValSet.UpdateWithChangeSet(validatorUpdates) 633 if err != nil { 634 return state, fmt.Errorf("changing validator set: %w", err) 635 } 636 // Change results from this height but only applies to the next next height. 637 lastHeightValsChanged = header.Height + 1 + 1 638 } 639 640 // Update validator proposer priority and set state variables. 641 nValSet.IncrementProposerPriority(1) 642 643 // Update the params with the latest responses to FinalizeBlock. 644 nextParams := state.ConsensusParams 645 lastHeightParamsChanged := state.LastHeightConsensusParamsChanged 646 if consensusParamUpdates != nil { 647 // NOTE: must not mutate state.ConsensusParams 648 nextParams = state.ConsensusParams.UpdateConsensusParams(consensusParamUpdates) 649 err := nextParams.ValidateConsensusParams() 650 if err != nil { 651 return state, fmt.Errorf("updating consensus params: %w", err) 652 } 653 654 err = state.ConsensusParams.ValidateUpdate(consensusParamUpdates, header.Height) 655 if err != nil { 656 return state, fmt.Errorf("updating consensus params: %w", err) 657 } 658 659 state.Version.Consensus.App = nextParams.Version.AppVersion 660 661 // Change results from this height but only applies to the next height. 662 lastHeightParamsChanged = header.Height + 1 663 } 664 665 nextVersion := state.Version 666 667 // NOTE: the AppHash and the VoteExtension has not been populated. 668 // It will be filled on state.Save. 669 return State{ 670 Version: nextVersion, 671 ChainID: state.ChainID, 672 InitialHeight: state.InitialHeight, 673 LastBlockHeight: header.Height, 674 LastBlockID: blockID, 675 LastBlockTime: header.Time, 676 NextValidators: nValSet, 677 Validators: state.NextValidators.Copy(), 678 LastValidators: state.Validators.Copy(), 679 LastHeightValidatorsChanged: lastHeightValsChanged, 680 ConsensusParams: nextParams, 681 LastHeightConsensusParamsChanged: lastHeightParamsChanged, 682 LastResultsHash: resultsHash, 683 AppHash: nil, 684 }, nil 685 } 686 687 // Fire NewBlock, NewBlockHeader. 688 // Fire TxEvent for every tx. 689 // NOTE: if Tendermint crashes before commit, some or all of these events may be published again. 690 func fireEvents( 691 logger log.Logger, 692 eventBus types.BlockEventPublisher, 693 block *types.Block, 694 blockID types.BlockID, 695 finalizeBlockResponse *abci.ResponseFinalizeBlock, 696 validatorUpdates []*types.Validator, 697 ) { 698 if err := eventBus.PublishEventNewBlock(types.EventDataNewBlock{ 699 Block: block, 700 BlockID: blockID, 701 ResultFinalizeBlock: *finalizeBlockResponse, 702 }); err != nil { 703 logger.Error("failed publishing new block", "err", err) 704 } 705 706 if err := eventBus.PublishEventNewBlockHeader(types.EventDataNewBlockHeader{ 707 Header: block.Header, 708 NumTxs: int64(len(block.Txs)), 709 ResultFinalizeBlock: *finalizeBlockResponse, 710 }); err != nil { 711 logger.Error("failed publishing new block header", "err", err) 712 } 713 714 if len(block.Evidence) != 0 { 715 for _, ev := range block.Evidence { 716 if err := eventBus.PublishEventNewEvidence(types.EventDataNewEvidence{ 717 Evidence: ev, 718 Height: block.Height, 719 }); err != nil { 720 logger.Error("failed publishing new evidence", "err", err) 721 } 722 } 723 } 724 725 // sanity check 726 if len(finalizeBlockResponse.TxResults) != len(block.Data.Txs) { 727 panic(fmt.Sprintf("number of TXs (%d) and ABCI TX responses (%d) do not match", 728 len(block.Data.Txs), len(finalizeBlockResponse.TxResults))) 729 } 730 731 for i, tx := range block.Data.Txs { 732 if err := eventBus.PublishEventTx(types.EventDataTx{ 733 TxResult: abci.TxResult{ 734 Height: block.Height, 735 Index: uint32(i), 736 Tx: tx, 737 Result: *(finalizeBlockResponse.TxResults[i]), 738 }, 739 }); err != nil { 740 logger.Error("failed publishing event TX", "err", err) 741 } 742 } 743 744 if len(finalizeBlockResponse.ValidatorUpdates) > 0 { 745 if err := eventBus.PublishEventValidatorSetUpdates( 746 types.EventDataValidatorSetUpdates{ValidatorUpdates: validatorUpdates}); err != nil { 747 logger.Error("failed publishing event", "err", err) 748 } 749 } 750 } 751 752 //---------------------------------------------------------------------------------------------------- 753 // Execute block without state. TODO: eliminate 754 755 // ExecCommitBlock executes and commits a block on the proxyApp without validating or mutating the state. 756 // It returns the application root hash (result of abci.Commit). 757 func ExecCommitBlock( 758 ctx context.Context, 759 be *BlockExecutor, 760 appConn abciclient.Client, 761 block *types.Block, 762 logger log.Logger, 763 store Store, 764 initialHeight int64, 765 s State, 766 ) ([]byte, error) { 767 finalizeBlockResponse, err := appConn.FinalizeBlock( 768 ctx, 769 &abci.RequestFinalizeBlock{ 770 Hash: block.Hash(), 771 Height: block.Height, 772 Time: block.Time, 773 Txs: block.Txs.ToSliceOfBytes(), 774 DecidedLastCommit: buildLastCommitInfo(block, store, initialHeight), 775 ByzantineValidators: block.Evidence.ToABCI(), 776 AppHash: block.AppHash, 777 ValidatorsHash: block.ValidatorsHash, 778 ConsensusHash: block.ConsensusHash, 779 DataHash: block.DataHash, 780 EvidenceHash: block.EvidenceHash, 781 LastBlockHash: block.LastBlockID.Hash, 782 LastBlockPartSetTotal: int64(block.LastBlockID.PartSetHeader.Total), 783 LastBlockPartSetHash: block.LastBlockID.Hash, 784 LastCommitHash: block.LastCommitHash, 785 LastResultsHash: block.LastResultsHash, 786 }, 787 ) 788 789 if err != nil { 790 logger.Error("executing block", "err", err) 791 return nil, err 792 } 793 logger.Info("executed block", "height", block.Height) 794 795 // the BlockExecutor condition is using for the final block replay process. 796 if be != nil { 797 err = validateValidatorUpdates(finalizeBlockResponse.ValidatorUpdates, s.ConsensusParams.Validator) 798 if err != nil { 799 logger.Error("validating validator updates", "err", err) 800 return nil, err 801 } 802 validatorUpdates, err := types.PB2TM.ValidatorUpdates(finalizeBlockResponse.ValidatorUpdates) 803 if err != nil { 804 logger.Error("converting validator updates to native types", "err", err) 805 return nil, err 806 } 807 808 bps, err := block.MakePartSet(types.BlockPartSizeBytes) 809 if err != nil { 810 return nil, err 811 } 812 813 blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} 814 fireEvents(be.logger, be.eventBus, block, blockID, finalizeBlockResponse, validatorUpdates) 815 } 816 817 // Commit block 818 _, err = appConn.Commit(ctx) 819 if err != nil { 820 logger.Error("client error during proxyAppConn.Commit", "err", err) 821 return nil, err 822 } 823 824 // ResponseCommit has no error or log 825 return finalizeBlockResponse.AppHash, nil 826 } 827 828 func (blockExec *BlockExecutor) pruneBlocks(retainHeight int64) (uint64, error) { 829 base := blockExec.blockStore.Base() 830 if retainHeight <= base { 831 return 0, nil 832 } 833 pruned, err := blockExec.blockStore.PruneBlocks(retainHeight) 834 if err != nil { 835 return 0, fmt.Errorf("failed to prune block store: %w", err) 836 } 837 838 err = blockExec.Store().PruneStates(retainHeight) 839 if err != nil { 840 return 0, fmt.Errorf("failed to prune state store: %w", err) 841 } 842 return pruned, nil 843 }