github.com/ava-labs/avalanchego@v1.11.11/vms/proposervm/vm_byzantine_test.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package proposervm 5 6 import ( 7 "bytes" 8 "context" 9 "encoding/hex" 10 "testing" 11 "time" 12 13 "github.com/stretchr/testify/require" 14 15 "github.com/ava-labs/avalanchego/database" 16 "github.com/ava-labs/avalanchego/ids" 17 "github.com/ava-labs/avalanchego/snow/consensus/snowman" 18 "github.com/ava-labs/avalanchego/snow/consensus/snowman/snowmantest" 19 "github.com/ava-labs/avalanchego/snow/validators" 20 "github.com/ava-labs/avalanchego/vms/proposervm/block" 21 ) 22 23 // Ensure that a byzantine node issuing an invalid PreForkBlock (Y) when the 24 // parent block (X) is issued into a PostForkBlock (A) will be marked as invalid 25 // correctly. 26 // 27 // G 28 // / | 29 // A - X 30 // | 31 // Y 32 func TestInvalidByzantineProposerParent(t *testing.T) { 33 require := require.New(t) 34 35 var ( 36 activationTime = time.Unix(0, 0) 37 durangoTime = activationTime 38 ) 39 coreVM, _, proVM, _ := initTestProposerVM(t, activationTime, durangoTime, 0) 40 defer func() { 41 require.NoError(proVM.Shutdown(context.Background())) 42 }() 43 44 xBlock := snowmantest.BuildChild(snowmantest.Genesis) 45 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 46 return xBlock, nil 47 } 48 49 aBlock, err := proVM.BuildBlock(context.Background()) 50 require.NoError(err) 51 52 coreVM.BuildBlockF = nil 53 54 require.NoError(aBlock.Verify(context.Background())) 55 require.NoError(aBlock.Accept(context.Background())) 56 57 yBlock := snowmantest.BuildChild(xBlock) 58 coreVM.ParseBlockF = func(_ context.Context, blockBytes []byte) (snowman.Block, error) { 59 if !bytes.Equal(blockBytes, yBlock.Bytes()) { 60 return nil, errUnknownBlock 61 } 62 return yBlock, nil 63 } 64 65 parsedBlock, err := proVM.ParseBlock(context.Background(), yBlock.Bytes()) 66 if err != nil { 67 // If there was an error parsing, then this is fine. 68 return 69 } 70 71 // If there wasn't an error parsing - verify must return an error 72 err = parsedBlock.Verify(context.Background()) 73 require.ErrorIs(err, errUnknownBlock) 74 } 75 76 // Ensure that a byzantine node issuing an invalid PreForkBlock (Y or Z) when 77 // the parent block (X) is issued into a PostForkBlock (A) will be marked as 78 // invalid correctly. 79 // 80 // G 81 // / | 82 // A - X 83 // / \ 84 // Y Z 85 func TestInvalidByzantineProposerOracleParent(t *testing.T) { 86 require := require.New(t) 87 88 var ( 89 activationTime = time.Unix(0, 0) 90 durangoTime = activationTime 91 ) 92 coreVM, _, proVM, _ := initTestProposerVM(t, activationTime, durangoTime, 0) 93 proVM.Set(snowmantest.GenesisTimestamp) 94 defer func() { 95 require.NoError(proVM.Shutdown(context.Background())) 96 }() 97 98 xTestBlock := snowmantest.BuildChild(snowmantest.Genesis) 99 xBlock := &TestOptionsBlock{ 100 Block: *xTestBlock, 101 opts: [2]*snowmantest.Block{ 102 snowmantest.BuildChild(xTestBlock), 103 snowmantest.BuildChild(xTestBlock), 104 }, 105 } 106 107 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 108 return xBlock, nil 109 } 110 coreVM.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) { 111 switch blkID { 112 case snowmantest.GenesisID: 113 return snowmantest.Genesis, nil 114 case xBlock.ID(): 115 return xBlock, nil 116 case xBlock.opts[0].ID(): 117 return xBlock.opts[0], nil 118 case xBlock.opts[1].ID(): 119 return xBlock.opts[1], nil 120 default: 121 return nil, database.ErrNotFound 122 } 123 } 124 coreVM.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) { 125 switch { 126 case bytes.Equal(b, snowmantest.GenesisBytes): 127 return snowmantest.Genesis, nil 128 case bytes.Equal(b, xBlock.Bytes()): 129 return xBlock, nil 130 case bytes.Equal(b, xBlock.opts[0].Bytes()): 131 return xBlock.opts[0], nil 132 case bytes.Equal(b, xBlock.opts[1].Bytes()): 133 return xBlock.opts[1], nil 134 default: 135 return nil, errUnknownBlock 136 } 137 } 138 139 aBlockIntf, err := proVM.BuildBlock(context.Background()) 140 require.NoError(err) 141 142 require.IsType(&postForkBlock{}, aBlockIntf) 143 aBlock := aBlockIntf.(*postForkBlock) 144 opts, err := aBlock.Options(context.Background()) 145 require.NoError(err) 146 147 require.NoError(aBlock.Verify(context.Background())) 148 require.NoError(opts[0].Verify(context.Background())) 149 require.NoError(opts[1].Verify(context.Background())) 150 151 wrappedXBlock, err := proVM.ParseBlock(context.Background(), xBlock.Bytes()) 152 require.NoError(err) 153 154 // This should never be invoked by the consensus engine. However, it is 155 // enforced to fail verification as a failsafe. 156 err = wrappedXBlock.Verify(context.Background()) 157 require.ErrorIs(err, errUnexpectedBlockType) 158 } 159 160 // Ensure that a byzantine node issuing an invalid PostForkBlock (B) when the 161 // parent block (X) is issued into a PostForkBlock (A) will be marked as invalid 162 // correctly. 163 // 164 // G 165 // / | 166 // A - X 167 // / | 168 // B - Y 169 func TestInvalidByzantineProposerPreForkParent(t *testing.T) { 170 require := require.New(t) 171 172 var ( 173 activationTime = time.Unix(0, 0) 174 durangoTime = activationTime 175 ) 176 coreVM, _, proVM, _ := initTestProposerVM(t, activationTime, durangoTime, 0) 177 defer func() { 178 require.NoError(proVM.Shutdown(context.Background())) 179 }() 180 181 xBlock := snowmantest.BuildChild(snowmantest.Genesis) 182 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 183 return xBlock, nil 184 } 185 186 yBlock := snowmantest.BuildChild(xBlock) 187 coreVM.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) { 188 switch blkID { 189 case snowmantest.GenesisID: 190 return snowmantest.Genesis, nil 191 case xBlock.ID(): 192 return xBlock, nil 193 case yBlock.ID(): 194 return yBlock, nil 195 default: 196 return nil, errUnknownBlock 197 } 198 } 199 coreVM.ParseBlockF = func(_ context.Context, blockBytes []byte) (snowman.Block, error) { 200 switch { 201 case bytes.Equal(blockBytes, snowmantest.GenesisBytes): 202 return snowmantest.Genesis, nil 203 case bytes.Equal(blockBytes, xBlock.Bytes()): 204 return xBlock, nil 205 case bytes.Equal(blockBytes, yBlock.Bytes()): 206 return yBlock, nil 207 default: 208 return nil, errUnknownBlock 209 } 210 } 211 212 aBlock, err := proVM.BuildBlock(context.Background()) 213 require.NoError(err) 214 coreVM.BuildBlockF = nil 215 216 require.NoError(aBlock.Verify(context.Background())) 217 218 wrappedXBlock, err := proVM.ParseBlock(context.Background(), xBlock.Bytes()) 219 require.NoError(err) 220 221 // This should never be invoked by the consensus engine. However, it is 222 // enforced to fail verification as a failsafe. 223 err = wrappedXBlock.Verify(context.Background()) 224 require.ErrorIs(err, errUnexpectedBlockType) 225 } 226 227 // Ensure that a byzantine node issuing an invalid OptionBlock (B) which 228 // contains core block (Y) whose parent (G) doesn't match (B)'s parent (A)'s 229 // inner block (X) will be marked as invalid correctly. 230 // 231 // G 232 // / | \ 233 // A - X | 234 // | / 235 // B - Y 236 func TestBlockVerify_PostForkOption_FaultyParent(t *testing.T) { 237 require := require.New(t) 238 239 var ( 240 activationTime = time.Unix(0, 0) 241 durangoTime = activationTime 242 ) 243 coreVM, _, proVM, _ := initTestProposerVM(t, activationTime, durangoTime, 0) 244 proVM.Set(snowmantest.GenesisTimestamp) 245 defer func() { 246 require.NoError(proVM.Shutdown(context.Background())) 247 }() 248 249 xBlock := &TestOptionsBlock{ 250 Block: *snowmantest.BuildChild(snowmantest.Genesis), 251 opts: [2]*snowmantest.Block{ // valid blocks should reference xBlock 252 snowmantest.BuildChild(snowmantest.Genesis), 253 snowmantest.BuildChild(snowmantest.Genesis), 254 }, 255 } 256 257 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 258 return xBlock, nil 259 } 260 coreVM.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) { 261 switch blkID { 262 case snowmantest.GenesisID: 263 return snowmantest.Genesis, nil 264 case xBlock.ID(): 265 return xBlock, nil 266 case xBlock.opts[0].ID(): 267 return xBlock.opts[0], nil 268 case xBlock.opts[1].ID(): 269 return xBlock.opts[1], nil 270 default: 271 return nil, database.ErrNotFound 272 } 273 } 274 coreVM.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) { 275 switch { 276 case bytes.Equal(b, snowmantest.GenesisBytes): 277 return snowmantest.Genesis, nil 278 case bytes.Equal(b, xBlock.Bytes()): 279 return xBlock, nil 280 case bytes.Equal(b, xBlock.opts[0].Bytes()): 281 return xBlock.opts[0], nil 282 case bytes.Equal(b, xBlock.opts[1].Bytes()): 283 return xBlock.opts[1], nil 284 default: 285 return nil, errUnknownBlock 286 } 287 } 288 289 aBlockIntf, err := proVM.BuildBlock(context.Background()) 290 require.NoError(err) 291 292 require.IsType(&postForkBlock{}, aBlockIntf) 293 aBlock := aBlockIntf.(*postForkBlock) 294 opts, err := aBlock.Options(context.Background()) 295 require.NoError(err) 296 297 require.NoError(aBlock.Verify(context.Background())) 298 err = opts[0].Verify(context.Background()) 299 require.ErrorIs(err, errInnerParentMismatch) 300 err = opts[1].Verify(context.Background()) 301 require.ErrorIs(err, errInnerParentMismatch) 302 } 303 304 // ,--G ----. 305 // / \ \ 306 // A(X) B(Y) C(Z) 307 // | \_ /_____/ 308 // |\ / | 309 // | \/ | 310 // O2 O1 O3 311 // 312 // O1.parent = B (non-Oracle), O1.inner = first option of X (invalid) 313 // O2.parent = A (original), O2.inner = first option of X (valid) 314 // O3.parent = C (Oracle), O3.inner = first option of X (invalid parent) 315 func TestBlockVerify_InvalidPostForkOption(t *testing.T) { 316 require := require.New(t) 317 318 var ( 319 activationTime = time.Unix(0, 0) 320 durangoTime = activationTime 321 ) 322 coreVM, _, proVM, _ := initTestProposerVM(t, activationTime, durangoTime, 0) 323 proVM.Set(snowmantest.GenesisTimestamp) 324 defer func() { 325 require.NoError(proVM.Shutdown(context.Background())) 326 }() 327 328 // create an Oracle pre-fork block X 329 xTestBlock := snowmantest.BuildChild(snowmantest.Genesis) 330 xBlock := &TestOptionsBlock{ 331 Block: *xTestBlock, 332 opts: [2]*snowmantest.Block{ 333 snowmantest.BuildChild(xTestBlock), 334 snowmantest.BuildChild(xTestBlock), 335 }, 336 } 337 338 xInnerOptions, err := xBlock.Options(context.Background()) 339 require.NoError(err) 340 xInnerOption := xInnerOptions[0] 341 342 // create a non-Oracle pre-fork block Y 343 yBlock := snowmantest.BuildChild(snowmantest.Genesis) 344 ySlb, err := block.BuildUnsigned( 345 snowmantest.GenesisID, 346 snowmantest.GenesisTimestamp, 347 uint64(2000), 348 yBlock.Bytes(), 349 ) 350 require.NoError(err) 351 352 // create post-fork block B from Y 353 bBlock := postForkBlock{ 354 SignedBlock: ySlb, 355 postForkCommonComponents: postForkCommonComponents{ 356 vm: proVM, 357 innerBlk: yBlock, 358 }, 359 } 360 361 require.NoError(bBlock.Verify(context.Background())) 362 363 // generate O1 364 statelessOuterOption, err := block.BuildOption( 365 bBlock.ID(), 366 xInnerOption.Bytes(), 367 ) 368 require.NoError(err) 369 370 outerOption := &postForkOption{ 371 Block: statelessOuterOption, 372 postForkCommonComponents: postForkCommonComponents{ 373 vm: proVM, 374 innerBlk: xInnerOption, 375 }, 376 } 377 378 err = outerOption.Verify(context.Background()) 379 require.ErrorIs(err, errUnexpectedBlockType) 380 381 // generate A from X and O2 382 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 383 return xBlock, nil 384 } 385 aBlock, err := proVM.BuildBlock(context.Background()) 386 require.NoError(err) 387 coreVM.BuildBlockF = nil 388 require.NoError(aBlock.Verify(context.Background())) 389 390 statelessOuterOption, err = block.BuildOption( 391 aBlock.ID(), 392 xInnerOption.Bytes(), 393 ) 394 require.NoError(err) 395 396 outerOption = &postForkOption{ 397 Block: statelessOuterOption, 398 postForkCommonComponents: postForkCommonComponents{ 399 vm: proVM, 400 innerBlk: xInnerOption, 401 }, 402 } 403 404 require.NoError(outerOption.Verify(context.Background())) 405 406 // create an Oracle pre-fork block Z 407 // create post-fork block B from Y 408 zTestBlock := snowmantest.BuildChild(snowmantest.Genesis) 409 zBlock := &TestOptionsBlock{ 410 Block: *zTestBlock, 411 opts: [2]*snowmantest.Block{ 412 snowmantest.BuildChild(zTestBlock), 413 snowmantest.BuildChild(zTestBlock), 414 }, 415 } 416 417 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 418 return zBlock, nil 419 } 420 cBlock, err := proVM.BuildBlock(context.Background()) 421 require.NoError(err) 422 coreVM.BuildBlockF = nil 423 require.NoError(cBlock.Verify(context.Background())) 424 425 // generate O3 426 statelessOuterOption, err = block.BuildOption( 427 cBlock.ID(), 428 xInnerOption.Bytes(), 429 ) 430 require.NoError(err) 431 432 outerOption = &postForkOption{ 433 Block: statelessOuterOption, 434 postForkCommonComponents: postForkCommonComponents{ 435 vm: proVM, 436 innerBlk: xInnerOption, 437 }, 438 } 439 440 err = outerOption.Verify(context.Background()) 441 require.ErrorIs(err, errInnerParentMismatch) 442 } 443 444 func TestGetBlock_MutatedSignature(t *testing.T) { 445 require := require.New(t) 446 447 var ( 448 activationTime = time.Unix(0, 0) 449 durangoTime = activationTime 450 ) 451 coreVM, valState, proVM, _ := initTestProposerVM(t, activationTime, durangoTime, 0) 452 defer func() { 453 require.NoError(proVM.Shutdown(context.Background())) 454 }() 455 456 // Make sure that we will be sampled to perform the proposals. 457 valState.GetValidatorSetF = func(context.Context, uint64, ids.ID) (map[ids.NodeID]*validators.GetValidatorOutput, error) { 458 return map[ids.NodeID]*validators.GetValidatorOutput{ 459 proVM.ctx.NodeID: { 460 NodeID: proVM.ctx.NodeID, 461 Weight: 10, 462 }, 463 }, nil 464 } 465 466 proVM.Set(snowmantest.GenesisTimestamp) 467 468 // Create valid core blocks to build our chain on. 469 coreBlk0 := snowmantest.BuildChild(snowmantest.Genesis) 470 coreBlk1 := snowmantest.BuildChild(coreBlk0) 471 coreVM.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) { 472 switch blkID { 473 case snowmantest.GenesisID: 474 return snowmantest.Genesis, nil 475 case coreBlk0.ID(): 476 return coreBlk0, nil 477 case coreBlk1.ID(): 478 return coreBlk1, nil 479 default: 480 return nil, database.ErrNotFound 481 } 482 } 483 coreVM.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) { 484 switch { 485 case bytes.Equal(b, snowmantest.GenesisBytes): 486 return snowmantest.Genesis, nil 487 case bytes.Equal(b, coreBlk0.Bytes()): 488 return coreBlk0, nil 489 case bytes.Equal(b, coreBlk1.Bytes()): 490 return coreBlk1, nil 491 default: 492 return nil, errUnknownBlock 493 } 494 } 495 496 // Build the first proposal block 497 coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) { 498 return coreBlk0, nil 499 } 500 501 builtBlk0, err := proVM.BuildBlock(context.Background()) 502 require.NoError(err) 503 504 require.NoError(builtBlk0.Verify(context.Background())) 505 506 require.NoError(proVM.SetPreference(context.Background(), builtBlk0.ID())) 507 508 // The second proposal block will need to be signed because the timestamp 509 // hasn't moved forward 510 511 // Craft what would be the next block, but with an invalid signature: 512 // ID: 2R3Uz98YmxHUJARWv6suApPdAbbZ7X7ipat1gZuZNNhC5wPwJW 513 // Valid Bytes: 000000000000fd81ce4f1ab2650176d46a3d1fbb593af5717a2ada7dabdcef19622325a8ce8400000000000003e800000000000006d0000004a13082049d30820285a003020102020100300d06092a864886f70d01010b050030003020170d3939313233313030303030305a180f32313231313132333130313030305a300030820222300d06092a864886f70d01010105000382020f003082020a0282020100b9c3615c42d501f3b9d21ed127b31855827dbe12652e6e6f278991a3ad1ca55e2241b1cac69a0aeeefdd913db8ae445ff847789fdcbc1cbe6cce0a63109d1c1fb9d441c524a6eb1412f9b8090f1507e3e50a725f9d0a9d5db424ea229a7c11d8b91c73fecbad31c7b216bb2ac5e4d5ff080a80fabc73b34beb8fa46513ab59d489ce3f273c0edab43ded4d4914e081e6e850f9e502c3c4a54afc8a3a89d889aec275b7162a7616d53a61cd3ee466394212e5bef307790100142ad9e0b6c95ad2424c6e84d06411ad066d0c37d4d14125bae22b49ad2a761a09507bbfe43d023696d278d9fbbaf06c4ff677356113d3105e248078c33caed144d85929b1dd994df33c5d3445675104659ca9642c269b5cfa39c7bad5e399e7ebce3b5e6661f989d5f388006ebd90f0e035d533f5662cb925df8744f61289e66517b51b9a2f54792dca9078d5e12bf8ad79e35a68d4d661d15f0d3029d6c5903c845323d5426e49deaa2be2bc261423a9cd77df9a2706afaca27f589cc2c8f53e2a1f90eb5a3f8bcee0769971db6bacaec265d86b39380f69e3e0e06072de986feede26fe856c55e24e88ee5ac342653ac55a04e21b8517310c717dff0e22825c0944c6ba263f8f060099ea6e44a57721c7aa54e2790a4421fb85e3347e4572cba44e62b2cad19c1623c1cab4a715078e56458554cef8442769e6d5dd7f99a6234653a46828804f0203010001a320301e300e0603551d0f0101ff0404030204b0300c0603551d130101ff04023000300d06092a864886f70d01010b050003820201004ee2229d354720a751e2d2821134994f5679997113192626cf61594225cfdf51e6479e2c17e1013ab9dceb713bc0f24649e5cab463a8cf8617816ed736ac5251a853ff35e859ac6853ebb314f967ff7867c53512d42e329659375682c854ca9150cfa4c3964680e7650beb93e8b4a0d6489a9ca0ce0104752ba4d9cf3e2dc9436b56ecd0bd2e33cbbeb5a107ec4fd6f41a943c8bee06c0b32f4291a3e3759a7984d919a97d5d6517b841053df6e795ed33b52ed5e41357c3e431beb725e4e4f2ef956c44fd1f76fa4d847602e491c3585a90cdccfff982405d388b83d6f32ea16da2f5e4595926a7d26078e32992179032d30831b1f1b42de1781c507536a49adb4c95bad04c171911eed30d63c73712873d1e8094355efb9aeee0c16f8599575fd7f8bb027024bad63b097d2230d8f0ba12a8ed23e618adc3d7cb6a63e02b82a6d4d74b21928dbcb6d3788c6fd45022d69f3ab94d914d97cd651db662e92918a5d891ef730a813f03aade2fe385b61f44840f8925ad3345df1c82c9de882bb7184b4cd0bbd9db8322aaedb4ff86e5be9635987e6c40455ab9b063cdb423bee2edcac47cf654487e9286f33bdbad10018f4db9564cee6e048570e1517a2e396501b5978a53d10a548aed26938c2f9aada3ae62d3fdae486deb9413dffb6524666453633d665c3712d0fec9f844632b2b3eaf0267ca495eb41dba8273862609de00000001020000020098147a41989d8626f63d0966b39376143e45ea6e21b62761a115660d88db9cba37be71d1e1153e7546eb075749122449f2f3f5984e51773f082700d847334da35babe72a66e5a49c9a96cd763bdd94258263ae92d30da65d7c606482d0afe9f4f884f4f6c33d6d8e1c0c71061244ebec6a9dbb9b78bfbb71dec572aa0c0d8e532bf779457e05412b75acf12f35c75917a3eda302aaa27c3090e93bf5de0c3e30968cf8ba025b91962118bbdb6612bf682ba6e87ae6cd1a5034c89559b76af870395dc17ec592e9dbb185633aa1604f8d648f82142a2d1a4dabd91f816b34e73120a70d061e64e6da62ba434fd0cdf7296aa67fd5e0432ef8cee67c1b59aee91c99288c17a8511d96ba7339fb4ae5da453289aa7a9fab00d37035accae24eef0eaf517148e67bdc76adaac2429508d642df3033ad6c9e3fb53057244c1295f2ed3ac66731f77178fccb7cc4fd40778ccb061e5d53cd0669371d8d355a4a733078a9072835b5564a52a50f5db8525d2ee00466124a8d40d9959281b86a789bd0769f3fb0deb89f0eb9cfe036ff8a0011f52ca551c30202f46680acfa656ccf32a4e8a7121ef52442128409dc40d21d61205839170c7b022f573c2cfdaa362df22e708e7572b9b77f4fb20fe56b122bcb003566e20caef289f9d7992c2f1ad0c8366f71e8889390e0d14e2e76c56b515933b0c337ac6bfcf76d33e2ba50cb62eb71 514 // Invalid Bytes: 000000000000fd81ce4f1ab2650176d46a3d1fbb593af5717a2ada7dabdcef19622325a8ce8400000000000003e800000000000006d0000004a13082049d30820285a003020102020100300d06092a864886f70d01010b050030003020170d3939313233313030303030305a180f32313231313132333130313030305a300030820222300d06092a864886f70d01010105000382020f003082020a0282020100b9c3615c42d501f3b9d21ed127b31855827dbe12652e6e6f278991a3ad1ca55e2241b1cac69a0aeeefdd913db8ae445ff847789fdcbc1cbe6cce0a63109d1c1fb9d441c524a6eb1412f9b8090f1507e3e50a725f9d0a9d5db424ea229a7c11d8b91c73fecbad31c7b216bb2ac5e4d5ff080a80fabc73b34beb8fa46513ab59d489ce3f273c0edab43ded4d4914e081e6e850f9e502c3c4a54afc8a3a89d889aec275b7162a7616d53a61cd3ee466394212e5bef307790100142ad9e0b6c95ad2424c6e84d06411ad066d0c37d4d14125bae22b49ad2a761a09507bbfe43d023696d278d9fbbaf06c4ff677356113d3105e248078c33caed144d85929b1dd994df33c5d3445675104659ca9642c269b5cfa39c7bad5e399e7ebce3b5e6661f989d5f388006ebd90f0e035d533f5662cb925df8744f61289e66517b51b9a2f54792dca9078d5e12bf8ad79e35a68d4d661d15f0d3029d6c5903c845323d5426e49deaa2be2bc261423a9cd77df9a2706afaca27f589cc2c8f53e2a1f90eb5a3f8bcee0769971db6bacaec265d86b39380f69e3e0e06072de986feede26fe856c55e24e88ee5ac342653ac55a04e21b8517310c717dff0e22825c0944c6ba263f8f060099ea6e44a57721c7aa54e2790a4421fb85e3347e4572cba44e62b2cad19c1623c1cab4a715078e56458554cef8442769e6d5dd7f99a6234653a46828804f0203010001a320301e300e0603551d0f0101ff0404030204b0300c0603551d130101ff04023000300d06092a864886f70d01010b050003820201004ee2229d354720a751e2d2821134994f5679997113192626cf61594225cfdf51e6479e2c17e1013ab9dceb713bc0f24649e5cab463a8cf8617816ed736ac5251a853ff35e859ac6853ebb314f967ff7867c53512d42e329659375682c854ca9150cfa4c3964680e7650beb93e8b4a0d6489a9ca0ce0104752ba4d9cf3e2dc9436b56ecd0bd2e33cbbeb5a107ec4fd6f41a943c8bee06c0b32f4291a3e3759a7984d919a97d5d6517b841053df6e795ed33b52ed5e41357c3e431beb725e4e4f2ef956c44fd1f76fa4d847602e491c3585a90cdccfff982405d388b83d6f32ea16da2f5e4595926a7d26078e32992179032d30831b1f1b42de1781c507536a49adb4c95bad04c171911eed30d63c73712873d1e8094355efb9aeee0c16f8599575fd7f8bb027024bad63b097d2230d8f0ba12a8ed23e618adc3d7cb6a63e02b82a6d4d74b21928dbcb6d3788c6fd45022d69f3ab94d914d97cd651db662e92918a5d891ef730a813f03aade2fe385b61f44840f8925ad3345df1c82c9de882bb7184b4cd0bbd9db8322aaedb4ff86e5be9635987e6c40455ab9b063cdb423bee2edcac47cf654487e9286f33bdbad10018f4db9564cee6e048570e1517a2e396501b5978a53d10a548aed26938c2f9aada3ae62d3fdae486deb9413dffb6524666453633d665c3712d0fec9f844632b2b3eaf0267ca495eb41dba8273862609de00000001020000000101 515 invalidBlkBytesHex := "000000000000fd81ce4f1ab2650176d46a3d1fbb593af5717a2ada7dabdcef19622325a8ce8400000000000003e800000000000006d0000004a13082049d30820285a003020102020100300d06092a864886f70d01010b050030003020170d3939313233313030303030305a180f32313231313132333130313030305a300030820222300d06092a864886f70d01010105000382020f003082020a0282020100b9c3615c42d501f3b9d21ed127b31855827dbe12652e6e6f278991a3ad1ca55e2241b1cac69a0aeeefdd913db8ae445ff847789fdcbc1cbe6cce0a63109d1c1fb9d441c524a6eb1412f9b8090f1507e3e50a725f9d0a9d5db424ea229a7c11d8b91c73fecbad31c7b216bb2ac5e4d5ff080a80fabc73b34beb8fa46513ab59d489ce3f273c0edab43ded4d4914e081e6e850f9e502c3c4a54afc8a3a89d889aec275b7162a7616d53a61cd3ee466394212e5bef307790100142ad9e0b6c95ad2424c6e84d06411ad066d0c37d4d14125bae22b49ad2a761a09507bbfe43d023696d278d9fbbaf06c4ff677356113d3105e248078c33caed144d85929b1dd994df33c5d3445675104659ca9642c269b5cfa39c7bad5e399e7ebce3b5e6661f989d5f388006ebd90f0e035d533f5662cb925df8744f61289e66517b51b9a2f54792dca9078d5e12bf8ad79e35a68d4d661d15f0d3029d6c5903c845323d5426e49deaa2be2bc261423a9cd77df9a2706afaca27f589cc2c8f53e2a1f90eb5a3f8bcee0769971db6bacaec265d86b39380f69e3e0e06072de986feede26fe856c55e24e88ee5ac342653ac55a04e21b8517310c717dff0e22825c0944c6ba263f8f060099ea6e44a57721c7aa54e2790a4421fb85e3347e4572cba44e62b2cad19c1623c1cab4a715078e56458554cef8442769e6d5dd7f99a6234653a46828804f0203010001a320301e300e0603551d0f0101ff0404030204b0300c0603551d130101ff04023000300d06092a864886f70d01010b050003820201004ee2229d354720a751e2d2821134994f5679997113192626cf61594225cfdf51e6479e2c17e1013ab9dceb713bc0f24649e5cab463a8cf8617816ed736ac5251a853ff35e859ac6853ebb314f967ff7867c53512d42e329659375682c854ca9150cfa4c3964680e7650beb93e8b4a0d6489a9ca0ce0104752ba4d9cf3e2dc9436b56ecd0bd2e33cbbeb5a107ec4fd6f41a943c8bee06c0b32f4291a3e3759a7984d919a97d5d6517b841053df6e795ed33b52ed5e41357c3e431beb725e4e4f2ef956c44fd1f76fa4d847602e491c3585a90cdccfff982405d388b83d6f32ea16da2f5e4595926a7d26078e32992179032d30831b1f1b42de1781c507536a49adb4c95bad04c171911eed30d63c73712873d1e8094355efb9aeee0c16f8599575fd7f8bb027024bad63b097d2230d8f0ba12a8ed23e618adc3d7cb6a63e02b82a6d4d74b21928dbcb6d3788c6fd45022d69f3ab94d914d97cd651db662e92918a5d891ef730a813f03aade2fe385b61f44840f8925ad3345df1c82c9de882bb7184b4cd0bbd9db8322aaedb4ff86e5be9635987e6c40455ab9b063cdb423bee2edcac47cf654487e9286f33bdbad10018f4db9564cee6e048570e1517a2e396501b5978a53d10a548aed26938c2f9aada3ae62d3fdae486deb9413dffb6524666453633d665c3712d0fec9f844632b2b3eaf0267ca495eb41dba8273862609de00000001020000000101" 516 invalidBlkBytes, err := hex.DecodeString(invalidBlkBytesHex) 517 require.NoError(err) 518 519 invalidBlk, err := proVM.ParseBlock(context.Background(), invalidBlkBytes) 520 if err != nil { 521 // Not being able to parse an invalid block is fine. 522 t.Skip(err) 523 } 524 525 err = invalidBlk.Verify(context.Background()) 526 require.ErrorIs(err, database.ErrNotFound) 527 528 // Note that the invalidBlk.ID() is the same as the correct blk ID because 529 // the signature isn't part of the blk ID. 530 blkID, err := ids.FromString("2R3Uz98YmxHUJARWv6suApPdAbbZ7X7ipat1gZuZNNhC5wPwJW") 531 require.NoError(err) 532 require.Equal(blkID, invalidBlk.ID()) 533 534 // GetBlock shouldn't really be able to succeed, as we don't have a valid 535 // representation of [blkID] 536 proVM.innerBlkCache.Flush() // So we don't get from the cache 537 fetchedBlk, err := proVM.GetBlock(context.Background(), blkID) 538 if err != nil { 539 t.Skip(err) 540 } 541 542 // GetBlock returned, so it must have somehow gotten a valid representation 543 // of [blkID]. 544 require.NoError(fetchedBlk.Verify(context.Background())) 545 }