1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
func validateBlock(stateDB dbm.DB, state State, block *types.Block) error {
// Validate internal consistency.
if err := block.ValidateBasic(); err != nil {
return err
}
// Validate basic info.
if block.Version != state.Version.Consensus {
return fmt.Errorf("Wrong Block.Header.Version. Expected %v, got %v",
state.Version.Consensus,
block.Version,
)
}
if block.ChainID != state.ChainID {
return fmt.Errorf("Wrong Block.Header.ChainID. Expected %v, got %v",
state.ChainID,
block.ChainID,
)
}
if block.Height != state.LastBlockHeight+1 {
return fmt.Errorf("Wrong Block.Header.Height. Expected %v, got %v",
state.LastBlockHeight+1,
block.Height,
)
}
// Validate prev block info.
if !block.LastBlockID.Equals(state.LastBlockID) {
return fmt.Errorf("Wrong Block.Header.LastBlockID. Expected %v, got %v",
state.LastBlockID,
block.LastBlockID,
)
}
newTxs := int64(len(block.Data.Txs))
if block.TotalTxs != state.LastBlockTotalTx+newTxs {
return fmt.Errorf("Wrong Block.Header.TotalTxs. Expected %v, got %v",
state.LastBlockTotalTx+newTxs,
block.TotalTxs,
)
}
// Validate app info
if !bytes.Equal(block.AppHash, state.AppHash) {
return fmt.Errorf("Wrong Block.Header.AppHash. Expected %X, got %v",
state.AppHash,
block.AppHash,
)
}
if !bytes.Equal(block.ConsensusHash, state.ConsensusParams.Hash()) {
return fmt.Errorf("Wrong Block.Header.ConsensusHash. Expected %X, got %v",
state.ConsensusParams.Hash(),
block.ConsensusHash,
)
}
if !bytes.Equal(block.LastResultsHash, state.LastResultsHash) {
return fmt.Errorf("Wrong Block.Header.LastResultsHash. Expected %X, got %v",
state.LastResultsHash,
block.LastResultsHash,
)
}
if !bytes.Equal(block.ValidatorsHash, state.Validators.Hash()) {
return fmt.Errorf("Wrong Block.Header.ValidatorsHash. Expected %X, got %v",
state.Validators.Hash(),
block.ValidatorsHash,
)
}
if !bytes.Equal(block.NextValidatorsHash, state.NextValidators.Hash()) {
return fmt.Errorf("Wrong Block.Header.NextValidatorsHash. Expected %X, got %v",
state.NextValidators.Hash(),
block.NextValidatorsHash,
)
}
// Validate block LastCommit.
if block.Height == 1 {
if len(block.LastCommit.Precommits) != 0 {
return errors.New("Block at height 1 can't have LastCommit precommits")
}
} else {
if len(block.LastCommit.Precommits) != state.LastValidators.Size() {
return fmt.Errorf("Invalid block commit size. Expected %v, got %v",
state.LastValidators.Size(),
len(block.LastCommit.Precommits),
)
}
// 此处和其他人理解有点不一致。我认为是用状态记录的区块验证集合,跟区块中的
// 验证集合进行对比。而不是用这个的信息去验证上一个区块。
err := state.LastValidators.VerifyCommit(
state.ChainID, state.LastBlockID, block.Height-1, block.LastCommit)
if err != nil {
return err
}
}
// Validate block Time
if block.Height > 1 {
if !block.Time.After(state.LastBlockTime) {
return fmt.Errorf("Block time %v not greater than last block time %v",
block.Time,
state.LastBlockTime,
)
}
medianTime := MedianTime(block.LastCommit, state.LastValidators)
if !block.Time.Equal(medianTime) {
return fmt.Errorf("Invalid block time. Expected %v, got %v",
medianTime,
block.Time,
)
}
} else if block.Height == 1 {
genesisTime := state.LastBlockTime
if !block.Time.Equal(genesisTime) {
return fmt.Errorf("Block time %v is not equal to genesis time %v",
block.Time,
genesisTime,
)
}
}
// Limit the amount of evidence
maxEvidenceBytes := types.MaxEvidenceBytesPerBlock(state.ConsensusParams.BlockSize.MaxBytes)
evidenceBytes := int64(len(block.Evidence.Evidence)) * types.MaxEvidenceBytes
if evidenceBytes > maxEvidenceBytes {
return types.NewErrEvidenceOverflow(maxEvidenceBytes, evidenceBytes)
}
// Validate all evidence.
for _, ev := range block.Evidence.Evidence {
if err := VerifyEvidence(stateDB, state, ev); err != nil {
return types.NewErrEvidenceInvalid(ev, err)
}
}
// NOTE: We can't actually verify it's the right proposer because we dont
// know what round the block was first proposed. So just check that it's
// a legit address and a known validator.
if len(block.ProposerAddress) != crypto.AddressSize ||
!state.Validators.HasAddress(block.ProposerAddress) {
return fmt.Errorf("Block.Header.ProposerAddress, %X, is not a validator",
block.ProposerAddress,
)
}
return nil
}
|