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