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  }