github.com/vipernet-xyz/tendermint-core@v0.32.0/lite2/verifier_test.go (about) 1 package lite_test 2 3 import ( 4 "fmt" 5 "testing" 6 "time" 7 8 "github.com/stretchr/testify/assert" 9 10 tmmath "github.com/tendermint/tendermint/libs/math" 11 lite "github.com/tendermint/tendermint/lite2" 12 "github.com/tendermint/tendermint/types" 13 ) 14 15 const ( 16 maxClockDrift = 10 * time.Second 17 ) 18 19 func TestVerifyAdjacentHeaders(t *testing.T) { 20 const ( 21 chainID = "TestVerifyAdjacentHeaders" 22 lastHeight = 1 23 nextHeight = 2 24 ) 25 26 var ( 27 keys = genPrivKeys(4) 28 // 20, 30, 40, 50 - the first 3 don't have 2/3, the last 3 do! 29 vals = keys.ToValidators(20, 10) 30 bTime, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z") 31 header = keys.GenSignedHeader(chainID, lastHeight, bTime, nil, vals, vals, 32 hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)) 33 ) 34 35 testCases := []struct { 36 newHeader *types.SignedHeader 37 newVals *types.ValidatorSet 38 trustingPeriod time.Duration 39 now time.Time 40 expErr error 41 expErrText string 42 }{ 43 // same header -> no error 44 0: { 45 header, 46 vals, 47 3 * time.Hour, 48 bTime.Add(2 * time.Hour), 49 nil, 50 "headers must be adjacent in height", 51 }, 52 // different chainID -> error 53 1: { 54 keys.GenSignedHeader("different-chainID", nextHeight, bTime.Add(1*time.Hour), nil, vals, vals, 55 hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)), 56 vals, 57 3 * time.Hour, 58 bTime.Add(2 * time.Hour), 59 nil, 60 "untrustedHeader.ValidateBasic failed: header belongs to another chain \"different-chainID\", not" + 61 " \"TestVerifyAdjacentHeaders\"", 62 }, 63 // new header's time is before old header's time -> error 64 2: { 65 keys.GenSignedHeader(chainID, nextHeight, bTime.Add(-1*time.Hour), nil, vals, vals, 66 hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)), 67 vals, 68 3 * time.Hour, 69 bTime.Add(2 * time.Hour), 70 nil, 71 "to be after old header time", 72 }, 73 // new header's time is from the future -> error 74 3: { 75 keys.GenSignedHeader(chainID, nextHeight, bTime.Add(3*time.Hour), nil, vals, vals, 76 hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)), 77 vals, 78 3 * time.Hour, 79 bTime.Add(2 * time.Hour), 80 nil, 81 "new header has a time from the future", 82 }, 83 // new header's time is from the future, but it's acceptable (< maxClockDrift) -> no error 84 4: { 85 keys.GenSignedHeader(chainID, nextHeight, 86 bTime.Add(2*time.Hour).Add(maxClockDrift).Add(-1*time.Millisecond), nil, vals, vals, 87 hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)), 88 vals, 89 3 * time.Hour, 90 bTime.Add(2 * time.Hour), 91 nil, 92 "", 93 }, 94 // 3/3 signed -> no error 95 5: { 96 keys.GenSignedHeader(chainID, nextHeight, bTime.Add(1*time.Hour), nil, vals, vals, 97 hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)), 98 vals, 99 3 * time.Hour, 100 bTime.Add(2 * time.Hour), 101 nil, 102 "", 103 }, 104 // 2/3 signed -> no error 105 6: { 106 keys.GenSignedHeader(chainID, nextHeight, bTime.Add(1*time.Hour), nil, vals, vals, 107 hash("app_hash"), hash("cons_hash"), hash("results_hash"), 1, len(keys)), 108 vals, 109 3 * time.Hour, 110 bTime.Add(2 * time.Hour), 111 nil, 112 "", 113 }, 114 // 1/3 signed -> error 115 7: { 116 keys.GenSignedHeader(chainID, nextHeight, bTime.Add(1*time.Hour), nil, vals, vals, 117 hash("app_hash"), hash("cons_hash"), hash("results_hash"), len(keys)-1, len(keys)), 118 vals, 119 3 * time.Hour, 120 bTime.Add(2 * time.Hour), 121 lite.ErrInvalidHeader{Reason: types.ErrNotEnoughVotingPowerSigned{Got: 50, Needed: 93}}, 122 "", 123 }, 124 // vals does not match with what we have -> error 125 8: { 126 keys.GenSignedHeader(chainID, nextHeight, bTime.Add(1*time.Hour), nil, keys.ToValidators(10, 1), vals, 127 hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)), 128 keys.ToValidators(10, 1), 129 3 * time.Hour, 130 bTime.Add(2 * time.Hour), 131 nil, 132 "to match those from new header", 133 }, 134 // vals are inconsistent with newHeader -> error 135 9: { 136 keys.GenSignedHeader(chainID, nextHeight, bTime.Add(1*time.Hour), nil, vals, vals, 137 hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)), 138 keys.ToValidators(10, 1), 139 3 * time.Hour, 140 bTime.Add(2 * time.Hour), 141 nil, 142 "to match those that were supplied", 143 }, 144 // old header has expired -> error 145 10: { 146 keys.GenSignedHeader(chainID, nextHeight, bTime.Add(1*time.Hour), nil, vals, vals, 147 hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)), 148 keys.ToValidators(10, 1), 149 1 * time.Hour, 150 bTime.Add(1 * time.Hour), 151 nil, 152 "old header has expired", 153 }, 154 } 155 156 for i, tc := range testCases { 157 tc := tc 158 t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) { 159 err := lite.VerifyAdjacent(chainID, header, tc.newHeader, tc.newVals, tc.trustingPeriod, tc.now, maxClockDrift) 160 switch { 161 case tc.expErr != nil && assert.Error(t, err): 162 assert.Equal(t, tc.expErr, err) 163 case tc.expErrText != "": 164 assert.Contains(t, err.Error(), tc.expErrText) 165 default: 166 assert.NoError(t, err) 167 } 168 }) 169 } 170 171 } 172 173 func TestVerifyNonAdjacentHeaders(t *testing.T) { 174 const ( 175 chainID = "TestVerifyNonAdjacentHeaders" 176 lastHeight = 1 177 ) 178 179 var ( 180 keys = genPrivKeys(4) 181 // 20, 30, 40, 50 - the first 3 don't have 2/3, the last 3 do! 182 vals = keys.ToValidators(20, 10) 183 bTime, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z") 184 header = keys.GenSignedHeader(chainID, lastHeight, bTime, nil, vals, vals, 185 hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)) 186 187 // 30, 40, 50 188 twoThirds = keys[1:] 189 twoThirdsVals = twoThirds.ToValidators(30, 10) 190 191 // 50 192 oneThird = keys[len(keys)-1:] 193 oneThirdVals = oneThird.ToValidators(50, 10) 194 195 // 20 196 lessThanOneThird = keys[0:1] 197 lessThanOneThirdVals = lessThanOneThird.ToValidators(20, 10) 198 ) 199 200 testCases := []struct { 201 newHeader *types.SignedHeader 202 newVals *types.ValidatorSet 203 trustingPeriod time.Duration 204 now time.Time 205 expErr error 206 expErrText string 207 }{ 208 // 3/3 new vals signed, 3/3 old vals present -> no error 209 0: { 210 keys.GenSignedHeader(chainID, 3, bTime.Add(1*time.Hour), nil, vals, vals, 211 hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)), 212 vals, 213 3 * time.Hour, 214 bTime.Add(2 * time.Hour), 215 nil, 216 "", 217 }, 218 // 2/3 new vals signed, 3/3 old vals present -> no error 219 1: { 220 keys.GenSignedHeader(chainID, 4, bTime.Add(1*time.Hour), nil, vals, vals, 221 hash("app_hash"), hash("cons_hash"), hash("results_hash"), 1, len(keys)), 222 vals, 223 3 * time.Hour, 224 bTime.Add(2 * time.Hour), 225 nil, 226 "", 227 }, 228 // 1/3 new vals signed, 3/3 old vals present -> error 229 2: { 230 keys.GenSignedHeader(chainID, 5, bTime.Add(1*time.Hour), nil, vals, vals, 231 hash("app_hash"), hash("cons_hash"), hash("results_hash"), len(keys)-1, len(keys)), 232 vals, 233 3 * time.Hour, 234 bTime.Add(2 * time.Hour), 235 lite.ErrInvalidHeader{types.ErrNotEnoughVotingPowerSigned{Got: 50, Needed: 93}}, 236 "", 237 }, 238 // 3/3 new vals signed, 2/3 old vals present -> no error 239 3: { 240 twoThirds.GenSignedHeader(chainID, 5, bTime.Add(1*time.Hour), nil, twoThirdsVals, twoThirdsVals, 241 hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(twoThirds)), 242 twoThirdsVals, 243 3 * time.Hour, 244 bTime.Add(2 * time.Hour), 245 nil, 246 "", 247 }, 248 // 3/3 new vals signed, 1/3 old vals present -> no error 249 4: { 250 oneThird.GenSignedHeader(chainID, 5, bTime.Add(1*time.Hour), nil, oneThirdVals, oneThirdVals, 251 hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(oneThird)), 252 oneThirdVals, 253 3 * time.Hour, 254 bTime.Add(2 * time.Hour), 255 nil, 256 "", 257 }, 258 // 3/3 new vals signed, less than 1/3 old vals present -> error 259 5: { 260 lessThanOneThird.GenSignedHeader(chainID, 5, bTime.Add(1*time.Hour), nil, lessThanOneThirdVals, lessThanOneThirdVals, 261 hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(lessThanOneThird)), 262 lessThanOneThirdVals, 263 3 * time.Hour, 264 bTime.Add(2 * time.Hour), 265 lite.ErrNewValSetCantBeTrusted{types.ErrNotEnoughVotingPowerSigned{Got: 20, Needed: 46}}, 266 "", 267 }, 268 } 269 270 for i, tc := range testCases { 271 tc := tc 272 t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) { 273 err := lite.VerifyNonAdjacent(chainID, header, vals, tc.newHeader, tc.newVals, tc.trustingPeriod, 274 tc.now, maxClockDrift, 275 lite.DefaultTrustLevel) 276 277 switch { 278 case tc.expErr != nil && assert.Error(t, err): 279 assert.Equal(t, tc.expErr, err) 280 case tc.expErrText != "": 281 assert.Contains(t, err.Error(), tc.expErrText) 282 default: 283 assert.NoError(t, err) 284 } 285 }) 286 } 287 } 288 289 func TestVerifyReturnsErrorIfTrustLevelIsInvalid(t *testing.T) { 290 const ( 291 chainID = "TestVerifyReturnsErrorIfTrustLevelIsInvalid" 292 lastHeight = 1 293 ) 294 295 var ( 296 keys = genPrivKeys(4) 297 // 20, 30, 40, 50 - the first 3 don't have 2/3, the last 3 do! 298 vals = keys.ToValidators(20, 10) 299 bTime, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z") 300 header = keys.GenSignedHeader(chainID, lastHeight, bTime, nil, vals, vals, 301 hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)) 302 ) 303 304 err := lite.Verify(chainID, header, vals, header, vals, 2*time.Hour, time.Now(), maxClockDrift, 305 tmmath.Fraction{Numerator: 2, Denominator: 1}) 306 assert.Error(t, err) 307 } 308 309 func TestValidateTrustLevel(t *testing.T) { 310 testCases := []struct { 311 lvl tmmath.Fraction 312 valid bool 313 }{ 314 // valid 315 0: {tmmath.Fraction{Numerator: 1, Denominator: 1}, true}, 316 1: {tmmath.Fraction{Numerator: 1, Denominator: 3}, true}, 317 2: {tmmath.Fraction{Numerator: 2, Denominator: 3}, true}, 318 3: {tmmath.Fraction{Numerator: 3, Denominator: 3}, true}, 319 4: {tmmath.Fraction{Numerator: 4, Denominator: 5}, true}, 320 321 // invalid 322 5: {tmmath.Fraction{Numerator: 6, Denominator: 5}, false}, 323 6: {tmmath.Fraction{Numerator: -1, Denominator: 3}, false}, 324 7: {tmmath.Fraction{Numerator: 0, Denominator: 1}, false}, 325 8: {tmmath.Fraction{Numerator: -1, Denominator: -3}, false}, 326 9: {tmmath.Fraction{Numerator: 0, Denominator: 0}, false}, 327 10: {tmmath.Fraction{Numerator: 1, Denominator: 0}, false}, 328 } 329 330 for _, tc := range testCases { 331 err := lite.ValidateTrustLevel(tc.lvl) 332 if !tc.valid { 333 assert.Error(t, err) 334 } else { 335 assert.NoError(t, err) 336 } 337 } 338 }