github.com/okex/exchain@v1.8.0/libs/tendermint/state/execution.go (about) 1 package state 2 3 import ( 4 "fmt" 5 "strconv" 6 "time" 7 8 "github.com/okex/exchain/libs/system/trace" 9 abci "github.com/okex/exchain/libs/tendermint/abci/types" 10 cfg "github.com/okex/exchain/libs/tendermint/config" 11 "github.com/okex/exchain/libs/tendermint/global" 12 "github.com/okex/exchain/libs/tendermint/libs/automation" 13 "github.com/okex/exchain/libs/tendermint/libs/fail" 14 "github.com/okex/exchain/libs/tendermint/libs/log" 15 mempl "github.com/okex/exchain/libs/tendermint/mempool" 16 "github.com/okex/exchain/libs/tendermint/proxy" 17 "github.com/okex/exchain/libs/tendermint/types" 18 tmtime "github.com/okex/exchain/libs/tendermint/types/time" 19 dbm "github.com/okex/exchain/libs/tm-db" 20 "github.com/tendermint/go-amino" 21 ) 22 23 // ----------------------------------------------------------------------------- 24 type ( 25 // Enum mode for executing [deliverTx, ...] 26 DeliverTxsExecMode int 27 ) 28 29 const ( 30 DeliverTxsExecModeSerial DeliverTxsExecMode = iota // execute [deliverTx,...] sequentially 31 DeliverTxsExecModeParallel = 2 // execute [deliverTx,...] parallel 32 33 // There are two modes. 34 // 0: execute [deliverTx,...] sequentially (default) 35 // 1: execute [deliverTx,...] deprecated 36 // 2: execute [deliverTx,...] parallel 37 FlagDeliverTxsExecMode = "deliver-txs-mode" 38 FlagEnableConcurrency = "enable-concurrency" 39 ) 40 41 // BlockExecutor handles block execution and state updates. 42 // It exposes ApplyBlock(), which validates & executes the block, updates state w/ ABCI responses, 43 // then commits and updates the mempool atomically, then saves state. 44 45 // BlockExecutor provides the context and accessories for properly executing a block. 46 type BlockExecutor struct { 47 // save state, validators, consensus params, abci responses here 48 db dbm.DB 49 50 // execute the app against this 51 proxyApp proxy.AppConnConsensus 52 53 // events 54 eventBus types.BlockEventPublisher 55 56 // manage the mempool lock during commit 57 // and update both with block results after commit. 58 mempool mempl.Mempool 59 evpool EvidencePool 60 61 logger log.Logger 62 metrics *Metrics 63 64 // download or upload data to dds 65 deltaContext *DeltaContext 66 67 prerunCtx *prerunContext 68 69 isFastSync bool 70 71 // async save state, validators, consensus params, abci responses here 72 asyncDBContext 73 74 // the owner is validator 75 isNullIndexer bool 76 eventsChan chan event 77 } 78 79 type event struct { 80 block *types.Block 81 abciRsp *ABCIResponses 82 vals []*types.Validator 83 } 84 85 type BlockExecutorOption func(executor *BlockExecutor) 86 87 func BlockExecutorWithMetrics(metrics *Metrics) BlockExecutorOption { 88 return func(blockExec *BlockExecutor) { 89 blockExec.metrics = metrics 90 } 91 } 92 93 // NewBlockExecutor returns a new BlockExecutor with a NopEventBus. 94 // Call SetEventBus to provide one. 95 func NewBlockExecutor( 96 db dbm.DB, 97 logger log.Logger, 98 proxyApp proxy.AppConnConsensus, 99 mempool mempl.Mempool, 100 evpool EvidencePool, 101 options ...BlockExecutorOption, 102 ) *BlockExecutor { 103 res := &BlockExecutor{ 104 db: db, 105 proxyApp: proxyApp, 106 eventBus: types.NopEventBus{}, 107 mempool: mempool, 108 evpool: evpool, 109 logger: logger, 110 metrics: NopMetrics(), 111 prerunCtx: newPrerunContex(logger), 112 deltaContext: newDeltaContext(logger), 113 eventsChan: make(chan event, 5), 114 } 115 116 for _, option := range options { 117 option(res) 118 } 119 automation.LoadTestCase(logger) 120 res.deltaContext.init() 121 122 res.initAsyncDBContext() 123 124 return res 125 } 126 127 func (blockExec *BlockExecutor) fireEventsRountine() { 128 for et := range blockExec.eventsChan { 129 if et.block == nil { 130 break 131 } 132 fireEvents(blockExec.logger, blockExec.eventBus, et.block, et.abciRsp, et.vals) 133 } 134 blockExec.wg.Done() 135 } 136 137 func (blockExec *BlockExecutor) DB() dbm.DB { 138 return blockExec.db 139 } 140 141 func (blockExec *BlockExecutor) SetIsFastSyncing(isSyncing bool) { 142 blockExec.isFastSync = isSyncing 143 } 144 145 func (blockExec *BlockExecutor) SetIsNullIndexer(isNullIndexer bool) { 146 blockExec.isNullIndexer = isNullIndexer 147 } 148 149 func (blockExec *BlockExecutor) Stop() { 150 blockExec.stopAsyncDBContext() 151 } 152 153 // SetEventBus - sets the event bus for publishing block related events. 154 // If not called, it defaults to types.NopEventBus. 155 func (blockExec *BlockExecutor) SetEventBus(eventBus types.BlockEventPublisher) { 156 blockExec.eventBus = eventBus 157 blockExec.mempool.SetEventBus(eventBus) 158 } 159 160 // CreateProposalBlock calls state.MakeBlock with evidence from the evpool 161 // and txs from the mempool. The max bytes must be big enough to fit the commit. 162 // Up to 1/10th of the block space is allcoated for maximum sized evidence. 163 // The rest is given to txs, up to the max gas. 164 func (blockExec *BlockExecutor) CreateProposalBlock( 165 height int64, 166 state State, commit *types.Commit, 167 proposerAddr []byte, 168 ) (*types.Block, *types.PartSet) { 169 170 maxBytes := state.ConsensusParams.Block.MaxBytes 171 maxGas := state.ConsensusParams.Block.MaxGas 172 173 // Fetch a limited amount of valid evidence 174 maxNumEvidence, _ := types.MaxEvidencePerBlock(maxBytes) 175 evidence := blockExec.evpool.PendingEvidence(maxNumEvidence) 176 177 // Fetch a limited amount of valid txs 178 maxDataBytes := types.MaxDataBytes(maxBytes, state.Validators.Size(), len(evidence)) 179 if cfg.DynamicConfig.GetMaxGasUsedPerBlock() > -1 { 180 maxGas = cfg.DynamicConfig.GetMaxGasUsedPerBlock() 181 } 182 txs := blockExec.mempool.ReapMaxBytesMaxGas(maxDataBytes, maxGas) 183 184 return state.MakeBlock(height, txs, commit, evidence, proposerAddr) 185 } 186 187 // ValidateBlock validates the given block against the given state. 188 // If the block is invalid, it returns an error. 189 // Validation does not mutate state, but does require historical information from the stateDB, 190 // ie. to verify evidence from a validator at an old height. 191 func (blockExec *BlockExecutor) ValidateBlock(state State, block *types.Block) error { 192 if IgnoreSmbCheck { 193 // debug only 194 return nil 195 } 196 return validateBlock(blockExec.evpool, blockExec.db, state, block) 197 } 198 199 // ApplyBlock validates the block against the state, executes it against the app, 200 // fires the relevant events, commits the app, and saves the new state and responses. 201 // It returns the new state and the block height to retain (pruning older blocks). 202 // It's the only function that needs to be called 203 // from outside this package to process and commit an entire block. 204 // It takes a blockID to avoid recomputing the parts hash. 205 func (blockExec *BlockExecutor) ApplyBlock( 206 state State, blockID types.BlockID, block *types.Block) (State, int64, error) { 207 if ApplyBlockPprofTime >= 0 { 208 f, t := PprofStart() 209 defer PprofEnd(int(block.Height), f, t) 210 } 211 212 trc := trace.NewTracer(trace.ApplyBlock) 213 trc.EnableSummary() 214 trc.SetWorkloadStatistic(trace.GetApplyBlockWorkloadSttistic()) 215 dc := blockExec.deltaContext 216 217 defer func() { 218 trace.GetElapsedInfo().AddInfo(trace.Height, strconv.FormatInt(block.Height, 10)) 219 trace.GetElapsedInfo().AddInfo(trace.Tx, strconv.Itoa(len(block.Data.Txs))) 220 trace.GetElapsedInfo().AddInfo(trace.BlockSize, strconv.Itoa(block.FastSize())) 221 trace.GetElapsedInfo().AddInfo(trace.ApplyBlock, trc.Format()) 222 trace.GetElapsedInfo().AddInfo(trace.Workload, trace.GetApplyBlockWorkloadSttistic().Format()) 223 trace.GetElapsedInfo().SetElapsedTime(trc.GetElapsedTime()) 224 225 now := time.Now().UnixNano() 226 blockExec.metrics.IntervalTime.Set(float64(now-blockExec.metrics.lastBlockTime) / 1e6) 227 blockExec.metrics.lastBlockTime = now 228 blockExec.metrics.CommittedHeight.Set(float64(block.Height)) 229 }() 230 231 if err := blockExec.ValidateBlock(state, block); err != nil { 232 return state, 0, ErrInvalidBlock(err) 233 } 234 235 deltaInfo := dc.prepareStateDelta(block.Height) 236 237 trc.Pin(trace.Abci) 238 if cfg.DynamicConfig.GetEnablePGU() { 239 global.CommitLock() 240 defer global.CommitUnlock() 241 } 242 243 startTime := time.Now().UnixNano() 244 245 //wait till the last block async write be saved 246 blockExec.tryWaitLastBlockSave(block.Height - 1) 247 248 abciResponses, duration, err := blockExec.runAbci(block, deltaInfo) 249 250 // publish event 251 if types.EnableEventBlockTime { 252 blockExec.FireBlockTimeEvents(block.Height, len(block.Txs), true) 253 if !blockExec.isNullIndexer { 254 blockExec.eventsChan <- event{ 255 block: block, 256 abciRsp: abciResponses, 257 } 258 } 259 } 260 261 trace.GetElapsedInfo().AddInfo(trace.LastRun, fmt.Sprintf("%dms", duration.Milliseconds())) 262 trace.GetApplyBlockWorkloadSttistic().Add(trace.LastRun, time.Now(), duration) 263 264 if err != nil { 265 return state, 0, ErrProxyAppConn(err) 266 } 267 268 fail.Fail() // XXX 269 270 // Save the results before we commit. 271 blockExec.trySaveABCIResponsesAsync(block.Height, abciResponses) 272 273 fail.Fail() // XXX 274 endTime := time.Now().UnixNano() 275 blockExec.metrics.BlockProcessingTime.Observe(float64(endTime-startTime) / 1e6) 276 blockExec.metrics.AbciTime.Set(float64(endTime-startTime) / 1e6) 277 278 // validate the validator updates and convert to tendermint types 279 abciValUpdates := abciResponses.EndBlock.ValidatorUpdates 280 err = validateValidatorUpdates(abciValUpdates, state.ConsensusParams.Validator) 281 if err != nil { 282 return state, 0, fmt.Errorf("error in validator updates: %v", err) 283 } 284 validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciValUpdates) 285 if err != nil { 286 return state, 0, err 287 } 288 if len(validatorUpdates) > 0 { 289 blockExec.logger.Info("Updates to validators", "updates", types.ValidatorListString(validatorUpdates)) 290 } 291 292 // Update the state with the block and responses. 293 state, err = updateState(state, blockID, &block.Header, abciResponses, validatorUpdates) 294 if err != nil { 295 return state, 0, fmt.Errorf("commit failed for application: %v", err) 296 } 297 298 trc.Pin(trace.Persist) 299 startTime = time.Now().UnixNano() 300 301 // Lock mempool, commit app state, update mempoool. 302 commitResp, retainHeight, err := blockExec.commit(state, block, deltaInfo, abciResponses.DeliverTxs, trc) 303 endTime = time.Now().UnixNano() 304 blockExec.metrics.CommitTime.Set(float64(endTime-startTime) / 1e6) 305 if err != nil { 306 return state, 0, fmt.Errorf("commit failed for application: %v", err) 307 } 308 global.SetGlobalHeight(block.Height) 309 310 // Update evpool with the block and state. 311 blockExec.evpool.Update(block, state) 312 313 fail.Fail() // XXX 314 315 trc.Pin("SaveState") 316 // Update the app hash and save the state. 317 state.AppHash = commitResp.Data 318 blockExec.trySaveStateAsync(state) 319 320 blockExec.logger.Debug("SaveState", "state", &state) 321 fail.Fail() // XXX 322 323 dc.postApplyBlock(block.Height, deltaInfo, abciResponses, commitResp.DeltaMap, blockExec.isFastSync) 324 325 // Events are fired after everything else. 326 // NOTE: if we crash between Commit and Save, events wont be fired during replay 327 if !types.EnableEventBlockTime { 328 if !blockExec.isNullIndexer { 329 blockExec.eventsChan <- event{ 330 block: block, 331 abciRsp: abciResponses, 332 } 333 } 334 } 335 336 return state, retainHeight, nil 337 } 338 339 func (blockExec *BlockExecutor) ApplyBlockWithTrace( 340 state State, blockID types.BlockID, block *types.Block) (State, int64, error) { 341 s, id, err := blockExec.ApplyBlock(state, blockID, block) 342 trace.GetElapsedInfo().Dump(blockExec.logger.With("module", "main")) 343 return s, id, err 344 } 345 346 func (blockExec *BlockExecutor) runAbci(block *types.Block, deltaInfo *DeltaInfo) (*ABCIResponses, time.Duration, error) { 347 var abciResponses *ABCIResponses 348 var err error 349 var duration time.Duration 350 351 if deltaInfo != nil { 352 blockExec.logger.Info("Apply delta", "height", block.Height, "deltas-length", deltaInfo.deltaLen) 353 t0 := time.Now() 354 execBlockOnProxyAppWithDeltas(blockExec.proxyApp, block, blockExec.db) 355 abciResponses = deltaInfo.abciResponses 356 duration = time.Now().Sub(t0) 357 } else { 358 pc := blockExec.prerunCtx 359 if pc.prerunTx { 360 abciResponses, duration, err = pc.getPrerunResult(block) 361 } 362 363 if abciResponses == nil { 364 t0 := time.Now() 365 ctx := &executionTask{ 366 logger: blockExec.logger, 367 block: block, 368 db: blockExec.db, 369 proxyApp: blockExec.proxyApp, 370 } 371 mode := DeliverTxsExecMode(cfg.DynamicConfig.GetDeliverTxsExecuteMode()) 372 switch mode { 373 case DeliverTxsExecModeSerial: 374 abciResponses, err = execBlockOnProxyApp(ctx) 375 case DeliverTxsExecModeParallel: 376 abciResponses, err = execBlockOnProxyAppAsync(blockExec.logger, blockExec.proxyApp, block, blockExec.db) 377 default: 378 abciResponses, err = execBlockOnProxyApp(ctx) 379 } 380 duration = time.Now().Sub(t0) 381 } 382 } 383 384 return abciResponses, duration, err 385 } 386 387 // Commit locks the mempool, runs the ABCI Commit message, and updates the 388 // mempool. 389 // It returns the result of calling abci.Commit (the AppHash) and the height to retain (if any). 390 // The Mempool must be locked during commit and update because state is 391 // typically reset on Commit and old txs must be replayed against committed 392 // state before new txs are run in the mempool, lest they be invalid. 393 func (blockExec *BlockExecutor) commit( 394 state State, 395 block *types.Block, 396 deltaInfo *DeltaInfo, 397 deliverTxResponses []*abci.ResponseDeliverTx, 398 trc *trace.Tracer, 399 ) (*abci.ResponseCommit, int64, error) { 400 blockExec.mempool.Lock() 401 defer func() { 402 blockExec.mempool.Unlock() 403 // Forced flushing mempool 404 if cfg.DynamicConfig.GetMempoolFlush() { 405 blockExec.mempool.Flush() 406 } 407 }() 408 409 // while mempool is Locked, flush to ensure all async requests have completed 410 // in the ABCI app before Commit. 411 err := blockExec.mempool.FlushAppConn() 412 if err != nil { 413 blockExec.logger.Error("Client error during mempool.FlushAppConn", "err", err) 414 return nil, 0, err 415 } 416 417 // Commit block, get hash back 418 var treeDeltaMap interface{} 419 if deltaInfo != nil { 420 treeDeltaMap = deltaInfo.treeDeltaMap 421 } 422 res, err := blockExec.proxyApp.CommitSync(abci.RequestCommit{DeltaMap: treeDeltaMap}) 423 if err != nil { 424 blockExec.logger.Error( 425 "Client error during proxyAppConn.CommitSync", 426 "err", err, 427 ) 428 return nil, 0, err 429 } 430 431 // ResponseCommit has no error code - just data 432 blockExec.logger.Debug( 433 "Committed state", 434 "height", block.Height, 435 "txs", len(block.Txs), 436 "appHash", amino.BytesHexStringer(res.Data), 437 "blockLen", amino.FuncStringer(func() string { return strconv.Itoa(block.FastSize()) }), 438 ) 439 440 trc.Pin("mpUpdate") 441 // Update mempool. 442 err = blockExec.mempool.Update( 443 block.Height, 444 block.Txs, 445 deliverTxResponses, 446 TxPreCheck(state), 447 TxPostCheck(state), 448 ) 449 450 if !cfg.DynamicConfig.GetMempoolRecheck() && block.Height%cfg.DynamicConfig.GetMempoolForceRecheckGap() == 0 { 451 proxyCb := func(req *abci.Request, res *abci.Response) { 452 453 } 454 blockExec.proxyApp.SetResponseCallback(proxyCb) 455 // reset checkState 456 blockExec.proxyApp.SetOptionAsync(abci.RequestSetOption{ 457 Key: "ResetCheckState", 458 }) 459 } 460 461 return res, res.RetainHeight, err 462 } 463 464 func transTxsToBytes(txs types.Txs) [][]byte { 465 ret := make([][]byte, 0) 466 for _, v := range txs { 467 ret = append(ret, v) 468 } 469 return ret 470 } 471 472 //--------------------------------------------------------- 473 // Helper functions for executing blocks and updating state 474 475 // Executes block's transactions on proxyAppConn. 476 // Returns a list of transaction results and updates to the validator set 477 func execBlockOnProxyApp(context *executionTask) (*ABCIResponses, error) { 478 block := context.block 479 proxyAppConn := context.proxyApp 480 stateDB := context.db 481 logger := context.logger 482 483 var validTxs, invalidTxs = 0, 0 484 485 txIndex := 0 486 abciResponses := NewABCIResponses(block) 487 488 // Execute transactions and get hash. 489 proxyCb := func(req *abci.Request, res *abci.Response) { 490 if r, ok := res.Value.(*abci.Response_DeliverTx); ok { 491 // TODO: make use of res.Log 492 // TODO: make use of this info 493 // Blocks may include invalid txs. 494 txRes := r.DeliverTx 495 if txRes.Code == abci.CodeTypeOK { 496 validTxs++ 497 } else { 498 logger.Debug("Invalid tx", "code", txRes.Code, "log", txRes.Log, "index", txIndex) 499 invalidTxs++ 500 } 501 abciResponses.DeliverTxs[txIndex] = txRes 502 txIndex++ 503 } 504 } 505 proxyAppConn.SetResponseCallback(proxyCb) 506 507 // proxyAppConn.ParallelTxs(transTxsToBytes(block.Txs), true) 508 commitInfo, byzVals := getBeginBlockValidatorInfo(block, stateDB) 509 510 // Begin block 511 var err error 512 abciResponses.BeginBlock, err = proxyAppConn.BeginBlockSync(abci.RequestBeginBlock{ 513 Hash: block.Hash(), 514 Header: types.TM2PB.Header(&block.Header), 515 LastCommitInfo: commitInfo, 516 ByzantineValidators: byzVals, 517 }) 518 if err != nil { 519 logger.Error("Error in proxyAppConn.BeginBlock", "err", err) 520 return nil, err 521 } 522 523 realTxCh := make(chan abci.TxEssentials, len(block.Txs)) 524 stopedCh := make(chan struct{}, 1) 525 526 go preDeliverRoutine(proxyAppConn, block.Txs, realTxCh, stopedCh) 527 528 count := 0 529 for realTx := range realTxCh { 530 if realTx != nil { 531 proxyAppConn.DeliverRealTxAsync(realTx) 532 } else { 533 proxyAppConn.DeliverTxAsync(abci.RequestDeliverTx{Tx: block.Txs[count]}) 534 } 535 536 if err = proxyAppConn.Error(); err != nil { 537 return nil, err 538 } 539 if context != nil && context.stopped { 540 stopedCh <- struct{}{} 541 close(stopedCh) 542 context.dump(fmt.Sprintf("Prerun stopped, %d/%d tx executed", count+1, len(block.Txs))) 543 return nil, fmt.Errorf("Prerun stopped") 544 } 545 count += 1 546 } 547 close(stopedCh) 548 549 // End block. 550 abciResponses.EndBlock, err = proxyAppConn.EndBlockSync(abci.RequestEndBlock{Height: block.Height}) 551 if err != nil { 552 logger.Error("Error in proxyAppConn.EndBlock", "err", err) 553 return nil, err 554 } 555 556 trace.GetElapsedInfo().AddInfo(trace.InvalidTxs, fmt.Sprintf("%d", invalidTxs)) 557 558 return abciResponses, nil 559 } 560 561 func preDeliverRoutine(proxyAppConn proxy.AppConnConsensus, txs types.Txs, realTxCh chan<- abci.TxEssentials, stopedCh <-chan struct{}) { 562 for _, tx := range txs { 563 realTx := proxyAppConn.PreDeliverRealTxAsync(tx) 564 select { 565 case realTxCh <- realTx: 566 case <-stopedCh: 567 close(realTxCh) 568 return 569 } 570 } 571 close(realTxCh) 572 } 573 574 func execBlockOnProxyAppWithDeltas( 575 proxyAppConn proxy.AppConnConsensus, 576 block *types.Block, 577 stateDB dbm.DB, 578 ) { 579 proxyCb := func(req *abci.Request, res *abci.Response) { 580 } 581 proxyAppConn.SetResponseCallback(proxyCb) 582 583 commitInfo, byzVals := getBeginBlockValidatorInfo(block, stateDB) 584 _, _ = proxyAppConn.BeginBlockSync(abci.RequestBeginBlock{ 585 Hash: block.Hash(), 586 Header: types.TM2PB.Header(&block.Header), 587 LastCommitInfo: commitInfo, 588 ByzantineValidators: byzVals, 589 }) 590 } 591 592 func getBeginBlockValidatorInfo(block *types.Block, stateDB dbm.DB) (abci.LastCommitInfo, []abci.Evidence) { 593 voteInfos := make([]abci.VoteInfo, block.LastCommit.Size()) 594 // block.Height=1 -> LastCommitInfo.Votes are empty. 595 // Remember that the first LastCommit is intentionally empty, so it makes 596 // sense for LastCommitInfo.Votes to also be empty. 597 if block.Height > types.GetStartBlockHeight()+1 { 598 lastValSet, err := LoadValidators(stateDB, block.Height-1) 599 if err != nil { 600 panic(err) 601 } 602 603 // Sanity check that commit size matches validator set size - only applies 604 // after first block. 605 var ( 606 commitSize = block.LastCommit.Size() 607 valSetLen = len(lastValSet.Validators) 608 ) 609 if commitSize != valSetLen { 610 panic(fmt.Sprintf("commit size (%d) doesn't match valset length (%d) at height %d\n\n%v\n\n%v", 611 commitSize, valSetLen, block.Height, block.LastCommit.Signatures, lastValSet.Validators)) 612 } 613 614 for i, val := range lastValSet.Validators { 615 commitSig := block.LastCommit.Signatures[i] 616 voteInfos[i] = abci.VoteInfo{ 617 Validator: types.TM2PB.Validator(val), 618 SignedLastBlock: !commitSig.Absent(), 619 } 620 } 621 } 622 623 byzVals := make([]abci.Evidence, len(block.Evidence.Evidence)) 624 for i, ev := range block.Evidence.Evidence { 625 // We need the validator set. We already did this in validateBlock. 626 // TODO: Should we instead cache the valset in the evidence itself and add 627 // `SetValidatorSet()` and `ToABCI` methods ? 628 valset, err := LoadValidators(stateDB, ev.Height()) 629 if err != nil { 630 panic(err) 631 } 632 byzVals[i] = types.TM2PB.Evidence(ev, valset, block.Time) 633 } 634 635 return abci.LastCommitInfo{ 636 Round: int32(block.LastCommit.Round), 637 Votes: voteInfos, 638 }, byzVals 639 } 640 641 func validateValidatorUpdates(abciUpdates []abci.ValidatorUpdate, 642 params types.ValidatorParams) error { 643 for _, valUpdate := range abciUpdates { 644 if valUpdate.GetPower() < 0 { 645 return fmt.Errorf("voting power can't be negative %v", valUpdate) 646 } else if valUpdate.GetPower() == 0 { 647 // continue, since this is deleting the validator, and thus there is no 648 // pubkey to check 649 continue 650 } 651 652 // Check if validator's pubkey matches an ABCI type in the consensus params 653 thisKeyType := valUpdate.PubKey.Type 654 if !params.IsValidPubkeyType(thisKeyType) { 655 return fmt.Errorf("validator %v is using pubkey %s, which is unsupported for consensus", 656 valUpdate, thisKeyType) 657 } 658 } 659 return nil 660 } 661 662 // updateState returns a new State updated according to the header and responses. 663 func updateState( 664 state State, 665 blockID types.BlockID, 666 header *types.Header, 667 abciResponses *ABCIResponses, 668 validatorUpdates []*types.Validator, 669 ) (State, error) { 670 671 // Copy the valset so we can apply changes from EndBlock 672 // and update s.LastValidators and s.Validators. 673 nValSet := state.NextValidators.Copy() 674 675 // Update the validator set with the latest abciResponses. 676 lastHeightValsChanged := state.LastHeightValidatorsChanged 677 if len(validatorUpdates) > 0 { 678 err := nValSet.UpdateWithChangeSet(validatorUpdates) 679 if err != nil { 680 return state, fmt.Errorf("error changing validator set: %v", err) 681 } 682 // Change results from this height but only applies to the next next height. 683 lastHeightValsChanged = header.Height + 1 + 1 684 } 685 686 // Update validator proposer priority and set state variables. 687 nValSet.IncrementProposerPriority(1) 688 689 // Update the params with the latest abciResponses. 690 nextParams := state.ConsensusParams 691 lastHeightParamsChanged := state.LastHeightConsensusParamsChanged 692 if abciResponses.EndBlock.ConsensusParamUpdates != nil { 693 // NOTE: must not mutate s.ConsensusParams 694 nextParams = state.ConsensusParams.Update(abciResponses.EndBlock.ConsensusParamUpdates) 695 err := nextParams.Validate() 696 if err != nil { 697 return state, fmt.Errorf("error updating consensus params: %v", err) 698 } 699 // Change results from this height but only applies to the next height. 700 lastHeightParamsChanged = header.Height + 1 701 } 702 703 // TODO: allow app to upgrade version 704 nextVersion := state.Version 705 if types.HigherThanVenus1(header.Height) && !state.Version.IsUpgraded() { 706 nextVersion = state.Version.UpgradeToIBCVersion() 707 } 708 709 // NOTE: the AppHash has not been populated. 710 // It will be filled on state.Save. 711 return State{ 712 Version: nextVersion, 713 ChainID: state.ChainID, 714 LastBlockHeight: header.Height, 715 LastBlockID: blockID, 716 LastBlockTime: header.Time, 717 NextValidators: nValSet, 718 Validators: state.NextValidators.Copy(), 719 LastValidators: state.Validators.Copy(), 720 LastHeightValidatorsChanged: lastHeightValsChanged, 721 ConsensusParams: nextParams, 722 LastHeightConsensusParamsChanged: lastHeightParamsChanged, 723 LastResultsHash: abciResponses.ResultsHash(), 724 AppHash: nil, 725 }, nil 726 } 727 728 // Fire NewBlock, NewBlockHeader. 729 // Fire TxEvent for every tx. 730 // NOTE: if Tendermint crashes before commit, some or all of these events may be published again. 731 func fireEvents( 732 logger log.Logger, 733 eventBus types.BlockEventPublisher, 734 block *types.Block, 735 abciResponses *ABCIResponses, 736 validatorUpdates []*types.Validator, 737 ) { 738 eventBus.PublishEventNewBlock(types.EventDataNewBlock{ 739 Block: block, 740 ResultBeginBlock: *abciResponses.BeginBlock, 741 ResultEndBlock: *abciResponses.EndBlock, 742 }) 743 eventBus.PublishEventNewBlockHeader(types.EventDataNewBlockHeader{ 744 Header: block.Header, 745 NumTxs: int64(len(block.Txs)), 746 ResultBeginBlock: *abciResponses.BeginBlock, 747 ResultEndBlock: *abciResponses.EndBlock, 748 }) 749 750 //publish tx event 1by1 751 for i, tx := range block.Data.Txs { 752 eventBus.PublishEventTx(types.EventDataTx{TxResult: types.TxResult{ 753 Height: block.Height, 754 Index: uint32(i), 755 Tx: tx, 756 Result: *(abciResponses.DeliverTxs[i]), 757 }}) 758 } 759 760 //publish batch txs event 761 if len(block.Data.Txs) > 0 { 762 eventBus.PublishEventTxs(types.EventDataTxs{ 763 Height: block.Height, 764 Results: abciResponses.DeliverTxs, 765 }) 766 } 767 768 //if len(validatorUpdates) > 0 { 769 // eventBus.PublishEventValidatorSetUpdates( 770 // types.EventDataValidatorSetUpdates{ValidatorUpdates: validatorUpdates}) 771 //} 772 } 773 774 func (blockExec *BlockExecutor) FireBlockTimeEvents(height int64, txNum int, available bool) { 775 blockExec.eventBus.PublishEventLatestBlockTime( 776 types.EventDataBlockTime{Height: height, TimeNow: tmtime.Now().UnixMilli(), TxNum: txNum, Available: available}) 777 }