github.com/arcology-network/consensus-engine@v1.9.0/state/validation.go (about) 1 package state 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 8 "github.com/arcology-network/consensus-engine/crypto" 9 "github.com/arcology-network/consensus-engine/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 hashCP := types.HashConsensusParams(state.ConsensusParams) 61 if !bytes.Equal(block.ConsensusHash, hashCP) { 62 return fmt.Errorf("wrong Block.Header.ConsensusHash. Expected %X, got %v", 63 hashCP, 64 block.ConsensusHash, 65 ) 66 } 67 if !bytes.Equal(block.LastResultsHash, state.LastResultsHash) { 68 return fmt.Errorf("wrong Block.Header.LastResultsHash. Expected %X, got %v", 69 state.LastResultsHash, 70 block.LastResultsHash, 71 ) 72 } 73 if !bytes.Equal(block.ValidatorsHash, state.Validators.Hash()) { 74 return fmt.Errorf("wrong Block.Header.ValidatorsHash. Expected %X, got %v", 75 state.Validators.Hash(), 76 block.ValidatorsHash, 77 ) 78 } 79 if !bytes.Equal(block.NextValidatorsHash, state.NextValidators.Hash()) { 80 return fmt.Errorf("wrong Block.Header.NextValidatorsHash. Expected %X, got %v", 81 state.NextValidators.Hash(), 82 block.NextValidatorsHash, 83 ) 84 } 85 86 // Validate block LastCommit. 87 if block.Height == state.InitialHeight { 88 if len(block.LastCommit.Signatures) != 0 { 89 return errors.New("initial block can't have LastCommit signatures") 90 } 91 } else { 92 // LastCommit.Signatures length is checked in VerifyCommit. 93 if err := state.LastValidators.VerifyCommit( 94 state.ChainID, state.LastBlockID, block.Height-1, block.LastCommit); err != nil { 95 return err 96 } 97 } 98 99 // NOTE: We can't actually verify it's the right proposer because we don't 100 // know what round the block was first proposed. So just check that it's 101 // a legit address and a known validator. 102 if len(block.ProposerAddress) != crypto.AddressSize { 103 return fmt.Errorf("expected ProposerAddress size %d, got %d", 104 crypto.AddressSize, 105 len(block.ProposerAddress), 106 ) 107 } 108 if !state.Validators.HasAddress(block.ProposerAddress) { 109 return fmt.Errorf("block.Header.ProposerAddress %X is not a validator", 110 block.ProposerAddress, 111 ) 112 } 113 114 // Validate block Time 115 switch { 116 case block.Height > state.InitialHeight: 117 if !block.Time.After(state.LastBlockTime) { 118 return fmt.Errorf("block time %v not greater than last block time %v", 119 block.Time, 120 state.LastBlockTime, 121 ) 122 } 123 medianTime := MedianTime(block.LastCommit, state.LastValidators) 124 if !block.Time.Equal(medianTime) { 125 return fmt.Errorf("invalid block time. Expected %v, got %v", 126 medianTime, 127 block.Time, 128 ) 129 } 130 131 case block.Height == state.InitialHeight: 132 genesisTime := state.LastBlockTime 133 if !block.Time.Equal(genesisTime) { 134 return fmt.Errorf("block time %v is not equal to genesis time %v", 135 block.Time, 136 genesisTime, 137 ) 138 } 139 140 default: 141 return fmt.Errorf("block height %v lower than initial height %v", 142 block.Height, state.InitialHeight) 143 } 144 145 // Check evidence doesn't exceed the limit amount of bytes. 146 if max, got := state.ConsensusParams.Evidence.MaxBytes, block.Evidence.ByteSize(); got > max { 147 return types.NewErrEvidenceOverflow(max, got) 148 } 149 150 return nil 151 }