ApplyBlock processes a given block, updating the state machine's state accordingly The function: - executes `BeginBlock` - applies all transactions within the block, generating transaction results nad a root hash - executes `EndBlock` - constructs and returns the block header, and the transaction re
(ctx context.Context, b *lib.Block, allowOversize bool)
| 104 | // - this function may be used to validate 'additional' transactions outside the normal block size as if they were to be included |
| 105 | // - a list of failed transactions are returned |
| 106 | func (s *StateMachine) ApplyBlock(ctx context.Context, b *lib.Block, allowOversize bool) (header *lib.BlockHeader, r *lib.ApplyBlockResults, err lib.ErrorI) { |
| 107 | // catch in case there's a panic |
| 108 | defer func() { |
| 109 | if r := recover(); r != nil { |
| 110 | s.log.Errorf("panic recovered, err: %s, stack: %s", r, string(debug.Stack())) |
| 111 | // handle the panic and set the error |
| 112 | err = lib.ErrPanic() |
| 113 | } |
| 114 | }() |
| 115 | // define vars to track the bytes of the transaction results and the size of a block |
| 116 | r = new(lib.ApplyBlockResults) |
| 117 | // cast the store to a StoreI, as only the writable store main 'apply blocks' |
| 118 | store, ok := s.Store().(lib.StoreI) |
| 119 | // casting fails, exit with error |
| 120 | if !ok { |
| 121 | return nil, nil, ErrWrongStoreType() |
| 122 | } |
| 123 | // automated execution at the 'beginning of a block' |
| 124 | events, err := s.BeginBlock() |
| 125 | if err != nil { |
| 126 | return nil, nil, err |
| 127 | } |
| 128 | // add the events from begin block |
| 129 | r.AddEvent(events...) |
| 130 | // apply all Transactions in the block |
| 131 | if err = s.ApplyTransactions(ctx, b.Transactions, r, allowOversize); err != nil { |
| 132 | return nil, nil, err |
| 133 | } |
| 134 | // sub-out transactions for those that succeeded (only useful for mempool application) |
| 135 | b.Transactions = r.Txs |
| 136 | // automated execution at the 'ending of a block' |
| 137 | events, err = s.EndBlock(b.BlockHeader.ProposerAddress) |
| 138 | if err != nil { |
| 139 | return nil, nil, err |
| 140 | } |
| 141 | // add the events from end block |
| 142 | r.AddEvent(events...) |
| 143 | // load the validator set for the previous height |
| 144 | lastValidatorSet, _ := s.LoadCommittee(s.Config.ChainId, s.Height()-1) |
| 145 | // calculate the merkle root of the last validators to maintain validator continuity between blocks (if root) |
| 146 | lastValidatorRoot, err := lastValidatorSet.ValidatorSet.Root() |
| 147 | if err != nil { |
| 148 | return nil, nil, err |
| 149 | } |
| 150 | // load the 'next validator set' from the state |
| 151 | nextValidatorSet, _ := s.LoadCommittee(s.Config.ChainId, s.Height()) |
| 152 | // calculate the merkle root of the next validators to maintain validator continuity between blocks (if root) |
| 153 | nextValidatorRoot, err := nextValidatorSet.ValidatorSet.Root() |
| 154 | if err != nil { |
| 155 | return nil, nil, err |
| 156 | } |
| 157 | // calculate the merkle root of the state database to enable consensus on the result of the state after applying the block |
| 158 | stateRoot, err := store.Root() |
| 159 | if err != nil { |
| 160 | return nil, nil, err |
| 161 | } |
| 162 | // load the last block from the indexer |
| 163 | lastBlock, err := s.LoadBlock(s.height - 1) |