github.com/badrootd/celestia-core@v0.0.0-20240305091328-aa4207a4b25d/state/validation.go (about) 1 package state 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 8 "github.com/badrootd/celestia-core/crypto" 9 "github.com/badrootd/celestia-core/types" 10 ) 11 12 //----------------------------------------------------- 13 // Validate block 14 15 func validateBlock(state State, block *types.Block) error { 16 // Validate internal consistency. 17 if err := block.ValidateBasic(); err != nil { 18 return err 19 } 20 21 // Validate basic info. 22 if block.Version.App != state.Version.Consensus.App || 23 block.Version.Block != state.Version.Consensus.Block { 24 return fmt.Errorf("wrong Block.Header.Version. Expected %v, got %v", 25 state.Version.Consensus, 26 block.Version, 27 ) 28 } 29 if block.ChainID != state.ChainID { 30 return fmt.Errorf("wrong Block.Header.ChainID. Expected %v, got %v", 31 state.ChainID, 32 block.ChainID, 33 ) 34 } 35 if state.LastBlockHeight == 0 && block.Height != state.InitialHeight { 36 return fmt.Errorf("wrong Block.Header.Height. Expected %v for initial block, got %v", 37 block.Height, state.InitialHeight) 38 } 39 if state.LastBlockHeight > 0 && block.Height != state.LastBlockHeight+1 { 40 return fmt.Errorf("wrong Block.Header.Height. Expected %v, got %v", 41 state.LastBlockHeight+1, 42 block.Height, 43 ) 44 } 45 // Validate prev block info. 46 if !block.LastBlockID.Equals(state.LastBlockID) { 47 return fmt.Errorf("wrong Block.Header.LastBlockID. Expected %v, got %v", 48 state.LastBlockID, 49 block.LastBlockID, 50 ) 51 } 52 53 // Validate app info 54 if !bytes.Equal(block.AppHash, state.AppHash) { 55 return fmt.Errorf("wrong Block.Header.AppHash. Expected %X, got %v", 56 state.AppHash, 57 block.AppHash, 58 ) 59 } 60 if !bytes.Equal(block.ConsensusHash, state.ConsensusParams.Hash()) { 61 return fmt.Errorf("wrong Block.Header.ConsensusHash. Expected %X, got %v", 62 state.ConsensusParams.Hash(), 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 if len(block.ProposerAddress) != crypto.AddressSize { 102 return fmt.Errorf("expected ProposerAddress size %d, got %d", 103 crypto.AddressSize, 104 len(block.ProposerAddress), 105 ) 106 } 107 if !state.Validators.HasAddress(block.ProposerAddress) { 108 return fmt.Errorf("block.Header.ProposerAddress %X is not a validator", 109 block.ProposerAddress, 110 ) 111 } 112 113 // Validate block Time 114 switch { 115 case block.Height > state.InitialHeight: 116 if !block.Time.After(state.LastBlockTime) { 117 return fmt.Errorf("block time %v not greater than last block time %v", 118 block.Time, 119 state.LastBlockTime, 120 ) 121 } 122 medianTime := MedianTime(block.LastCommit, state.LastValidators) 123 if !block.Time.Equal(medianTime) { 124 return fmt.Errorf("invalid block time. Expected %v, got %v", 125 medianTime, 126 block.Time, 127 ) 128 } 129 130 case block.Height == state.InitialHeight: 131 genesisTime := state.LastBlockTime 132 if !block.Time.Equal(genesisTime) { 133 return fmt.Errorf("block time %v is not equal to genesis time %v", 134 block.Time, 135 genesisTime, 136 ) 137 } 138 139 default: 140 return fmt.Errorf("block height %v lower than initial height %v", 141 block.Height, state.InitialHeight) 142 } 143 144 // Check evidence doesn't exceed the limit amount of bytes. 145 if max, got := state.ConsensusParams.Evidence.MaxBytes, block.Evidence.ByteSize(); got > max { 146 return types.NewErrEvidenceOverflow(max, got) 147 } 148 149 return nil 150 }