github.com/ava-labs/avalanchego@v1.11.11/vms/proposervm/post_fork_option_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  	"testing"
    10  	"time"
    11  
    12  	"github.com/prometheus/client_golang/prometheus"
    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"
    18  	"github.com/ava-labs/avalanchego/snow/consensus/snowman"
    19  	"github.com/ava-labs/avalanchego/snow/consensus/snowman/snowmantest"
    20  	"github.com/ava-labs/avalanchego/snow/engine/common"
    21  	"github.com/ava-labs/avalanchego/snow/snowtest"
    22  	"github.com/ava-labs/avalanchego/upgrade/upgradetest"
    23  	"github.com/ava-labs/avalanchego/vms/proposervm/block"
    24  )
    25  
    26  var _ snowman.OracleBlock = (*TestOptionsBlock)(nil)
    27  
    28  type TestOptionsBlock struct {
    29  	snowmantest.Block
    30  	opts    [2]*snowmantest.Block
    31  	optsErr error
    32  }
    33  
    34  func (tob TestOptionsBlock) Options(context.Context) ([2]snowman.Block, error) {
    35  	return [2]snowman.Block{tob.opts[0], tob.opts[1]}, tob.optsErr
    36  }
    37  
    38  // ProposerBlock.Verify tests section
    39  func TestBlockVerify_PostForkOption_ParentChecks(t *testing.T) {
    40  	require := require.New(t)
    41  
    42  	var (
    43  		activationTime = time.Unix(0, 0)
    44  		durangoTime    = activationTime
    45  	)
    46  	coreVM, _, proVM, _ := initTestProposerVM(t, activationTime, durangoTime, 0)
    47  	defer func() {
    48  		require.NoError(proVM.Shutdown(context.Background()))
    49  	}()
    50  
    51  	// create post fork oracle block ...
    52  	coreTestBlk := snowmantest.BuildChild(snowmantest.Genesis)
    53  	preferredBlk := snowmantest.BuildChild(coreTestBlk)
    54  	oracleCoreBlk := &TestOptionsBlock{
    55  		Block: *coreTestBlk,
    56  		opts: [2]*snowmantest.Block{
    57  			preferredBlk,
    58  			snowmantest.BuildChild(coreTestBlk),
    59  		},
    60  	}
    61  
    62  	coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) {
    63  		return oracleCoreBlk, nil
    64  	}
    65  	coreVM.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
    66  		switch blkID {
    67  		case snowmantest.GenesisID:
    68  			return snowmantest.Genesis, nil
    69  		case oracleCoreBlk.ID():
    70  			return oracleCoreBlk, nil
    71  		case oracleCoreBlk.opts[0].ID():
    72  			return oracleCoreBlk.opts[0], nil
    73  		case oracleCoreBlk.opts[1].ID():
    74  			return oracleCoreBlk.opts[1], nil
    75  		default:
    76  			return nil, database.ErrNotFound
    77  		}
    78  	}
    79  	coreVM.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) {
    80  		switch {
    81  		case bytes.Equal(b, snowmantest.GenesisBytes):
    82  			return snowmantest.Genesis, nil
    83  		case bytes.Equal(b, oracleCoreBlk.Bytes()):
    84  			return oracleCoreBlk, nil
    85  		case bytes.Equal(b, oracleCoreBlk.opts[0].Bytes()):
    86  			return oracleCoreBlk.opts[0], nil
    87  		case bytes.Equal(b, oracleCoreBlk.opts[1].Bytes()):
    88  			return oracleCoreBlk.opts[1], nil
    89  		default:
    90  			return nil, errUnknownBlock
    91  		}
    92  	}
    93  
    94  	parentBlk, err := proVM.BuildBlock(context.Background())
    95  	require.NoError(err)
    96  
    97  	require.NoError(parentBlk.Verify(context.Background()))
    98  	require.NoError(proVM.SetPreference(context.Background(), parentBlk.ID()))
    99  
   100  	// retrieve options ...
   101  	require.IsType(&postForkBlock{}, parentBlk)
   102  	postForkOracleBlk := parentBlk.(*postForkBlock)
   103  	opts, err := postForkOracleBlk.Options(context.Background())
   104  	require.NoError(err)
   105  	require.IsType(&postForkOption{}, opts[0])
   106  
   107  	// ... and verify them
   108  	require.NoError(opts[0].Verify(context.Background()))
   109  	require.NoError(opts[1].Verify(context.Background()))
   110  
   111  	// show we can build on options
   112  	require.NoError(proVM.SetPreference(context.Background(), opts[0].ID()))
   113  
   114  	childCoreBlk := snowmantest.BuildChild(preferredBlk)
   115  	coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) {
   116  		return childCoreBlk, nil
   117  	}
   118  	require.NoError(waitForProposerWindow(proVM, opts[0], postForkOracleBlk.PChainHeight()))
   119  
   120  	proChild, err := proVM.BuildBlock(context.Background())
   121  	require.NoError(err)
   122  	require.IsType(&postForkBlock{}, proChild)
   123  	require.NoError(proChild.Verify(context.Background()))
   124  }
   125  
   126  // ProposerBlock.Accept tests section
   127  func TestBlockVerify_PostForkOption_CoreBlockVerifyIsCalledOnce(t *testing.T) {
   128  	require := require.New(t)
   129  
   130  	// Verify an option once; then show that another verify call would not call coreBlk.Verify()
   131  	var (
   132  		activationTime = time.Unix(0, 0)
   133  		durangoTime    = activationTime
   134  	)
   135  	coreVM, _, proVM, _ := initTestProposerVM(t, activationTime, durangoTime, 0)
   136  	defer func() {
   137  		require.NoError(proVM.Shutdown(context.Background()))
   138  	}()
   139  
   140  	// create post fork oracle block ...
   141  	coreTestBlk := snowmantest.BuildChild(snowmantest.Genesis)
   142  	coreOpt0 := snowmantest.BuildChild(coreTestBlk)
   143  	coreOpt1 := snowmantest.BuildChild(coreTestBlk)
   144  	oracleCoreBlk := &TestOptionsBlock{
   145  		Block: *coreTestBlk,
   146  		opts: [2]*snowmantest.Block{
   147  			coreOpt0,
   148  			coreOpt1,
   149  		},
   150  	}
   151  
   152  	coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) {
   153  		return oracleCoreBlk, nil
   154  	}
   155  	coreVM.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
   156  		switch blkID {
   157  		case snowmantest.GenesisID:
   158  			return snowmantest.Genesis, nil
   159  		case oracleCoreBlk.ID():
   160  			return oracleCoreBlk, nil
   161  		case oracleCoreBlk.opts[0].ID():
   162  			return oracleCoreBlk.opts[0], nil
   163  		case oracleCoreBlk.opts[1].ID():
   164  			return oracleCoreBlk.opts[1], nil
   165  		default:
   166  			return nil, database.ErrNotFound
   167  		}
   168  	}
   169  	coreVM.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) {
   170  		switch {
   171  		case bytes.Equal(b, snowmantest.GenesisBytes):
   172  			return snowmantest.Genesis, nil
   173  		case bytes.Equal(b, oracleCoreBlk.Bytes()):
   174  			return oracleCoreBlk, nil
   175  		case bytes.Equal(b, oracleCoreBlk.opts[0].Bytes()):
   176  			return oracleCoreBlk.opts[0], nil
   177  		case bytes.Equal(b, oracleCoreBlk.opts[1].Bytes()):
   178  			return oracleCoreBlk.opts[1], nil
   179  		default:
   180  			return nil, errUnknownBlock
   181  		}
   182  	}
   183  
   184  	parentBlk, err := proVM.BuildBlock(context.Background())
   185  	require.NoError(err)
   186  
   187  	require.NoError(parentBlk.Verify(context.Background()))
   188  	require.NoError(proVM.SetPreference(context.Background(), parentBlk.ID()))
   189  
   190  	// retrieve options ...
   191  	require.IsType(&postForkBlock{}, parentBlk)
   192  	postForkOracleBlk := parentBlk.(*postForkBlock)
   193  	opts, err := postForkOracleBlk.Options(context.Background())
   194  	require.NoError(err)
   195  	require.IsType(&postForkOption{}, opts[0])
   196  
   197  	// ... and verify them the first time
   198  	require.NoError(opts[0].Verify(context.Background()))
   199  	require.NoError(opts[1].Verify(context.Background()))
   200  
   201  	// set error on coreBlock.Verify and recall Verify()
   202  	coreOpt0.VerifyV = errDuplicateVerify
   203  	coreOpt1.VerifyV = errDuplicateVerify
   204  
   205  	// ... and verify them again. They verify without call to innerBlk
   206  	require.NoError(opts[0].Verify(context.Background()))
   207  	require.NoError(opts[1].Verify(context.Background()))
   208  }
   209  
   210  func TestBlockAccept_PostForkOption_SetsLastAcceptedBlock(t *testing.T) {
   211  	require := require.New(t)
   212  
   213  	var (
   214  		activationTime = time.Unix(0, 0)
   215  		durangoTime    = activationTime
   216  	)
   217  	coreVM, _, proVM, _ := initTestProposerVM(t, activationTime, durangoTime, 0)
   218  	defer func() {
   219  		require.NoError(proVM.Shutdown(context.Background()))
   220  	}()
   221  
   222  	// create post fork oracle block ...
   223  	coreTestBlk := snowmantest.BuildChild(snowmantest.Genesis)
   224  	oracleCoreBlk := &TestOptionsBlock{
   225  		Block: *coreTestBlk,
   226  		opts: [2]*snowmantest.Block{
   227  			snowmantest.BuildChild(coreTestBlk),
   228  			snowmantest.BuildChild(coreTestBlk),
   229  		},
   230  	}
   231  
   232  	coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) {
   233  		return oracleCoreBlk, nil
   234  	}
   235  	coreVM.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
   236  		switch blkID {
   237  		case snowmantest.GenesisID:
   238  			return snowmantest.Genesis, nil
   239  		case oracleCoreBlk.ID():
   240  			return oracleCoreBlk, nil
   241  		case oracleCoreBlk.opts[0].ID():
   242  			return oracleCoreBlk.opts[0], nil
   243  		case oracleCoreBlk.opts[1].ID():
   244  			return oracleCoreBlk.opts[1], nil
   245  		default:
   246  			return nil, database.ErrNotFound
   247  		}
   248  	}
   249  	coreVM.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) {
   250  		switch {
   251  		case bytes.Equal(b, snowmantest.GenesisBytes):
   252  			return snowmantest.Genesis, nil
   253  		case bytes.Equal(b, oracleCoreBlk.Bytes()):
   254  			return oracleCoreBlk, nil
   255  		case bytes.Equal(b, oracleCoreBlk.opts[0].Bytes()):
   256  			return oracleCoreBlk.opts[0], nil
   257  		case bytes.Equal(b, oracleCoreBlk.opts[1].Bytes()):
   258  			return oracleCoreBlk.opts[1], nil
   259  		default:
   260  			return nil, errUnknownBlock
   261  		}
   262  	}
   263  
   264  	parentBlk, err := proVM.BuildBlock(context.Background())
   265  	require.NoError(err)
   266  
   267  	// accept oracle block
   268  	require.NoError(parentBlk.Accept(context.Background()))
   269  
   270  	coreVM.LastAcceptedF = snowmantest.MakeLastAcceptedBlockF(
   271  		[]*snowmantest.Block{
   272  			snowmantest.Genesis,
   273  			&oracleCoreBlk.Block,
   274  		},
   275  		oracleCoreBlk.opts[:],
   276  	)
   277  	acceptedID, err := proVM.LastAccepted(context.Background())
   278  	require.NoError(err)
   279  	require.Equal(parentBlk.ID(), acceptedID)
   280  
   281  	// accept one of the options
   282  	require.IsType(&postForkBlock{}, parentBlk)
   283  	postForkOracleBlk := parentBlk.(*postForkBlock)
   284  	opts, err := postForkOracleBlk.Options(context.Background())
   285  	require.NoError(err)
   286  
   287  	require.NoError(opts[0].Accept(context.Background()))
   288  
   289  	acceptedID, err = proVM.LastAccepted(context.Background())
   290  	require.NoError(err)
   291  	require.Equal(opts[0].ID(), acceptedID)
   292  }
   293  
   294  // ProposerBlock.Reject tests section
   295  func TestBlockReject_InnerBlockIsNotRejected(t *testing.T) {
   296  	require := require.New(t)
   297  
   298  	var (
   299  		activationTime = time.Unix(0, 0)
   300  		durangoTime    = activationTime
   301  	)
   302  	coreVM, _, proVM, _ := initTestProposerVM(t, activationTime, durangoTime, 0)
   303  	defer func() {
   304  		require.NoError(proVM.Shutdown(context.Background()))
   305  	}()
   306  
   307  	// create post fork oracle block ...
   308  	coreTestBlk := snowmantest.BuildChild(snowmantest.Genesis)
   309  	oracleCoreBlk := &TestOptionsBlock{
   310  		Block: *coreTestBlk,
   311  		opts: [2]*snowmantest.Block{
   312  			snowmantest.BuildChild(coreTestBlk),
   313  			snowmantest.BuildChild(coreTestBlk),
   314  		},
   315  	}
   316  
   317  	coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) {
   318  		return oracleCoreBlk, nil
   319  	}
   320  	coreVM.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
   321  		switch blkID {
   322  		case snowmantest.GenesisID:
   323  			return snowmantest.Genesis, nil
   324  		case oracleCoreBlk.ID():
   325  			return oracleCoreBlk, nil
   326  		case oracleCoreBlk.opts[0].ID():
   327  			return oracleCoreBlk.opts[0], nil
   328  		case oracleCoreBlk.opts[1].ID():
   329  			return oracleCoreBlk.opts[1], nil
   330  		default:
   331  			return nil, database.ErrNotFound
   332  		}
   333  	}
   334  	coreVM.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) {
   335  		switch {
   336  		case bytes.Equal(b, snowmantest.GenesisBytes):
   337  			return snowmantest.Genesis, nil
   338  		case bytes.Equal(b, oracleCoreBlk.Bytes()):
   339  			return oracleCoreBlk, nil
   340  		case bytes.Equal(b, oracleCoreBlk.opts[0].Bytes()):
   341  			return oracleCoreBlk.opts[0], nil
   342  		case bytes.Equal(b, oracleCoreBlk.opts[1].Bytes()):
   343  			return oracleCoreBlk.opts[1], nil
   344  		default:
   345  			return nil, errUnknownBlock
   346  		}
   347  	}
   348  
   349  	builtBlk, err := proVM.BuildBlock(context.Background())
   350  	require.NoError(err)
   351  
   352  	// reject oracle block
   353  	require.NoError(builtBlk.Reject(context.Background()))
   354  	require.NotEqual(snowtest.Rejected, oracleCoreBlk.Status)
   355  
   356  	// reject an option
   357  	require.IsType(&postForkBlock{}, builtBlk)
   358  	postForkOracleBlk := builtBlk.(*postForkBlock)
   359  	opts, err := postForkOracleBlk.Options(context.Background())
   360  	require.NoError(err)
   361  
   362  	require.NoError(opts[0].Reject(context.Background()))
   363  	require.NotEqual(snowtest.Rejected, oracleCoreBlk.opts[0].Status)
   364  }
   365  
   366  func TestBlockVerify_PostForkOption_ParentIsNotOracleWithError(t *testing.T) {
   367  	require := require.New(t)
   368  
   369  	// Verify an option once; then show that another verify call would not call coreBlk.Verify()
   370  	var (
   371  		activationTime = time.Unix(0, 0)
   372  		durangoTime    = activationTime
   373  	)
   374  	coreVM, _, proVM, _ := initTestProposerVM(t, activationTime, durangoTime, 0)
   375  	defer func() {
   376  		require.NoError(proVM.Shutdown(context.Background()))
   377  	}()
   378  
   379  	coreTestBlk := snowmantest.BuildChild(snowmantest.Genesis)
   380  	coreBlk := &TestOptionsBlock{
   381  		Block:   *coreTestBlk,
   382  		optsErr: snowman.ErrNotOracle,
   383  	}
   384  
   385  	coreChildBlk := snowmantest.BuildChild(coreTestBlk)
   386  
   387  	coreVM.BuildBlockF = func(context.Context) (snowman.Block, error) {
   388  		return coreBlk, nil
   389  	}
   390  	coreVM.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
   391  		switch blkID {
   392  		case snowmantest.GenesisID:
   393  			return snowmantest.Genesis, nil
   394  		case coreBlk.ID():
   395  			return coreBlk, nil
   396  		case coreChildBlk.ID():
   397  			return coreChildBlk, nil
   398  		default:
   399  			return nil, database.ErrNotFound
   400  		}
   401  	}
   402  	coreVM.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) {
   403  		switch {
   404  		case bytes.Equal(b, snowmantest.GenesisBytes):
   405  			return snowmantest.Genesis, nil
   406  		case bytes.Equal(b, coreBlk.Bytes()):
   407  			return coreBlk, nil
   408  		case bytes.Equal(b, coreChildBlk.Bytes()):
   409  			return coreChildBlk, nil
   410  		default:
   411  			return nil, errUnknownBlock
   412  		}
   413  	}
   414  
   415  	parentBlk, err := proVM.BuildBlock(context.Background())
   416  	require.NoError(err)
   417  
   418  	require.IsType(&postForkBlock{}, parentBlk)
   419  	postForkBlk := parentBlk.(*postForkBlock)
   420  	_, err = postForkBlk.Options(context.Background())
   421  	require.Equal(snowman.ErrNotOracle, err)
   422  
   423  	// Build the child
   424  	statelessChild, err := block.BuildOption(
   425  		postForkBlk.ID(),
   426  		coreChildBlk.Bytes(),
   427  	)
   428  	require.NoError(err)
   429  
   430  	invalidChild, err := proVM.ParseBlock(context.Background(), statelessChild.Bytes())
   431  	if err != nil {
   432  		// A failure to parse is okay here
   433  		return
   434  	}
   435  
   436  	err = invalidChild.Verify(context.Background())
   437  	require.ErrorIs(err, database.ErrNotFound)
   438  }
   439  
   440  func TestOptionTimestampValidity(t *testing.T) {
   441  	require := require.New(t)
   442  
   443  	var (
   444  		activationTime = time.Unix(0, 0)
   445  		durangoTime    = activationTime
   446  	)
   447  	coreVM, _, proVM, db := initTestProposerVM(t, activationTime, durangoTime, 0)
   448  
   449  	coreTestBlk := snowmantest.BuildChild(snowmantest.Genesis)
   450  	coreOracleBlk := &TestOptionsBlock{
   451  		Block: *coreTestBlk,
   452  		opts: [2]*snowmantest.Block{
   453  			snowmantest.BuildChild(coreTestBlk),
   454  			snowmantest.BuildChild(coreTestBlk),
   455  		},
   456  	}
   457  
   458  	oracleBlkTime := proVM.Time().Truncate(time.Second)
   459  	statelessBlock, err := block.BuildUnsigned(
   460  		snowmantest.GenesisID,
   461  		oracleBlkTime,
   462  		0,
   463  		coreOracleBlk.Bytes(),
   464  	)
   465  	require.NoError(err)
   466  
   467  	coreVM.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
   468  		switch blkID {
   469  		case snowmantest.GenesisID:
   470  			return snowmantest.Genesis, nil
   471  		case coreOracleBlk.ID():
   472  			return coreOracleBlk, nil
   473  		case coreOracleBlk.opts[0].ID():
   474  			return coreOracleBlk.opts[0], nil
   475  		case coreOracleBlk.opts[1].ID():
   476  			return coreOracleBlk.opts[1], nil
   477  		default:
   478  			return nil, errUnknownBlock
   479  		}
   480  	}
   481  	coreVM.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) {
   482  		switch {
   483  		case bytes.Equal(b, snowmantest.GenesisBytes):
   484  			return snowmantest.Genesis, nil
   485  		case bytes.Equal(b, coreOracleBlk.Bytes()):
   486  			return coreOracleBlk, nil
   487  		case bytes.Equal(b, coreOracleBlk.opts[0].Bytes()):
   488  			return coreOracleBlk.opts[0], nil
   489  		case bytes.Equal(b, coreOracleBlk.opts[1].Bytes()):
   490  			return coreOracleBlk.opts[1], nil
   491  		default:
   492  			return nil, errUnknownBlock
   493  		}
   494  	}
   495  
   496  	statefulBlock, err := proVM.ParseBlock(context.Background(), statelessBlock.Bytes())
   497  	require.NoError(err)
   498  
   499  	require.NoError(statefulBlock.Verify(context.Background()))
   500  
   501  	statefulOracleBlock, ok := statefulBlock.(snowman.OracleBlock)
   502  	require.True(ok)
   503  
   504  	options, err := statefulOracleBlock.Options(context.Background())
   505  	require.NoError(err)
   506  
   507  	option := options[0]
   508  	require.NoError(option.Verify(context.Background()))
   509  
   510  	require.NoError(statefulBlock.Accept(context.Background()))
   511  
   512  	coreVM.GetBlockF = func(context.Context, ids.ID) (snowman.Block, error) {
   513  		require.FailNow("called GetBlock when unable to handle the error")
   514  		return nil, nil
   515  	}
   516  	coreVM.ParseBlockF = func(context.Context, []byte) (snowman.Block, error) {
   517  		require.FailNow("called ParseBlock when unable to handle the error")
   518  		return nil, nil
   519  	}
   520  
   521  	require.Equal(oracleBlkTime, option.Timestamp())
   522  
   523  	require.NoError(option.Accept(context.Background()))
   524  	require.NoError(proVM.Shutdown(context.Background()))
   525  
   526  	// Restart the node.
   527  	ctx := proVM.ctx
   528  	proVM = New(
   529  		coreVM,
   530  		Config{
   531  			Upgrades:            upgradetest.GetConfig(upgradetest.Latest),
   532  			MinBlkDelay:         DefaultMinBlockDelay,
   533  			NumHistoricalBlocks: DefaultNumHistoricalBlocks,
   534  			StakingLeafSigner:   pTestSigner,
   535  			StakingCertLeaf:     pTestCert,
   536  			Registerer:          prometheus.NewRegistry(),
   537  		},
   538  	)
   539  
   540  	coreVM.InitializeF = func(
   541  		context.Context,
   542  		*snow.Context,
   543  		database.Database,
   544  		[]byte,
   545  		[]byte,
   546  		[]byte,
   547  		chan<- common.Message,
   548  		[]*common.Fx,
   549  		common.AppSender,
   550  	) error {
   551  		return nil
   552  	}
   553  	coreVM.LastAcceptedF = func(context.Context) (ids.ID, error) {
   554  		return coreOracleBlk.opts[0].ID(), nil
   555  	}
   556  
   557  	coreVM.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) {
   558  		switch blkID {
   559  		case snowmantest.GenesisID:
   560  			return snowmantest.Genesis, nil
   561  		case coreOracleBlk.ID():
   562  			return coreOracleBlk, nil
   563  		case coreOracleBlk.opts[0].ID():
   564  			return coreOracleBlk.opts[0], nil
   565  		case coreOracleBlk.opts[1].ID():
   566  			return coreOracleBlk.opts[1], nil
   567  		default:
   568  			return nil, errUnknownBlock
   569  		}
   570  	}
   571  	coreVM.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) {
   572  		switch {
   573  		case bytes.Equal(b, snowmantest.GenesisBytes):
   574  			return snowmantest.Genesis, nil
   575  		case bytes.Equal(b, coreOracleBlk.Bytes()):
   576  			return coreOracleBlk, nil
   577  		case bytes.Equal(b, coreOracleBlk.opts[0].Bytes()):
   578  			return coreOracleBlk.opts[0], nil
   579  		case bytes.Equal(b, coreOracleBlk.opts[1].Bytes()):
   580  			return coreOracleBlk.opts[1], nil
   581  		default:
   582  			return nil, errUnknownBlock
   583  		}
   584  	}
   585  
   586  	require.NoError(proVM.Initialize(
   587  		context.Background(),
   588  		ctx,
   589  		db,
   590  		nil,
   591  		nil,
   592  		nil,
   593  		nil,
   594  		nil,
   595  		nil,
   596  	))
   597  	defer func() {
   598  		require.NoError(proVM.Shutdown(context.Background()))
   599  	}()
   600  
   601  	statefulOptionBlock, err := proVM.ParseBlock(context.Background(), option.Bytes())
   602  	require.NoError(err)
   603  
   604  	require.LessOrEqual(statefulOptionBlock.Height(), proVM.lastAcceptedHeight)
   605  
   606  	coreVM.GetBlockF = func(context.Context, ids.ID) (snowman.Block, error) {
   607  		require.FailNow("called GetBlock when unable to handle the error")
   608  		return nil, nil
   609  	}
   610  	coreVM.ParseBlockF = func(context.Context, []byte) (snowman.Block, error) {
   611  		require.FailNow("called ParseBlock when unable to handle the error")
   612  		return nil, nil
   613  	}
   614  
   615  	require.Equal(oracleBlkTime, statefulOptionBlock.Timestamp())
   616  }