github.com/consideritdone/landslidecore@v0.0.0-20230718131026-a8b21c5cf8a7/vm/vm.go (about)

     1  package vm
     2  
     3  import (
     4  	"context"
     5  	"encoding/base64"
     6  	"errors"
     7  	"fmt"
     8  	"time"
     9  
    10  	"github.com/ava-labs/avalanchego/api/health"
    11  	"github.com/ava-labs/avalanchego/api/metrics"
    12  	"github.com/ava-labs/avalanchego/database/manager"
    13  	"github.com/ava-labs/avalanchego/database/prefixdb"
    14  	"github.com/ava-labs/avalanchego/ids"
    15  	"github.com/ava-labs/avalanchego/snow"
    16  	"github.com/ava-labs/avalanchego/snow/choices"
    17  	"github.com/ava-labs/avalanchego/snow/consensus/snowman"
    18  	"github.com/ava-labs/avalanchego/snow/engine/common"
    19  	"github.com/ava-labs/avalanchego/snow/engine/snowman/block"
    20  	"github.com/ava-labs/avalanchego/snow/validators"
    21  	"github.com/ava-labs/avalanchego/utils"
    22  	"github.com/ava-labs/avalanchego/version"
    23  
    24  	abciTypes "github.com/consideritdone/landslidecore/abci/types"
    25  	"github.com/consideritdone/landslidecore/config"
    26  	"github.com/consideritdone/landslidecore/consensus"
    27  	"github.com/consideritdone/landslidecore/crypto/secp256k1"
    28  	"github.com/consideritdone/landslidecore/crypto/tmhash"
    29  	"github.com/consideritdone/landslidecore/libs/log"
    30  	mempl "github.com/consideritdone/landslidecore/mempool"
    31  	"github.com/consideritdone/landslidecore/node"
    32  	tmproto "github.com/consideritdone/landslidecore/proto/tendermint/types"
    33  	"github.com/consideritdone/landslidecore/proxy"
    34  	rpcserver "github.com/consideritdone/landslidecore/rpc/jsonrpc/server"
    35  	"github.com/consideritdone/landslidecore/state"
    36  	"github.com/consideritdone/landslidecore/state/indexer"
    37  	blockidxkv "github.com/consideritdone/landslidecore/state/indexer/block/kv"
    38  	"github.com/consideritdone/landslidecore/state/txindex"
    39  	txidxkv "github.com/consideritdone/landslidecore/state/txindex/kv"
    40  	"github.com/consideritdone/landslidecore/store"
    41  	"github.com/consideritdone/landslidecore/types"
    42  )
    43  
    44  const (
    45  	Name = "landslide"
    46  
    47  	decidedCacheSize    = 100
    48  	missingCacheSize    = 50
    49  	unverifiedCacheSize = 50
    50  
    51  	genesisChunkSize = 16 * 1024 * 1024 // 16
    52  )
    53  
    54  var (
    55  	Version = version.Semantic{
    56  		Major: 0,
    57  		Minor: 1,
    58  		Patch: 2,
    59  	}
    60  	_ common.NetworkAppHandler    = (*VM)(nil)
    61  	_ common.CrossChainAppHandler = (*VM)(nil)
    62  	_ common.AppHandler           = (*VM)(nil)
    63  	_ health.Checker              = (*VM)(nil)
    64  	_ validators.Connector        = (*VM)(nil)
    65  	_ common.VM                   = (*VM)(nil)
    66  	_ block.Getter                = (*VM)(nil)
    67  	_ block.Parser                = (*VM)(nil)
    68  	_ block.ChainVM               = (*VM)(nil)
    69  
    70  	dbPrefixBlockStore   = []byte("block-store")
    71  	dbPrefixStateStore   = []byte("state-store")
    72  	dbPrefixTxIndexer    = []byte("tx-indexer")
    73  	dbPrefixBlockIndexer = []byte("block-indexer")
    74  
    75  	proposerAddress = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
    76  	proposerPubKey  = secp256k1.PubKey{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
    77  
    78  	errInvalidBlock = errors.New("invalid block")
    79  	errNoPendingTxs = errors.New("there is no txs to include to block")
    80  )
    81  
    82  type (
    83  	AppCreator func(ids.ID) (abciTypes.Application, error)
    84  
    85  	VM struct {
    86  		appCreator AppCreator
    87  		app        proxy.AppConns
    88  
    89  		rpcConfig *config.RPCConfig
    90  
    91  		log      log.Logger
    92  		chainCtx *snow.Context
    93  		toEngine chan<- common.Message
    94  
    95  		blockStore *store.BlockStore
    96  		stateStore state.Store
    97  		state      state.State
    98  		genesis    *types.GenesisDoc
    99  		genChunks  []string
   100  
   101  		mempool  *mempl.CListMempool
   102  		eventBus *types.EventBus
   103  
   104  		txIndexer      txindex.TxIndexer
   105  		blockIndexer   indexer.BlockIndexer
   106  		indexerService *txindex.IndexerService
   107  		multiGatherer  metrics.MultiGatherer
   108  
   109  		bootstrapped   utils.Atomic[bool]
   110  		verifiedBlocks map[ids.ID]*Block
   111  		preferred      ids.ID
   112  	}
   113  )
   114  
   115  func LocalAppCreator(app abciTypes.Application) AppCreator {
   116  	return func(ids.ID) (abciTypes.Application, error) {
   117  		return app, nil
   118  	}
   119  }
   120  
   121  func New(appCreator AppCreator) *VM {
   122  	return &VM{
   123  		appCreator: appCreator,
   124  		app:        nil,
   125  	}
   126  }
   127  
   128  // Notify this engine of a request for data from [nodeID].
   129  //
   130  // The meaning of [request], and what should be sent in response to it, is
   131  // application (VM) specific.
   132  //
   133  // It is not guaranteed that:
   134  // * [request] is well-formed/valid.
   135  //
   136  // This node should typically send an AppResponse to [nodeID] in response to
   137  // a valid message using the same request ID before the deadline. However,
   138  // the VM may arbitrarily choose to not send a response to this request.
   139  func (vm *VM) AppRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, deadline time.Time, request []byte) error {
   140  	panic("implement me")
   141  }
   142  
   143  // Notify this engine that an AppRequest message it sent to [nodeID] with
   144  // request ID [requestID] failed.
   145  //
   146  // This may be because the request timed out or because the message couldn't
   147  // be sent to [nodeID].
   148  //
   149  // It is guaranteed that:
   150  // * This engine sent a request to [nodeID] with ID [requestID].
   151  // * AppRequestFailed([nodeID], [requestID]) has not already been called.
   152  // * AppResponse([nodeID], [requestID]) has not already been called.
   153  func (vm *VM) AppRequestFailed(ctx context.Context, nodeID ids.NodeID, requestID uint32) error {
   154  	panic("implement me")
   155  }
   156  
   157  // Notify this engine of a response to the AppRequest message it sent to
   158  // [nodeID] with request ID [requestID].
   159  //
   160  // The meaning of [response] is application (VM) specifc.
   161  //
   162  // It is guaranteed that:
   163  // * This engine sent a request to [nodeID] with ID [requestID].
   164  // * AppRequestFailed([nodeID], [requestID]) has not already been called.
   165  // * AppResponse([nodeID], [requestID]) has not already been called.
   166  //
   167  // It is not guaranteed that:
   168  // * [response] contains the expected response
   169  // * [response] is well-formed/valid.
   170  //
   171  // If [response] is invalid or not the expected response, the VM chooses how
   172  // to react. For example, the VM may send another AppRequest, or it may give
   173  // up trying to get the requested information.
   174  func (vm *VM) AppResponse(ctx context.Context, nodeID ids.NodeID, requestID uint32, response []byte) error {
   175  	panic("implement me")
   176  }
   177  
   178  // Notify this engine of a gossip message from [nodeID].
   179  //
   180  // The meaning of [msg] is application (VM) specific, and the VM defines how
   181  // to react to this message.
   182  //
   183  // This message is not expected in response to any event, and it does not
   184  // need to be responded to.
   185  //
   186  // A node may gossip the same message multiple times. That is,
   187  // AppGossip([nodeID], [msg]) may be called multiple times.
   188  func (vm *VM) AppGossip(ctx context.Context, nodeID ids.NodeID, msg []byte) error {
   189  	panic("implement me")
   190  }
   191  
   192  // CrossChainAppRequest Notify this engine of a request for data from
   193  // [chainID].
   194  //
   195  // The meaning of [request], and what should be sent in response to it, is
   196  // application (VM) specific.
   197  //
   198  // Guarantees surrounding the request are specific to the implementation of
   199  // the requesting VM. For example, the request may or may not be guaranteed
   200  // to be well-formed/valid depending on the implementation of the requesting
   201  // VM.
   202  //
   203  // This node should typically send a CrossChainAppResponse to [chainID] in
   204  // response to a valid message using the same request ID before the
   205  // deadline. However, the VM may arbitrarily choose to not send a response
   206  // to this request.
   207  func (vm *VM) CrossChainAppRequest(ctx context.Context, chainID ids.ID, requestID uint32, deadline time.Time, request []byte) error {
   208  	panic("implement me")
   209  }
   210  
   211  // CrossChainAppRequestFailed notifies this engine that a
   212  // CrossChainAppRequest message it sent to [chainID] with request ID
   213  // [requestID] failed.
   214  //
   215  // This may be because the request timed out or because the message couldn't
   216  // be sent to [chainID].
   217  //
   218  // It is guaranteed that:
   219  // * This engine sent a request to [chainID] with ID [requestID].
   220  // * CrossChainAppRequestFailed([chainID], [requestID]) has not already been
   221  // called.
   222  // * CrossChainAppResponse([chainID], [requestID]) has not already been
   223  // called.
   224  func (vm *VM) CrossChainAppRequestFailed(ctx context.Context, chainID ids.ID, requestID uint32) error {
   225  	panic("implement me")
   226  }
   227  
   228  // CrossChainAppResponse notifies this engine of a response to the
   229  // CrossChainAppRequest message it sent to [chainID] with request ID
   230  // [requestID].
   231  //
   232  // The meaning of [response] is application (VM) specific.
   233  //
   234  // It is guaranteed that:
   235  // * This engine sent a request to [chainID] with ID [requestID].
   236  // * CrossChainAppRequestFailed([chainID], [requestID]) has not already been
   237  // called.
   238  // * CrossChainAppResponse([chainID], [requestID]) has not already been
   239  // called.
   240  //
   241  // Guarantees surrounding the response are specific to the implementation of
   242  // the responding VM. For example, the response may or may not be guaranteed
   243  // to be well-formed/valid depending on the implementation of the requesting
   244  // VM.
   245  //
   246  // If [response] is invalid or not the expected response, the VM chooses how
   247  // to react. For example, the VM may send another CrossChainAppRequest, or
   248  // it may give up trying to get the requested information.
   249  func (vm *VM) CrossChainAppResponse(ctx context.Context, chainID ids.ID, requestID uint32, response []byte) error {
   250  	panic("implement me")
   251  }
   252  
   253  // HealthCheck returns health check results and, if not healthy, a non-nil
   254  // error
   255  //
   256  // It is expected that the results are json marshallable.
   257  func (vm *VM) HealthCheck(context.Context) (interface{}, error) {
   258  	return nil, nil
   259  }
   260  
   261  // Connector represents a handler that is called when a connection is marked as connected
   262  func (vm *VM) Connected(ctx context.Context, nodeID ids.NodeID, nodeVersion *version.Application) error {
   263  	vm.log.Info("connected", "nodeID", nodeID.String(), "nodeVersion", nodeVersion.String())
   264  	return nil
   265  }
   266  
   267  // Connector represents a handler that is called when a connection is marked as disconnected
   268  func (vm *VM) Disconnected(ctx context.Context, nodeID ids.NodeID) error {
   269  	vm.log.Info("disconnected", "nodeID", nodeID.String())
   270  	return nil
   271  }
   272  
   273  // Initialize this VM.
   274  // [chainCtx]: Metadata about this VM.
   275  //
   276  //	[chainCtx.networkID]: The ID of the network this VM's chain is
   277  //	                      running on.
   278  //	[chainCtx.chainID]: The unique ID of the chain this VM is running on.
   279  //	[chainCtx.Log]: Used to log messages
   280  //	[chainCtx.NodeID]: The unique staker ID of this node.
   281  //	[chainCtx.Lock]: A Read/Write lock shared by this VM and the
   282  //	                 consensus engine that manages this VM. The write
   283  //	                 lock is held whenever code in the consensus engine
   284  //	                 calls the VM.
   285  //
   286  // [dbManager]: The manager of the database this VM will persist data to.
   287  // [genesisBytes]: The byte-encoding of the genesis information of this
   288  //
   289  //	VM. The VM uses it to initialize its state. For
   290  //	example, if this VM were an account-based payments
   291  //	system, `genesisBytes` would probably contain a genesis
   292  //	transaction that gives coins to some accounts, and this
   293  //	transaction would be in the genesis block.
   294  //
   295  // [toEngine]: The channel used to send messages to the consensus engine.
   296  // [fxs]: Feature extensions that attach to this VM.
   297  func (vm *VM) Initialize(
   298  	ctx context.Context,
   299  	chainCtx *snow.Context,
   300  	dbManager manager.Manager,
   301  	genesisBytes []byte,
   302  	upgradeBytes []byte,
   303  	configBytes []byte,
   304  	toEngine chan<- common.Message,
   305  	fxs []*common.Fx,
   306  	appSender common.AppSender,
   307  ) error {
   308  	vm.chainCtx = chainCtx
   309  	vm.toEngine = toEngine
   310  	vm.log = log.NewTMLogger(vm.chainCtx.Log).With("module", "vm")
   311  	vm.verifiedBlocks = make(map[ids.ID]*Block)
   312  	vm.rpcConfig = config.DefaultRPCConfig()
   313  
   314  	db := dbManager.Current().Database
   315  
   316  	dbBlockStore := NewDB(prefixdb.NewNested(dbPrefixBlockStore, db))
   317  	vm.blockStore = store.NewBlockStore(dbBlockStore)
   318  
   319  	dbStateStore := NewDB(prefixdb.NewNested(dbPrefixStateStore, db))
   320  	vm.stateStore = state.NewStore(dbStateStore)
   321  
   322  	app, err := vm.appCreator(chainCtx.ChainID)
   323  	if err != nil {
   324  		return err
   325  	}
   326  
   327  	vm.state, vm.genesis, err = node.LoadStateFromDBOrGenesisDocProvider(
   328  		dbStateStore,
   329  		NewLocalGenesisDocProvider(genesisBytes),
   330  	)
   331  	if err != nil {
   332  		return nil
   333  	}
   334  	for i := 0; i < len(genesisBytes); i += genesisChunkSize {
   335  		end := i + genesisChunkSize
   336  		if end > len(genesisBytes) {
   337  			end = len(genesisBytes)
   338  		}
   339  		vm.genChunks = append(vm.genChunks, base64.StdEncoding.EncodeToString(genesisBytes[i:end]))
   340  	}
   341  
   342  	vm.app, err = node.CreateAndStartProxyAppConns(proxy.NewLocalClientCreator(app), vm.log)
   343  	if err != nil {
   344  		return err
   345  	}
   346  
   347  	vm.eventBus, err = node.CreateAndStartEventBus(vm.log)
   348  	if err != nil {
   349  		return err
   350  	}
   351  
   352  	dbTxIndexer := NewDB(prefixdb.NewNested(dbPrefixTxIndexer, db))
   353  	vm.txIndexer = txidxkv.NewTxIndex(dbTxIndexer)
   354  
   355  	dbBlockIndexer := NewDB(prefixdb.NewNested(dbPrefixBlockIndexer, db))
   356  	vm.blockIndexer = blockidxkv.New(dbBlockIndexer)
   357  
   358  	vm.indexerService = txindex.NewIndexerService(vm.txIndexer, vm.blockIndexer, vm.eventBus)
   359  	vm.indexerService.SetLogger(vm.log.With("module", "indexer"))
   360  	if err := vm.indexerService.Start(); err != nil {
   361  		return err
   362  	}
   363  
   364  	handshaker := consensus.NewHandshaker(
   365  		vm.stateStore,
   366  		vm.state,
   367  		vm.blockStore,
   368  		vm.genesis,
   369  	)
   370  	handshaker.SetLogger(vm.log.With("module", "consensus"))
   371  	handshaker.SetEventBus(vm.eventBus)
   372  	if err := handshaker.Handshake(vm.app); err != nil {
   373  		return fmt.Errorf("error during handshake: %v", err)
   374  	}
   375  
   376  	vm.state, err = vm.stateStore.Load()
   377  	if err != nil {
   378  		return nil
   379  	}
   380  
   381  	vm.mempool = mempl.NewCListMempool(
   382  		config.DefaultMempoolConfig(),
   383  		vm.app.Mempool(),
   384  		vm.state.LastBlockHeight,
   385  		vm,
   386  		mempl.WithMetrics(mempl.NopMetrics()),
   387  		mempl.WithPreCheck(state.TxPreCheck(vm.state)),
   388  		mempl.WithPostCheck(state.TxPostCheck(vm.state)),
   389  	)
   390  	vm.mempool.SetLogger(vm.log.With("module", "mempool"))
   391  	vm.mempool.EnableTxsAvailable()
   392  
   393  	vm.multiGatherer = metrics.NewMultiGatherer()
   394  	if err := vm.chainCtx.Metrics.Register(vm.multiGatherer); err != nil {
   395  		return err
   396  	}
   397  
   398  	if vm.state.LastBlockHeight == 0 {
   399  		block, _ := vm.state.MakeBlock(1, types.Txs{}, makeCommit(1, time.Now()), nil, proposerAddress)
   400  		block.LastBlockID = types.BlockID{
   401  			Hash: tmhash.Sum([]byte{}),
   402  			PartSetHeader: types.PartSetHeader{
   403  				Total: 0,
   404  				Hash:  tmhash.Sum([]byte{}),
   405  			},
   406  		}
   407  		if err := NewBlock(vm, block, choices.Processing).Accept(ctx); err != nil {
   408  			return err
   409  		}
   410  	}
   411  
   412  	vm.log.Info("vm initialization completed")
   413  	return nil
   414  }
   415  
   416  func (vm *VM) NotifyBlockReady() {
   417  	select {
   418  	case vm.toEngine <- common.PendingTxs:
   419  		vm.log.Debug("notify consensys engine")
   420  	default:
   421  		vm.log.Error("failed to push PendingTxs notification to the consensus engine.")
   422  	}
   423  }
   424  
   425  // SetState communicates to VM its next state it starts
   426  func (vm *VM) SetState(ctx context.Context, state snow.State) error {
   427  	vm.log.Debug("set state", "state", state.String())
   428  	switch state {
   429  	case snow.Bootstrapping:
   430  		vm.bootstrapped.Set(false)
   431  	case snow.NormalOp:
   432  		vm.bootstrapped.Set(true)
   433  	default:
   434  		return snow.ErrUnknownState
   435  	}
   436  	return nil
   437  }
   438  
   439  // Shutdown is called when the node is shutting down.
   440  func (vm *VM) Shutdown(context.Context) error {
   441  	vm.log.Debug("shutdown start")
   442  
   443  	if err := vm.indexerService.Stop(); err != nil {
   444  		return fmt.Errorf("error closing indexerService: %w ", err)
   445  	}
   446  
   447  	if err := vm.eventBus.Stop(); err != nil {
   448  		return fmt.Errorf("error closing eventBus: %w ", err)
   449  	}
   450  
   451  	if err := vm.app.Stop(); err != nil {
   452  		return fmt.Errorf("error closing app: %w ", err)
   453  	}
   454  
   455  	if err := vm.stateStore.Close(); err != nil {
   456  		return fmt.Errorf("error closing stateStore: %w ", err)
   457  	}
   458  
   459  	if err := vm.blockStore.Close(); err != nil {
   460  		return fmt.Errorf("Error closing blockStore: %w ", err)
   461  	}
   462  
   463  	vm.log.Debug("shutdown completed")
   464  	return nil
   465  }
   466  
   467  // Version returns the version of the VM.
   468  func (vm *VM) Version(context.Context) (string, error) {
   469  	return Version.String(), nil
   470  }
   471  
   472  // Creates the HTTP handlers for custom VM network calls.
   473  //
   474  // This exposes handlers that the outside world can use to communicate with
   475  // a static reference to the VM. Each handler has the path:
   476  // [Address of node]/ext/VM/[VM ID]/[extension]
   477  //
   478  // Returns a mapping from [extension]s to HTTP handlers.
   479  //
   480  // Each extension can specify how locking is managed for convenience.
   481  //
   482  // For example, it might make sense to have an extension for creating
   483  // genesis bytes this VM can interpret.
   484  //
   485  // Note: If this method is called, no other method will be called on this VM.
   486  // Each registered VM will have a single instance created to handle static
   487  // APIs. This instance will be handled separately from instances created to
   488  // service an instance of a chain.
   489  func (vm *VM) CreateStaticHandlers(context.Context) (map[string]*common.HTTPHandler, error) {
   490  	// ToDo: need to add implementation
   491  	return nil, nil
   492  }
   493  
   494  // Creates the HTTP handlers for custom chain network calls.
   495  //
   496  // This exposes handlers that the outside world can use to communicate with
   497  // the chain. Each handler has the path:
   498  // [Address of node]/ext/bc/[chain ID]/[extension]
   499  //
   500  // Returns a mapping from [extension]s to HTTP handlers.
   501  //
   502  // Each extension can specify how locking is managed for convenience.
   503  //
   504  // For example, if this VM implements an account-based payments system,
   505  // it have an extension called `accounts`, where clients could get
   506  // information about their accounts.
   507  func (vm *VM) CreateHandlers(context.Context) (map[string]*common.HTTPHandler, error) {
   508  	return map[string]*common.HTTPHandler{
   509  		"/rpc": {
   510  			LockOptions: common.WriteLock,
   511  			Handler: rpcserver.MakeJSONRPCHandler(
   512  				NewServiceAsRPCRoutes(vm),
   513  				vm.log.With("module", "rpc"),
   514  			),
   515  		},
   516  	}, nil
   517  }
   518  
   519  // Attempt to load a block.
   520  //
   521  // If the block does not exist, database.ErrNotFound should be returned.
   522  //
   523  // It is expected that blocks that have been successfully verified should be
   524  // returned correctly. It is also expected that blocks that have been
   525  // accepted by the consensus engine should be able to be fetched. It is not
   526  // required for blocks that have been rejected by the consensus engine to be
   527  // able to be fetched.
   528  func (vm *VM) GetBlock(ctx context.Context, blkID ids.ID) (snowman.Block, error) {
   529  	vm.log.Debug("get block", "blkID", blkID.String())
   530  	if b, ok := vm.verifiedBlocks[blkID]; ok {
   531  		vm.log.Debug("get block", "status", b.Status())
   532  		return b, nil
   533  	}
   534  	b := vm.blockStore.LoadBlockByHash(blkID[:])
   535  	if b == nil {
   536  		return nil, errInvalidBlock
   537  	}
   538  	vm.log.Debug("get block", "status", choices.Accepted)
   539  	return NewBlock(vm, b, choices.Accepted), nil
   540  }
   541  
   542  // Attempt to create a block from a stream of bytes.
   543  //
   544  // The block should be represented by the full byte array, without extra
   545  // bytes.
   546  //
   547  // It is expected for all historical blocks to be parseable.
   548  func (vm *VM) ParseBlock(ctx context.Context, blockBytes []byte) (snowman.Block, error) {
   549  	vm.log.Debug("parse block")
   550  
   551  	protoBlock := new(tmproto.Block)
   552  	if err := protoBlock.Unmarshal(blockBytes[1:]); err != nil {
   553  		vm.log.Error("can't parse block", "err", err)
   554  		return nil, err
   555  	}
   556  
   557  	block, err := types.BlockFromProto(protoBlock)
   558  	if err != nil {
   559  		vm.log.Error("can't create block from proto", "err", err)
   560  		return nil, err
   561  	}
   562  
   563  	blk := NewBlock(vm, block, choices.Status(uint32(blockBytes[0])))
   564  	vm.log.Debug("parsed block", "id", blk.ID(), "status", blk.Status().String())
   565  	if _, ok := vm.verifiedBlocks[blk.ID()]; !ok {
   566  		vm.verifiedBlocks[blk.ID()] = blk
   567  	}
   568  
   569  	return blk, nil
   570  }
   571  
   572  // Attempt to create a new block from data contained in the VM.
   573  //
   574  // If the VM doesn't want to issue a new block, an error should be
   575  // returned.
   576  func (vm *VM) BuildBlock(ctx context.Context) (snowman.Block, error) {
   577  	vm.log.Debug("build block")
   578  
   579  	txs := vm.mempool.ReapMaxBytesMaxGas(-1, -1)
   580  	if len(txs) == 0 {
   581  		return nil, errNoPendingTxs
   582  	}
   583  
   584  	state := vm.state.Copy()
   585  
   586  	var preferredBlock *types.Block
   587  	if vm.preferred != ids.Empty {
   588  		if b, ok := vm.verifiedBlocks[vm.preferred]; ok {
   589  			vm.log.Debug("load preferred block from cache", "id", vm.preferred.String())
   590  			preferredBlock = b.Block
   591  		} else {
   592  			vm.log.Debug("load preferred block from blockStore", "id", vm.preferred.String())
   593  			preferredBlock = vm.blockStore.LoadBlockByHash(vm.preferred[:])
   594  			if preferredBlock == nil {
   595  				return nil, errInvalidBlock
   596  			}
   597  		}
   598  	} else {
   599  		preferredBlock = vm.blockStore.LoadBlockByHash(state.LastBlockID.Hash)
   600  	}
   601  	preferredHeight := preferredBlock.Header.Height
   602  
   603  	commit := makeCommit(preferredHeight+1, time.Now())
   604  	block, _ := state.MakeBlock(preferredHeight+1, txs, commit, nil, proposerAddress)
   605  	block.LastBlockID = types.BlockID{
   606  		Hash:          preferredBlock.Hash(),
   607  		PartSetHeader: preferredBlock.MakePartSet(types.BlockPartSizeBytes).Header(),
   608  	}
   609  
   610  	blk := NewBlock(vm, block, choices.Processing)
   611  	vm.verifiedBlocks[blk.ID()] = blk
   612  
   613  	vm.log.Debug("build block", "id", blk.ID(), "height", blk.Height(), "txs", len(block.Txs))
   614  	return blk, nil
   615  }
   616  
   617  // Notify the VM of the currently preferred block.
   618  //
   619  // This should always be a block that has no children known to consensus.
   620  func (vm *VM) SetPreference(ctx context.Context, blkID ids.ID) error {
   621  	vm.log.Debug("set preference", "blkID", blkID.String())
   622  	vm.preferred = blkID
   623  	return nil
   624  }
   625  
   626  // LastAccepted returns the ID of the last accepted block.
   627  //
   628  // If no blocks have been accepted by consensus yet, it is assumed there is
   629  // a definitionally accepted block, the Genesis block, that will be
   630  // returned.
   631  func (vm *VM) LastAccepted(context.Context) (ids.ID, error) {
   632  	if vm.preferred == ids.Empty {
   633  		return ids.ID(vm.state.LastBlockID.Hash), nil
   634  	}
   635  	return vm.preferred, nil
   636  }
   637  
   638  func (vm *VM) applyBlock(block *Block) error {
   639  	vm.mempool.Lock()
   640  	defer vm.mempool.Unlock()
   641  
   642  	state := vm.state.Copy()
   643  
   644  	err := validateBlock(state, block.Block)
   645  	if err != nil {
   646  		return err
   647  	}
   648  
   649  	abciResponses, err := execBlockOnProxyApp(vm.log, vm.app.Consensus(), block.Block, vm.stateStore, state.InitialHeight)
   650  	if err != nil {
   651  		return err
   652  	}
   653  
   654  	// Save the results before we commit.
   655  	if err := vm.stateStore.SaveABCIResponses(block.Block.Height, abciResponses); err != nil {
   656  		return err
   657  	}
   658  
   659  	blockID := types.BlockID{
   660  		Hash:          block.Block.Hash(),
   661  		PartSetHeader: block.Block.MakePartSet(types.BlockPartSizeBytes).Header(),
   662  	}
   663  
   664  	// while mempool is Locked, flush to ensure all async requests have completed
   665  	// in the ABCI app before Commit.
   666  	if err := vm.mempool.FlushAppConn(); err != nil {
   667  		vm.log.Error("client error during mempool.FlushAppConn", "err", err)
   668  		return err
   669  	}
   670  
   671  	// Commit block, get hash back
   672  	res, err := vm.app.Consensus().CommitSync()
   673  	if err != nil {
   674  		vm.log.Error("client error during proxyAppConn.CommitSync", "err", err)
   675  		return err
   676  	}
   677  
   678  	// Update the state with the block and responses.
   679  	state.LastBlockHeight = block.Block.Height
   680  	state.LastBlockID = blockID
   681  	state.LastBlockTime = block.Time
   682  	state.LastResultsHash = types.NewResults(abciResponses.DeliverTxs).Hash()
   683  	state.AppHash = res.Data
   684  
   685  	// ResponseCommit has no error code - just data
   686  	vm.log.Info(
   687  		"committed state",
   688  		"height", block.Height,
   689  		"num_txs", len(block.Block.Txs),
   690  		"app_hash", fmt.Sprintf("%X", res.Data),
   691  	)
   692  
   693  	deliverTxResponses := make([]*abciTypes.ResponseDeliverTx, len(block.Block.Txs))
   694  	for i := range block.Block.Txs {
   695  		deliverTxResponses[i] = &abciTypes.ResponseDeliverTx{Code: abciTypes.CodeTypeOK}
   696  	}
   697  
   698  	// Update mempool.
   699  	if err := vm.mempool.Update(
   700  		block.Block.Height,
   701  		block.Block.Txs,
   702  		deliverTxResponses,
   703  		TxPreCheck(state),
   704  		TxPostCheck(state),
   705  	); err != nil {
   706  		return err
   707  	}
   708  
   709  	if err := vm.stateStore.Save(state); err != nil {
   710  		return err
   711  	}
   712  	vm.state = state
   713  
   714  	vm.blockStore.SaveBlock(block.Block, block.Block.MakePartSet(types.BlockPartSizeBytes), block.Block.LastCommit)
   715  	fireEvents(vm.log, vm.eventBus, block.Block, abciResponses)
   716  	return nil
   717  }