github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/tendermint/state/execution.go (about) 1 package state 2 3 import ( 4 "fmt" 5 "strconv" 6 "time" 7 8 "github.com/fibonacci-chain/fbc/libs/system/trace" 9 abci "github.com/fibonacci-chain/fbc/libs/tendermint/abci/types" 10 cfg "github.com/fibonacci-chain/fbc/libs/tendermint/config" 11 "github.com/fibonacci-chain/fbc/libs/tendermint/global" 12 "github.com/fibonacci-chain/fbc/libs/tendermint/libs/automation" 13 "github.com/fibonacci-chain/fbc/libs/tendermint/libs/fail" 14 "github.com/fibonacci-chain/fbc/libs/tendermint/libs/log" 15 mempl "github.com/fibonacci-chain/fbc/libs/tendermint/mempool" 16 "github.com/fibonacci-chain/fbc/libs/tendermint/proxy" 17 "github.com/fibonacci-chain/fbc/libs/tendermint/types" 18 tmtime "github.com/fibonacci-chain/fbc/libs/tendermint/types/time" 19 dbm "github.com/fibonacci-chain/fbc/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 trc := trace.NewTracer(trace.ApplyBlock) 212 trc.EnableSummary() 213 trc.SetWorkloadStatistic(trace.GetApplyBlockWorkloadSttistic()) 214 dc := blockExec.deltaContext 215 216 defer func() { 217 trace.GetElapsedInfo().AddInfo(trace.Height, strconv.FormatInt(block.Height, 10)) 218 trace.GetElapsedInfo().AddInfo(trace.Tx, strconv.Itoa(len(block.Data.Txs))) 219 trace.GetElapsedInfo().AddInfo(trace.BlockSize, strconv.Itoa(block.FastSize())) 220 trace.GetElapsedInfo().AddInfo(trace.ApplyBlock, trc.Format()) 221 trace.GetElapsedInfo().AddInfo(trace.Workload, trace.GetApplyBlockWorkloadSttistic().Format()) 222 trace.GetElapsedInfo().SetElapsedTime(trc.GetElapsedTime()) 223 224 now := time.Now().UnixNano() 225 blockExec.metrics.IntervalTime.Set(float64(now-blockExec.metrics.lastBlockTime) / 1e6) 226 blockExec.metrics.lastBlockTime = now 227 }() 228 229 if err := blockExec.ValidateBlock(state, block); err != nil { 230 return state, 0, ErrInvalidBlock(err) 231 } 232 233 deltaInfo := dc.prepareStateDelta(block.Height) 234 235 trc.Pin(trace.Abci) 236 237 startTime := time.Now().UnixNano() 238 239 //wait till the last block async write be saved 240 blockExec.tryWaitLastBlockSave(block.Height - 1) 241 242 abciResponses, duration, err := blockExec.runAbci(block, deltaInfo) 243 244 // publish event 245 if types.EnableEventBlockTime { 246 247 blockExec.FireBlockTimeEvents(block.Height, len(block.Txs), true) 248 249 if !blockExec.isNullIndexer { 250 blockExec.eventsChan <- event{ 251 block: block, 252 abciRsp: abciResponses, 253 } 254 } 255 } 256 257 trace.GetElapsedInfo().AddInfo(trace.LastRun, fmt.Sprintf("%dms", duration.Milliseconds())) 258 trace.GetApplyBlockWorkloadSttistic().Add(trace.LastRun, time.Now(), duration) 259 260 if err != nil { 261 return state, 0, ErrProxyAppConn(err) 262 } 263 264 fail.Fail() // XXX 265 266 // Save the results before we commit. 267 blockExec.trySaveABCIResponsesAsync(block.Height, abciResponses) 268 269 fail.Fail() // XXX 270 endTime := time.Now().UnixNano() 271 blockExec.metrics.BlockProcessingTime.Observe(float64(endTime-startTime) / 1e6) 272 blockExec.metrics.AbciTime.Set(float64(endTime-startTime) / 1e6) 273 274 // validate the validator updates and convert to tendermint types 275 abciValUpdates := abciResponses.EndBlock.ValidatorUpdates 276 err = validateValidatorUpdates(abciValUpdates, state.ConsensusParams.Validator) 277 if err != nil { 278 return state, 0, fmt.Errorf("error in validator updates: %v", err) 279 } 280 validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciValUpdates) 281 if err != nil { 282 return state, 0, err 283 } 284 if len(validatorUpdates) > 0 { 285 blockExec.logger.Info("Updates to validators", "updates", types.ValidatorListString(validatorUpdates)) 286 } 287 288 // Update the state with the block and responses. 289 state, err = updateState(state, blockID, &block.Header, abciResponses, validatorUpdates) 290 if err != nil { 291 return state, 0, fmt.Errorf("commit failed for application: %v", err) 292 } 293 294 trc.Pin(trace.Persist) 295 startTime = time.Now().UnixNano() 296 297 // Lock mempool, commit app state, update mempoool. 298 commitResp, retainHeight, err := blockExec.commit(state, block, deltaInfo, abciResponses.DeliverTxs, trc) 299 endTime = time.Now().UnixNano() 300 blockExec.metrics.CommitTime.Set(float64(endTime-startTime) / 1e6) 301 if err != nil { 302 return state, 0, fmt.Errorf("commit failed for application: %v", err) 303 } 304 global.SetGlobalHeight(block.Height) 305 306 // Update evpool with the block and state. 307 blockExec.evpool.Update(block, state) 308 309 fail.Fail() // XXX 310 311 trc.Pin("SaveState") 312 313 // Update the app hash and save the state. 314 state.AppHash = commitResp.Data 315 blockExec.trySaveStateAsync(state) 316 317 blockExec.logger.Debug("SaveState", "state", &state) 318 fail.Fail() // XXX 319 320 dc.postApplyBlock(block.Height, deltaInfo, abciResponses, commitResp.DeltaMap, blockExec.isFastSync) 321 322 // Events are fired after everything else. 323 // NOTE: if we crash between Commit and Save, events wont be fired during replay 324 if !types.EnableEventBlockTime { 325 if !blockExec.isNullIndexer { 326 blockExec.eventsChan <- event{ 327 block: block, 328 abciRsp: abciResponses, 329 } 330 } 331 } 332 333 return state, retainHeight, nil 334 } 335 336 func (blockExec *BlockExecutor) ApplyBlockWithTrace( 337 state State, blockID types.BlockID, block *types.Block) (State, int64, error) { 338 s, id, err := blockExec.ApplyBlock(state, blockID, block) 339 trace.GetElapsedInfo().Dump(blockExec.logger.With("module", "main")) 340 return s, id, err 341 } 342 343 func (blockExec *BlockExecutor) runAbci(block *types.Block, deltaInfo *DeltaInfo) (*ABCIResponses, time.Duration, error) { 344 var abciResponses *ABCIResponses 345 var err error 346 var duration time.Duration 347 348 if deltaInfo != nil { 349 blockExec.logger.Info("Apply delta", "height", block.Height, "deltas-length", deltaInfo.deltaLen) 350 t0 := time.Now() 351 execBlockOnProxyAppWithDeltas(blockExec.proxyApp, block, blockExec.db) 352 abciResponses = deltaInfo.abciResponses 353 duration = time.Now().Sub(t0) 354 } else { 355 pc := blockExec.prerunCtx 356 if pc.prerunTx { 357 abciResponses, duration, err = pc.getPrerunResult(block) 358 } 359 360 if abciResponses == nil { 361 t0 := time.Now() 362 ctx := &executionTask{ 363 logger: blockExec.logger, 364 block: block, 365 db: blockExec.db, 366 proxyApp: blockExec.proxyApp, 367 } 368 mode := DeliverTxsExecMode(cfg.DynamicConfig.GetDeliverTxsExecuteMode()) 369 switch mode { 370 case DeliverTxsExecModeSerial: 371 abciResponses, err = execBlockOnProxyApp(ctx) 372 case DeliverTxsExecModeParallel: 373 abciResponses, err = execBlockOnProxyAppAsync(blockExec.logger, blockExec.proxyApp, block, blockExec.db) 374 default: 375 abciResponses, err = execBlockOnProxyApp(ctx) 376 } 377 duration = time.Now().Sub(t0) 378 } 379 } 380 381 return abciResponses, duration, err 382 } 383 384 // Commit locks the mempool, runs the ABCI Commit message, and updates the 385 // mempool. 386 // It returns the result of calling abci.Commit (the AppHash) and the height to retain (if any). 387 // The Mempool must be locked during commit and update because state is 388 // typically reset on Commit and old txs must be replayed against committed 389 // state before new txs are run in the mempool, lest they be invalid. 390 func (blockExec *BlockExecutor) commit( 391 state State, 392 block *types.Block, 393 deltaInfo *DeltaInfo, 394 deliverTxResponses []*abci.ResponseDeliverTx, 395 trc *trace.Tracer, 396 ) (*abci.ResponseCommit, int64, error) { 397 blockExec.mempool.Lock() 398 defer func() { 399 blockExec.mempool.Unlock() 400 // Forced flushing mempool 401 if cfg.DynamicConfig.GetMempoolFlush() { 402 blockExec.mempool.Flush() 403 } 404 }() 405 406 // while mempool is Locked, flush to ensure all async requests have completed 407 // in the ABCI app before Commit. 408 err := blockExec.mempool.FlushAppConn() 409 if err != nil { 410 blockExec.logger.Error("Client error during mempool.FlushAppConn", "err", err) 411 return nil, 0, err 412 } 413 414 // Commit block, get hash back 415 var treeDeltaMap interface{} 416 if deltaInfo != nil { 417 treeDeltaMap = deltaInfo.treeDeltaMap 418 } 419 res, err := blockExec.proxyApp.CommitSync(abci.RequestCommit{DeltaMap: treeDeltaMap}) 420 if err != nil { 421 blockExec.logger.Error( 422 "Client error during proxyAppConn.CommitSync", 423 "err", err, 424 ) 425 return nil, 0, err 426 } 427 428 // ResponseCommit has no error code - just data 429 blockExec.logger.Debug( 430 "Committed state", 431 "height", block.Height, 432 "txs", len(block.Txs), 433 "appHash", amino.BytesHexStringer(res.Data), 434 "blockLen", amino.FuncStringer(func() string { return strconv.Itoa(block.FastSize()) }), 435 ) 436 437 trc.Pin("mpUpdate") 438 // Update mempool. 439 err = blockExec.mempool.Update( 440 block.Height, 441 block.Txs, 442 deliverTxResponses, 443 TxPreCheck(state), 444 TxPostCheck(state), 445 ) 446 447 if !cfg.DynamicConfig.GetMempoolRecheck() && block.Height%cfg.DynamicConfig.GetMempoolForceRecheckGap() == 0 { 448 proxyCb := func(req *abci.Request, res *abci.Response) { 449 450 } 451 blockExec.proxyApp.SetResponseCallback(proxyCb) 452 // reset checkState 453 blockExec.proxyApp.SetOptionAsync(abci.RequestSetOption{ 454 Key: "ResetCheckState", 455 }) 456 } 457 458 return res, res.RetainHeight, err 459 } 460 461 func transTxsToBytes(txs types.Txs) [][]byte { 462 ret := make([][]byte, 0) 463 for _, v := range txs { 464 ret = append(ret, v) 465 } 466 return ret 467 } 468 469 //--------------------------------------------------------- 470 // Helper functions for executing blocks and updating state 471 472 // Executes block's transactions on proxyAppConn. 473 // Returns a list of transaction results and updates to the validator set 474 func execBlockOnProxyApp(context *executionTask) (*ABCIResponses, error) { 475 block := context.block 476 proxyAppConn := context.proxyApp 477 stateDB := context.db 478 logger := context.logger 479 480 var validTxs, invalidTxs = 0, 0 481 482 txIndex := 0 483 abciResponses := NewABCIResponses(block) 484 485 // Execute transactions and get hash. 486 proxyCb := func(req *abci.Request, res *abci.Response) { 487 if r, ok := res.Value.(*abci.Response_DeliverTx); ok { 488 // TODO: make use of res.Log 489 // TODO: make use of this info 490 // Blocks may include invalid txs. 491 txRes := r.DeliverTx 492 if txRes.Code == abci.CodeTypeOK { 493 validTxs++ 494 } else { 495 logger.Debug("Invalid tx", "code", txRes.Code, "log", txRes.Log, "index", txIndex) 496 invalidTxs++ 497 } 498 abciResponses.DeliverTxs[txIndex] = txRes 499 txIndex++ 500 } 501 } 502 proxyAppConn.SetResponseCallback(proxyCb) 503 504 // proxyAppConn.ParallelTxs(transTxsToBytes(block.Txs), true) 505 commitInfo, byzVals := getBeginBlockValidatorInfo(block, stateDB) 506 507 // Begin block 508 var err error 509 abciResponses.BeginBlock, err = proxyAppConn.BeginBlockSync(abci.RequestBeginBlock{ 510 Hash: block.Hash(), 511 Header: types.TM2PB.Header(&block.Header), 512 LastCommitInfo: commitInfo, 513 ByzantineValidators: byzVals, 514 }) 515 if err != nil { 516 logger.Error("Error in proxyAppConn.BeginBlock", "err", err) 517 return nil, err 518 } 519 520 realTxCh := make(chan abci.TxEssentials, len(block.Txs)) 521 stopedCh := make(chan struct{}, 1) 522 523 go preDeliverRoutine(proxyAppConn, block.Txs, realTxCh, stopedCh) 524 525 count := 0 526 for realTx := range realTxCh { 527 if realTx != nil { 528 proxyAppConn.DeliverRealTxAsync(realTx) 529 } else { 530 proxyAppConn.DeliverTxAsync(abci.RequestDeliverTx{Tx: block.Txs[count]}) 531 } 532 533 if err = proxyAppConn.Error(); err != nil { 534 return nil, err 535 } 536 if context != nil && context.stopped { 537 stopedCh <- struct{}{} 538 close(stopedCh) 539 context.dump(fmt.Sprintf("Prerun stopped, %d/%d tx executed", count+1, len(block.Txs))) 540 return nil, fmt.Errorf("Prerun stopped") 541 } 542 count += 1 543 } 544 close(stopedCh) 545 546 // End block. 547 abciResponses.EndBlock, err = proxyAppConn.EndBlockSync(abci.RequestEndBlock{Height: block.Height}) 548 if err != nil { 549 logger.Error("Error in proxyAppConn.EndBlock", "err", err) 550 return nil, err 551 } 552 553 trace.GetElapsedInfo().AddInfo(trace.InvalidTxs, fmt.Sprintf("%d", invalidTxs)) 554 555 return abciResponses, nil 556 } 557 558 func preDeliverRoutine(proxyAppConn proxy.AppConnConsensus, txs types.Txs, realTxCh chan<- abci.TxEssentials, stopedCh <-chan struct{}) { 559 for _, tx := range txs { 560 realTx := proxyAppConn.PreDeliverRealTxAsync(tx) 561 select { 562 case realTxCh <- realTx: 563 case <-stopedCh: 564 close(realTxCh) 565 return 566 } 567 } 568 close(realTxCh) 569 } 570 571 func execBlockOnProxyAppWithDeltas( 572 proxyAppConn proxy.AppConnConsensus, 573 block *types.Block, 574 stateDB dbm.DB, 575 ) { 576 proxyCb := func(req *abci.Request, res *abci.Response) { 577 } 578 proxyAppConn.SetResponseCallback(proxyCb) 579 580 commitInfo, byzVals := getBeginBlockValidatorInfo(block, stateDB) 581 _, _ = proxyAppConn.BeginBlockSync(abci.RequestBeginBlock{ 582 Hash: block.Hash(), 583 Header: types.TM2PB.Header(&block.Header), 584 LastCommitInfo: commitInfo, 585 ByzantineValidators: byzVals, 586 }) 587 } 588 589 func getBeginBlockValidatorInfo(block *types.Block, stateDB dbm.DB) (abci.LastCommitInfo, []abci.Evidence) { 590 voteInfos := make([]abci.VoteInfo, block.LastCommit.Size()) 591 // block.Height=1 -> LastCommitInfo.Votes are empty. 592 // Remember that the first LastCommit is intentionally empty, so it makes 593 // sense for LastCommitInfo.Votes to also be empty. 594 if block.Height > types.GetStartBlockHeight()+1 { 595 lastValSet, err := LoadValidators(stateDB, block.Height-1) 596 if err != nil { 597 panic(err) 598 } 599 600 // Sanity check that commit size matches validator set size - only applies 601 // after first block. 602 var ( 603 commitSize = block.LastCommit.Size() 604 valSetLen = len(lastValSet.Validators) 605 ) 606 if commitSize != valSetLen { 607 panic(fmt.Sprintf("commit size (%d) doesn't match valset length (%d) at height %d\n\n%v\n\n%v", 608 commitSize, valSetLen, block.Height, block.LastCommit.Signatures, lastValSet.Validators)) 609 } 610 611 for i, val := range lastValSet.Validators { 612 commitSig := block.LastCommit.Signatures[i] 613 voteInfos[i] = abci.VoteInfo{ 614 Validator: types.TM2PB.Validator(val), 615 SignedLastBlock: !commitSig.Absent(), 616 } 617 } 618 } 619 620 byzVals := make([]abci.Evidence, len(block.Evidence.Evidence)) 621 for i, ev := range block.Evidence.Evidence { 622 // We need the validator set. We already did this in validateBlock. 623 // TODO: Should we instead cache the valset in the evidence itself and add 624 // `SetValidatorSet()` and `ToABCI` methods ? 625 valset, err := LoadValidators(stateDB, ev.Height()) 626 if err != nil { 627 panic(err) 628 } 629 byzVals[i] = types.TM2PB.Evidence(ev, valset, block.Time) 630 } 631 632 return abci.LastCommitInfo{ 633 Round: int32(block.LastCommit.Round), 634 Votes: voteInfos, 635 }, byzVals 636 } 637 638 func validateValidatorUpdates(abciUpdates []abci.ValidatorUpdate, 639 params types.ValidatorParams) error { 640 for _, valUpdate := range abciUpdates { 641 if valUpdate.GetPower() < 0 { 642 return fmt.Errorf("voting power can't be negative %v", valUpdate) 643 } else if valUpdate.GetPower() == 0 { 644 // continue, since this is deleting the validator, and thus there is no 645 // pubkey to check 646 continue 647 } 648 649 // Check if validator's pubkey matches an ABCI type in the consensus params 650 thisKeyType := valUpdate.PubKey.Type 651 if !params.IsValidPubkeyType(thisKeyType) { 652 return fmt.Errorf("validator %v is using pubkey %s, which is unsupported for consensus", 653 valUpdate, thisKeyType) 654 } 655 } 656 return nil 657 } 658 659 // updateState returns a new State updated according to the header and responses. 660 func updateState( 661 state State, 662 blockID types.BlockID, 663 header *types.Header, 664 abciResponses *ABCIResponses, 665 validatorUpdates []*types.Validator, 666 ) (State, error) { 667 668 // Copy the valset so we can apply changes from EndBlock 669 // and update s.LastValidators and s.Validators. 670 nValSet := state.NextValidators.Copy() 671 672 // Update the validator set with the latest abciResponses. 673 lastHeightValsChanged := state.LastHeightValidatorsChanged 674 if len(validatorUpdates) > 0 { 675 err := nValSet.UpdateWithChangeSet(validatorUpdates) 676 if err != nil { 677 return state, fmt.Errorf("error changing validator set: %v", err) 678 } 679 // Change results from this height but only applies to the next next height. 680 lastHeightValsChanged = header.Height + 1 + 1 681 } 682 683 // Update validator proposer priority and set state variables. 684 nValSet.IncrementProposerPriority(1) 685 686 // Update the params with the latest abciResponses. 687 nextParams := state.ConsensusParams 688 lastHeightParamsChanged := state.LastHeightConsensusParamsChanged 689 if abciResponses.EndBlock.ConsensusParamUpdates != nil { 690 // NOTE: must not mutate s.ConsensusParams 691 nextParams = state.ConsensusParams.Update(abciResponses.EndBlock.ConsensusParamUpdates) 692 err := nextParams.Validate() 693 if err != nil { 694 return state, fmt.Errorf("error updating consensus params: %v", err) 695 } 696 // Change results from this height but only applies to the next height. 697 lastHeightParamsChanged = header.Height + 1 698 } 699 700 // TODO: allow app to upgrade version 701 nextVersion := state.Version 702 if types.HigherThanVenus1(header.Height) && !state.Version.IsUpgraded() { 703 nextVersion = state.Version.UpgradeToIBCVersion() 704 } 705 706 // NOTE: the AppHash has not been populated. 707 // It will be filled on state.Save. 708 return State{ 709 Version: nextVersion, 710 ChainID: state.ChainID, 711 LastBlockHeight: header.Height, 712 LastBlockID: blockID, 713 LastBlockTime: header.Time, 714 NextValidators: nValSet, 715 Validators: state.NextValidators.Copy(), 716 LastValidators: state.Validators.Copy(), 717 LastHeightValidatorsChanged: lastHeightValsChanged, 718 ConsensusParams: nextParams, 719 LastHeightConsensusParamsChanged: lastHeightParamsChanged, 720 LastResultsHash: abciResponses.ResultsHash(), 721 AppHash: nil, 722 }, nil 723 } 724 725 // Fire NewBlock, NewBlockHeader. 726 // Fire TxEvent for every tx. 727 // NOTE: if Tendermint crashes before commit, some or all of these events may be published again. 728 func fireEvents( 729 logger log.Logger, 730 eventBus types.BlockEventPublisher, 731 block *types.Block, 732 abciResponses *ABCIResponses, 733 validatorUpdates []*types.Validator, 734 ) { 735 eventBus.PublishEventNewBlock(types.EventDataNewBlock{ 736 Block: block, 737 ResultBeginBlock: *abciResponses.BeginBlock, 738 ResultEndBlock: *abciResponses.EndBlock, 739 }) 740 eventBus.PublishEventNewBlockHeader(types.EventDataNewBlockHeader{ 741 Header: block.Header, 742 NumTxs: int64(len(block.Txs)), 743 ResultBeginBlock: *abciResponses.BeginBlock, 744 ResultEndBlock: *abciResponses.EndBlock, 745 }) 746 747 //publish tx event 1by1 748 for i, tx := range block.Data.Txs { 749 eventBus.PublishEventTx(types.EventDataTx{TxResult: types.TxResult{ 750 Height: block.Height, 751 Index: uint32(i), 752 Tx: tx, 753 Result: *(abciResponses.DeliverTxs[i]), 754 }}) 755 } 756 757 //publish batch txs event 758 if len(block.Data.Txs) > 0 { 759 eventBus.PublishEventTxs(types.EventDataTxs{ 760 Height: block.Height, 761 Results: abciResponses.DeliverTxs, 762 }) 763 } 764 765 //if len(validatorUpdates) > 0 { 766 // eventBus.PublishEventValidatorSetUpdates( 767 // types.EventDataValidatorSetUpdates{ValidatorUpdates: validatorUpdates}) 768 //} 769 } 770 771 func (blockExec *BlockExecutor) FireBlockTimeEvents(height int64, txNum int, available bool) { 772 blockExec.eventBus.PublishEventLatestBlockTime( 773 types.EventDataBlockTime{Height: height, TimeNow: tmtime.Now().UnixMilli(), TxNum: txNum, Available: available}) 774 }