github.com/ari-anchor/sei-tendermint@v0.0.0-20230519144642-dc826b7b56bb/internal/state/validation.go (about)

     1  package state
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  
     8  	"github.com/ari-anchor/sei-tendermint/types"
     9  )
    10  
    11  //-----------------------------------------------------
    12  // Validate block
    13  
    14  func validateBlock(state State, block *types.Block) error {
    15  	// Validate internal consistency.
    16  	if err := block.ValidateBasic(); err != nil {
    17  		return err
    18  	}
    19  
    20  	// Validate basic info.
    21  	if block.Version.App != state.Version.Consensus.App ||
    22  		block.Version.Block != state.Version.Consensus.Block {
    23  		return fmt.Errorf("wrong Block.Header.Version. Expected %v, got %v",
    24  			state.Version.Consensus,
    25  			block.Version,
    26  		)
    27  	}
    28  	if block.ChainID != state.ChainID {
    29  		return fmt.Errorf("wrong Block.Header.ChainID. Expected %v, got %v",
    30  			state.ChainID,
    31  			block.ChainID,
    32  		)
    33  	}
    34  	if state.LastBlockHeight == 0 && block.Height != state.InitialHeight {
    35  		return fmt.Errorf("wrong Block.Header.Height. Expected %v for initial block, got %v",
    36  			block.Height, state.InitialHeight)
    37  	}
    38  	if state.LastBlockHeight > 0 && block.Height != state.LastBlockHeight+1 {
    39  		return fmt.Errorf("wrong Block.Header.Height. Expected %v, got %v",
    40  			state.LastBlockHeight+1,
    41  			block.Height,
    42  		)
    43  	}
    44  	// Validate prev block info.
    45  	if !block.LastBlockID.Equals(state.LastBlockID) {
    46  		return fmt.Errorf("wrong Block.Header.LastBlockID.  Expected %v, got %v",
    47  			state.LastBlockID,
    48  			block.LastBlockID,
    49  		)
    50  	}
    51  
    52  	// Validate app info
    53  	if !bytes.Equal(block.AppHash, state.AppHash) {
    54  		return fmt.Errorf("wrong Block.Header.AppHash.  Expected %X, got %v",
    55  			state.AppHash,
    56  			block.AppHash,
    57  		)
    58  	}
    59  	hashCP := state.ConsensusParams.HashConsensusParams()
    60  	if !bytes.Equal(block.ConsensusHash, hashCP) {
    61  		return fmt.Errorf("wrong Block.Header.ConsensusHash.  Expected %X, got %v",
    62  			hashCP,
    63  			block.ConsensusHash,
    64  		)
    65  	}
    66  	if !bytes.Equal(block.LastResultsHash, state.LastResultsHash) {
    67  		return fmt.Errorf("wrong Block.Header.LastResultsHash.  Expected %X, got %v",
    68  			state.LastResultsHash,
    69  			block.LastResultsHash,
    70  		)
    71  	}
    72  	if !bytes.Equal(block.ValidatorsHash, state.Validators.Hash()) {
    73  		return fmt.Errorf("wrong Block.Header.ValidatorsHash.  Expected %X, got %v",
    74  			state.Validators.Hash(),
    75  			block.ValidatorsHash,
    76  		)
    77  	}
    78  	if !bytes.Equal(block.NextValidatorsHash, state.NextValidators.Hash()) {
    79  		return fmt.Errorf("wrong Block.Header.NextValidatorsHash.  Expected %X, got %v",
    80  			state.NextValidators.Hash(),
    81  			block.NextValidatorsHash,
    82  		)
    83  	}
    84  
    85  	// Validate block LastCommit.
    86  	if block.Height == state.InitialHeight {
    87  		if len(block.LastCommit.Signatures) != 0 {
    88  			return errors.New("initial block can't have LastCommit signatures")
    89  		}
    90  	} else {
    91  		// LastCommit.Signatures length is checked in VerifyCommit.
    92  		if err := state.LastValidators.VerifyCommit(
    93  			state.ChainID, state.LastBlockID, block.Height-1, block.LastCommit); err != nil {
    94  			return err
    95  		}
    96  	}
    97  
    98  	// NOTE: We can't actually verify it's the right proposer because we don't
    99  	// know what round the block was first proposed. So just check that it's
   100  	// a legit address and a known validator.
   101  	// The length is checked in ValidateBasic above.
   102  	if !state.Validators.HasAddress(block.ProposerAddress) {
   103  		return fmt.Errorf("block.Header.ProposerAddress %X is not a validator",
   104  			block.ProposerAddress,
   105  		)
   106  	}
   107  
   108  	// Validate block Time
   109  	switch {
   110  	case block.Height > state.InitialHeight:
   111  		if !block.Time.After(state.LastBlockTime) {
   112  			return fmt.Errorf("block time %v not greater than last block time %v",
   113  				block.Time,
   114  				state.LastBlockTime,
   115  			)
   116  		}
   117  
   118  	case block.Height == state.InitialHeight:
   119  		genesisTime := state.LastBlockTime
   120  		if block.Time.Before(genesisTime) {
   121  			return fmt.Errorf("block time %v is before genesis time %v",
   122  				block.Time,
   123  				genesisTime,
   124  			)
   125  		}
   126  
   127  	default:
   128  		return fmt.Errorf("block height %v lower than initial height %v",
   129  			block.Height, state.InitialHeight)
   130  	}
   131  
   132  	// Check evidence doesn't exceed the limit amount of bytes.
   133  	if max, got := state.ConsensusParams.Evidence.MaxBytes, block.Evidence.ByteSize(); got > max {
   134  		return types.NewErrEvidenceOverflow(max, got)
   135  	}
   136  
   137  	return nil
   138  }