bitbucket.org/number571/tendermint@v0.8.14/state/execution.go (about) 1 package state 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "time" 8 9 abci "bitbucket.org/number571/tendermint/abci/types" 10 cryptoenc "bitbucket.org/number571/tendermint/crypto/encoding" 11 "bitbucket.org/number571/tendermint/internal/libs/fail" 12 mempl "bitbucket.org/number571/tendermint/internal/mempool" 13 "bitbucket.org/number571/tendermint/libs/log" 14 tmstate "bitbucket.org/number571/tendermint/proto/tendermint/state" 15 "bitbucket.org/number571/tendermint/proxy" 16 "bitbucket.org/number571/tendermint/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 mempl.Mempool 41 evpool EvidencePool 42 43 logger log.Logger 44 metrics *Metrics 45 46 // cache the verification results over a single height 47 cache map[string]struct{} 48 } 49 50 type BlockExecutorOption func(executor *BlockExecutor) 51 52 func BlockExecutorWithMetrics(metrics *Metrics) BlockExecutorOption { 53 return func(blockExec *BlockExecutor) { 54 blockExec.metrics = metrics 55 } 56 } 57 58 // NewBlockExecutor returns a new BlockExecutor with a NopEventBus. 59 // Call SetEventBus to provide one. 60 func NewBlockExecutor( 61 stateStore Store, 62 logger log.Logger, 63 proxyApp proxy.AppConnConsensus, 64 mempool mempl.Mempool, 65 evpool EvidencePool, 66 blockStore BlockStore, 67 options ...BlockExecutorOption, 68 ) *BlockExecutor { 69 res := &BlockExecutor{ 70 store: stateStore, 71 proxyApp: proxyApp, 72 eventBus: types.NopEventBus{}, 73 mempool: mempool, 74 evpool: evpool, 75 logger: logger, 76 metrics: NopMetrics(), 77 cache: make(map[string]struct{}), 78 blockStore: blockStore, 79 } 80 81 for _, option := range options { 82 option(res) 83 } 84 85 return res 86 } 87 88 func (blockExec *BlockExecutor) Store() Store { 89 return blockExec.store 90 } 91 92 // SetEventBus - sets the event bus for publishing block related events. 93 // If not called, it defaults to types.NopEventBus. 94 func (blockExec *BlockExecutor) SetEventBus(eventBus types.BlockEventPublisher) { 95 blockExec.eventBus = eventBus 96 } 97 98 // CreateProposalBlock calls state.MakeBlock with evidence from the evpool 99 // and txs from the mempool. The max bytes must be big enough to fit the commit. 100 // Up to 1/10th of the block space is allcoated for maximum sized evidence. 101 // The rest is given to txs, up to the max gas. 102 func (blockExec *BlockExecutor) CreateProposalBlock( 103 height int64, 104 state State, commit *types.Commit, 105 proposerAddr []byte, 106 ) (*types.Block, *types.PartSet) { 107 108 maxBytes := state.ConsensusParams.Block.MaxBytes 109 maxGas := state.ConsensusParams.Block.MaxGas 110 111 evidence, evSize := blockExec.evpool.PendingEvidence(state.ConsensusParams.Evidence.MaxBytes) 112 113 // Fetch a limited amount of valid txs 114 maxDataBytes := types.MaxDataBytes(maxBytes, evSize, state.Validators.Size()) 115 116 txs := blockExec.mempool.ReapMaxBytesMaxGas(maxDataBytes, maxGas) 117 118 return state.MakeBlock(height, txs, commit, evidence, proposerAddr) 119 } 120 121 // ValidateBlock validates the given block against the given state. 122 // If the block is invalid, it returns an error. 123 // Validation does not mutate state, but does require historical information from the stateDB, 124 // ie. to verify evidence from a validator at an old height. 125 func (blockExec *BlockExecutor) ValidateBlock(state State, block *types.Block) error { 126 hash := block.Hash() 127 if _, ok := blockExec.cache[hash.String()]; ok { 128 return nil 129 } 130 131 err := validateBlock(state, block) 132 if err != nil { 133 return err 134 } 135 136 err = blockExec.evpool.CheckEvidence(block.Evidence.Evidence) 137 if err != nil { 138 return err 139 } 140 141 blockExec.cache[hash.String()] = struct{}{} 142 return nil 143 } 144 145 // ApplyBlock validates the block against the state, executes it against the app, 146 // fires the relevant events, commits the app, and saves the new state and responses. 147 // It returns the new state. 148 // It's the only function that needs to be called 149 // from outside this package to process and commit an entire block. 150 // It takes a blockID to avoid recomputing the parts hash. 151 func (blockExec *BlockExecutor) ApplyBlock( 152 state State, blockID types.BlockID, block *types.Block, 153 ) (State, error) { 154 155 // validate the block if we haven't already 156 if err := blockExec.ValidateBlock(state, block); err != nil { 157 return state, ErrInvalidBlock(err) 158 } 159 160 startTime := time.Now().UnixNano() 161 abciResponses, err := execBlockOnProxyApp( 162 blockExec.logger, blockExec.proxyApp, block, blockExec.store, state.InitialHeight, 163 ) 164 endTime := time.Now().UnixNano() 165 blockExec.metrics.BlockProcessingTime.Observe(float64(endTime-startTime) / 1000000) 166 if err != nil { 167 return state, ErrProxyAppConn(err) 168 } 169 170 fail.Fail() // XXX 171 172 // Save the results before we commit. 173 if err := blockExec.store.SaveABCIResponses(block.Height, abciResponses); err != nil { 174 return state, err 175 } 176 177 fail.Fail() // XXX 178 179 // validate the validator updates and convert to tendermint types 180 abciValUpdates := abciResponses.EndBlock.ValidatorUpdates 181 err = validateValidatorUpdates(abciValUpdates, state.ConsensusParams.Validator) 182 if err != nil { 183 return state, fmt.Errorf("error in validator updates: %v", err) 184 } 185 186 validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciValUpdates) 187 if err != nil { 188 return state, err 189 } 190 if len(validatorUpdates) > 0 { 191 blockExec.logger.Debug("updates to validators", "updates", types.ValidatorListString(validatorUpdates)) 192 } 193 194 // Update the state with the block and responses. 195 state, err = updateState(state, blockID, &block.Header, abciResponses, validatorUpdates) 196 if err != nil { 197 return state, fmt.Errorf("commit failed for application: %v", err) 198 } 199 200 // Lock mempool, commit app state, update mempoool. 201 appHash, retainHeight, err := blockExec.Commit(state, block, abciResponses.DeliverTxs) 202 if err != nil { 203 return state, fmt.Errorf("commit failed for application: %v", err) 204 } 205 206 // Update evpool with the latest state. 207 blockExec.evpool.Update(state, block.Evidence.Evidence) 208 209 fail.Fail() // XXX 210 211 // Update the app hash and save the state. 212 state.AppHash = appHash 213 if err := blockExec.store.Save(state); err != nil { 214 return state, err 215 } 216 217 fail.Fail() // XXX 218 219 // Prune old heights, if requested by ABCI app. 220 if retainHeight > 0 { 221 pruned, err := blockExec.pruneBlocks(retainHeight) 222 if err != nil { 223 blockExec.logger.Error("failed to prune blocks", "retain_height", retainHeight, "err", err) 224 } else { 225 blockExec.logger.Debug("pruned blocks", "pruned", pruned, "retain_height", retainHeight) 226 } 227 } 228 229 // reset the verification cache 230 blockExec.cache = make(map[string]struct{}) 231 232 // Events are fired after everything else. 233 // NOTE: if we crash between Commit and Save, events wont be fired during replay 234 fireEvents(blockExec.logger, blockExec.eventBus, block, blockID, abciResponses, validatorUpdates) 235 236 return state, nil 237 } 238 239 // Commit locks the mempool, runs the ABCI Commit message, and updates the 240 // mempool. 241 // It returns the result of calling abci.Commit (the AppHash) and the height to retain (if any). 242 // The Mempool must be locked during commit and update because state is 243 // typically reset on Commit and old txs must be replayed against committed 244 // state before new txs are run in the mempool, lest they be invalid. 245 func (blockExec *BlockExecutor) Commit( 246 state State, 247 block *types.Block, 248 deliverTxResponses []*abci.ResponseDeliverTx, 249 ) ([]byte, int64, error) { 250 blockExec.mempool.Lock() 251 defer blockExec.mempool.Unlock() 252 253 // while mempool is Locked, flush to ensure all async requests have completed 254 // in the ABCI app before Commit. 255 err := blockExec.mempool.FlushAppConn() 256 if err != nil { 257 blockExec.logger.Error("client error during mempool.FlushAppConn", "err", err) 258 return nil, 0, err 259 } 260 261 // Commit block, get hash back 262 res, err := blockExec.proxyApp.CommitSync(context.Background()) 263 if err != nil { 264 blockExec.logger.Error("client error during proxyAppConn.CommitSync", "err", err) 265 return nil, 0, err 266 } 267 268 // ResponseCommit has no error code - just data 269 blockExec.logger.Info( 270 "committed state", 271 "height", block.Height, 272 "num_txs", len(block.Txs), 273 "app_hash", fmt.Sprintf("%X", res.Data), 274 ) 275 276 // Update mempool. 277 err = blockExec.mempool.Update( 278 block.Height, 279 block.Txs, 280 deliverTxResponses, 281 TxPreCheck(state), 282 TxPostCheck(state), 283 ) 284 285 return res.Data, res.RetainHeight, err 286 } 287 288 //--------------------------------------------------------- 289 // Helper functions for executing blocks and updating state 290 291 // Executes block's transactions on proxyAppConn. 292 // Returns a list of transaction results and updates to the validator set 293 func execBlockOnProxyApp( 294 logger log.Logger, 295 proxyAppConn proxy.AppConnConsensus, 296 block *types.Block, 297 store Store, 298 initialHeight int64, 299 ) (*tmstate.ABCIResponses, error) { 300 var validTxs, invalidTxs = 0, 0 301 302 txIndex := 0 303 abciResponses := new(tmstate.ABCIResponses) 304 dtxs := make([]*abci.ResponseDeliverTx, len(block.Txs)) 305 abciResponses.DeliverTxs = dtxs 306 307 // Execute transactions and get hash. 308 proxyCb := func(req *abci.Request, res *abci.Response) { 309 if r, ok := res.Value.(*abci.Response_DeliverTx); ok { 310 // TODO: make use of res.Log 311 // TODO: make use of this info 312 // Blocks may include invalid txs. 313 txRes := r.DeliverTx 314 if txRes.Code == abci.CodeTypeOK { 315 validTxs++ 316 } else { 317 logger.Debug("invalid tx", "code", txRes.Code, "log", txRes.Log) 318 invalidTxs++ 319 } 320 321 abciResponses.DeliverTxs[txIndex] = txRes 322 txIndex++ 323 } 324 } 325 proxyAppConn.SetResponseCallback(proxyCb) 326 327 commitInfo := getBeginBlockValidatorInfo(block, store, initialHeight) 328 329 byzVals := make([]abci.Evidence, 0) 330 for _, evidence := range block.Evidence.Evidence { 331 byzVals = append(byzVals, evidence.ABCI()...) 332 } 333 334 ctx := context.Background() 335 336 // Begin block 337 var err error 338 pbh := block.Header.ToProto() 339 if pbh == nil { 340 return nil, errors.New("nil header") 341 } 342 343 abciResponses.BeginBlock, err = proxyAppConn.BeginBlockSync( 344 ctx, 345 abci.RequestBeginBlock{ 346 Hash: block.Hash(), 347 Header: *pbh, 348 LastCommitInfo: commitInfo, 349 ByzantineValidators: byzVals, 350 }, 351 ) 352 if err != nil { 353 logger.Error("error in proxyAppConn.BeginBlock", "err", err) 354 return nil, err 355 } 356 357 // run txs of block 358 for _, tx := range block.Txs { 359 _, err = proxyAppConn.DeliverTxAsync(ctx, abci.RequestDeliverTx{Tx: tx}) 360 if err != nil { 361 return nil, err 362 } 363 } 364 365 abciResponses.EndBlock, err = proxyAppConn.EndBlockSync(ctx, abci.RequestEndBlock{Height: block.Height}) 366 if err != nil { 367 logger.Error("error in proxyAppConn.EndBlock", "err", err) 368 return nil, err 369 } 370 371 logger.Info("executed block", "height", block.Height, "num_valid_txs", validTxs, "num_invalid_txs", invalidTxs) 372 return abciResponses, nil 373 } 374 375 func getBeginBlockValidatorInfo(block *types.Block, store Store, 376 initialHeight int64) abci.LastCommitInfo { 377 voteInfos := make([]abci.VoteInfo, block.LastCommit.Size()) 378 // Initial block -> LastCommitInfo.Votes are empty. 379 // Remember that the first LastCommit is intentionally empty, so it makes 380 // sense for LastCommitInfo.Votes to also be empty. 381 if block.Height > initialHeight { 382 lastValSet, err := store.LoadValidators(block.Height - 1) 383 if err != nil { 384 panic(err) 385 } 386 387 // Sanity check that commit size matches validator set size - only applies 388 // after first block. 389 var ( 390 commitSize = block.LastCommit.Size() 391 valSetLen = len(lastValSet.Validators) 392 ) 393 if commitSize != valSetLen { 394 panic(fmt.Sprintf( 395 "commit size (%d) doesn't match valset length (%d) at height %d\n\n%v\n\n%v", 396 commitSize, valSetLen, block.Height, block.LastCommit.Signatures, lastValSet.Validators, 397 )) 398 } 399 400 for i, val := range lastValSet.Validators { 401 commitSig := block.LastCommit.Signatures[i] 402 voteInfos[i] = abci.VoteInfo{ 403 Validator: types.TM2PB.Validator(val), 404 SignedLastBlock: !commitSig.Absent(), 405 } 406 } 407 } 408 409 return abci.LastCommitInfo{ 410 Round: block.LastCommit.Round, 411 Votes: voteInfos, 412 } 413 } 414 415 func validateValidatorUpdates(abciUpdates []abci.ValidatorUpdate, 416 params types.ValidatorParams) error { 417 for _, valUpdate := range abciUpdates { 418 if valUpdate.GetPower() < 0 { 419 return fmt.Errorf("voting power can't be negative %v", valUpdate) 420 } else if valUpdate.GetPower() == 0 { 421 // continue, since this is deleting the validator, and thus there is no 422 // pubkey to check 423 continue 424 } 425 426 // Check if validator's pubkey matches an ABCI type in the consensus params 427 pk, err := cryptoenc.PubKeyFromProto(valUpdate.PubKey) 428 if err != nil { 429 return err 430 } 431 432 if !params.IsValidPubkeyType(pk.Type()) { 433 return fmt.Errorf("validator %v is using pubkey %s, which is unsupported for consensus", 434 valUpdate, pk.Type()) 435 } 436 } 437 return nil 438 } 439 440 // updateState returns a new State updated according to the header and responses. 441 func updateState( 442 state State, 443 blockID types.BlockID, 444 header *types.Header, 445 abciResponses *tmstate.ABCIResponses, 446 validatorUpdates []*types.Validator, 447 ) (State, error) { 448 449 // Copy the valset so we can apply changes from EndBlock 450 // and update s.LastValidators and s.Validators. 451 nValSet := state.NextValidators.Copy() 452 453 // Update the validator set with the latest abciResponses. 454 lastHeightValsChanged := state.LastHeightValidatorsChanged 455 if len(validatorUpdates) > 0 { 456 err := nValSet.UpdateWithChangeSet(validatorUpdates) 457 if err != nil { 458 return state, fmt.Errorf("error changing validator set: %v", err) 459 } 460 // Change results from this height but only applies to the next next height. 461 lastHeightValsChanged = header.Height + 1 + 1 462 } 463 464 // Update validator proposer priority and set state variables. 465 nValSet.IncrementProposerPriority(1) 466 467 // Update the params with the latest abciResponses. 468 nextParams := state.ConsensusParams 469 lastHeightParamsChanged := state.LastHeightConsensusParamsChanged 470 if abciResponses.EndBlock.ConsensusParamUpdates != nil { 471 // NOTE: must not mutate s.ConsensusParams 472 nextParams = state.ConsensusParams.UpdateConsensusParams(abciResponses.EndBlock.ConsensusParamUpdates) 473 err := nextParams.ValidateConsensusParams() 474 if err != nil { 475 return state, fmt.Errorf("error updating consensus params: %v", err) 476 } 477 478 state.Version.Consensus.App = nextParams.Version.AppVersion 479 480 // Change results from this height but only applies to the next height. 481 lastHeightParamsChanged = header.Height + 1 482 } 483 484 nextVersion := state.Version 485 486 // NOTE: the AppHash has not been populated. 487 // It will be filled on state.Save. 488 return State{ 489 Version: nextVersion, 490 ChainID: state.ChainID, 491 InitialHeight: state.InitialHeight, 492 LastBlockHeight: header.Height, 493 LastBlockID: blockID, 494 LastBlockTime: header.Time, 495 NextValidators: nValSet, 496 Validators: state.NextValidators.Copy(), 497 LastValidators: state.Validators.Copy(), 498 LastHeightValidatorsChanged: lastHeightValsChanged, 499 ConsensusParams: nextParams, 500 LastHeightConsensusParamsChanged: lastHeightParamsChanged, 501 LastResultsHash: ABCIResponsesResultsHash(abciResponses), 502 AppHash: nil, 503 }, nil 504 } 505 506 // Fire NewBlock, NewBlockHeader. 507 // Fire TxEvent for every tx. 508 // NOTE: if Tendermint crashes before commit, some or all of these events may be published again. 509 func fireEvents( 510 logger log.Logger, 511 eventBus types.BlockEventPublisher, 512 block *types.Block, 513 blockID types.BlockID, 514 abciResponses *tmstate.ABCIResponses, 515 validatorUpdates []*types.Validator, 516 ) { 517 if err := eventBus.PublishEventNewBlock(types.EventDataNewBlock{ 518 Block: block, 519 BlockID: blockID, 520 ResultBeginBlock: *abciResponses.BeginBlock, 521 ResultEndBlock: *abciResponses.EndBlock, 522 }); err != nil { 523 logger.Error("failed publishing new block", "err", err) 524 } 525 526 if err := eventBus.PublishEventNewBlockHeader(types.EventDataNewBlockHeader{ 527 Header: block.Header, 528 NumTxs: int64(len(block.Txs)), 529 ResultBeginBlock: *abciResponses.BeginBlock, 530 ResultEndBlock: *abciResponses.EndBlock, 531 }); err != nil { 532 logger.Error("failed publishing new block header", "err", err) 533 } 534 535 if len(block.Evidence.Evidence) != 0 { 536 for _, ev := range block.Evidence.Evidence { 537 if err := eventBus.PublishEventNewEvidence(types.EventDataNewEvidence{ 538 Evidence: ev, 539 Height: block.Height, 540 }); err != nil { 541 logger.Error("failed publishing new evidence", "err", err) 542 } 543 } 544 } 545 546 for i, tx := range block.Data.Txs { 547 if err := eventBus.PublishEventTx(types.EventDataTx{TxResult: abci.TxResult{ 548 Height: block.Height, 549 Index: uint32(i), 550 Tx: tx, 551 Result: *(abciResponses.DeliverTxs[i]), 552 }}); err != nil { 553 logger.Error("failed publishing event TX", "err", err) 554 } 555 } 556 557 if len(validatorUpdates) > 0 { 558 if err := eventBus.PublishEventValidatorSetUpdates( 559 types.EventDataValidatorSetUpdates{ValidatorUpdates: validatorUpdates}); err != nil { 560 logger.Error("failed publishing event", "err", err) 561 } 562 } 563 } 564 565 //---------------------------------------------------------------------------------------------------- 566 // Execute block without state. TODO: eliminate 567 568 // ExecCommitBlock executes and commits a block on the proxyApp without validating or mutating the state. 569 // It returns the application root hash (result of abci.Commit). 570 func ExecCommitBlock( 571 be *BlockExecutor, 572 appConnConsensus proxy.AppConnConsensus, 573 block *types.Block, 574 logger log.Logger, 575 store Store, 576 initialHeight int64, 577 s State, 578 ) ([]byte, error) { 579 abciResponses, err := execBlockOnProxyApp(logger, appConnConsensus, block, store, initialHeight) 580 if err != nil { 581 logger.Error("failed executing block on proxy app", "height", block.Height, "err", err) 582 return nil, err 583 } 584 585 // the BlockExecutor condition is using for the final block replay process. 586 if be != nil { 587 abciValUpdates := abciResponses.EndBlock.ValidatorUpdates 588 err = validateValidatorUpdates(abciValUpdates, s.ConsensusParams.Validator) 589 if err != nil { 590 logger.Error("err", err) 591 return nil, err 592 } 593 validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciValUpdates) 594 if err != nil { 595 logger.Error("err", err) 596 return nil, err 597 } 598 599 blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(types.BlockPartSizeBytes).Header()} 600 fireEvents(be.logger, be.eventBus, block, blockID, abciResponses, validatorUpdates) 601 } 602 603 // Commit block, get hash back 604 res, err := appConnConsensus.CommitSync(context.Background()) 605 if err != nil { 606 logger.Error("client error during proxyAppConn.CommitSync", "err", res) 607 return nil, err 608 } 609 610 // ResponseCommit has no error or log, just data 611 return res.Data, nil 612 } 613 614 func (blockExec *BlockExecutor) pruneBlocks(retainHeight int64) (uint64, error) { 615 base := blockExec.blockStore.Base() 616 if retainHeight <= base { 617 return 0, nil 618 } 619 pruned, err := blockExec.blockStore.PruneBlocks(retainHeight) 620 if err != nil { 621 return 0, fmt.Errorf("failed to prune block store: %w", err) 622 } 623 624 err = blockExec.Store().PruneStates(retainHeight) 625 if err != nil { 626 return 0, fmt.Errorf("failed to prune state store: %w", err) 627 } 628 return pruned, nil 629 }