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  }