github.com/MetalBlockchain/metalgo@v1.11.9/vms/rpcchainvm/vm_server.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package rpcchainvm
     5  
     6  import (
     7  	"context"
     8  	"encoding/json"
     9  	"errors"
    10  	"fmt"
    11  	"os"
    12  	"time"
    13  
    14  	"github.com/prometheus/client_golang/prometheus"
    15  	"github.com/prometheus/client_golang/prometheus/collectors"
    16  	"google.golang.org/protobuf/types/known/emptypb"
    17  
    18  	"github.com/MetalBlockchain/metalgo/api/keystore/gkeystore"
    19  	"github.com/MetalBlockchain/metalgo/api/metrics"
    20  	"github.com/MetalBlockchain/metalgo/chains/atomic/gsharedmemory"
    21  	"github.com/MetalBlockchain/metalgo/database"
    22  	"github.com/MetalBlockchain/metalgo/database/corruptabledb"
    23  	"github.com/MetalBlockchain/metalgo/database/rpcdb"
    24  	"github.com/MetalBlockchain/metalgo/ids"
    25  	"github.com/MetalBlockchain/metalgo/ids/galiasreader"
    26  	"github.com/MetalBlockchain/metalgo/snow"
    27  	"github.com/MetalBlockchain/metalgo/snow/consensus/snowman"
    28  	"github.com/MetalBlockchain/metalgo/snow/engine/common"
    29  	"github.com/MetalBlockchain/metalgo/snow/engine/common/appsender"
    30  	"github.com/MetalBlockchain/metalgo/snow/engine/snowman/block"
    31  	"github.com/MetalBlockchain/metalgo/snow/validators/gvalidators"
    32  	"github.com/MetalBlockchain/metalgo/utils"
    33  	"github.com/MetalBlockchain/metalgo/utils/crypto/bls"
    34  	"github.com/MetalBlockchain/metalgo/utils/logging"
    35  	"github.com/MetalBlockchain/metalgo/utils/wrappers"
    36  	"github.com/MetalBlockchain/metalgo/version"
    37  	"github.com/MetalBlockchain/metalgo/vms/platformvm/warp/gwarp"
    38  	"github.com/MetalBlockchain/metalgo/vms/rpcchainvm/ghttp"
    39  	"github.com/MetalBlockchain/metalgo/vms/rpcchainvm/grpcutils"
    40  	"github.com/MetalBlockchain/metalgo/vms/rpcchainvm/messenger"
    41  
    42  	aliasreaderpb "github.com/MetalBlockchain/metalgo/proto/pb/aliasreader"
    43  	appsenderpb "github.com/MetalBlockchain/metalgo/proto/pb/appsender"
    44  	httppb "github.com/MetalBlockchain/metalgo/proto/pb/http"
    45  	keystorepb "github.com/MetalBlockchain/metalgo/proto/pb/keystore"
    46  	messengerpb "github.com/MetalBlockchain/metalgo/proto/pb/messenger"
    47  	rpcdbpb "github.com/MetalBlockchain/metalgo/proto/pb/rpcdb"
    48  	sharedmemorypb "github.com/MetalBlockchain/metalgo/proto/pb/sharedmemory"
    49  	validatorstatepb "github.com/MetalBlockchain/metalgo/proto/pb/validatorstate"
    50  	vmpb "github.com/MetalBlockchain/metalgo/proto/pb/vm"
    51  	warppb "github.com/MetalBlockchain/metalgo/proto/pb/warp"
    52  	grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
    53  )
    54  
    55  var (
    56  	_ vmpb.VMServer = (*VMServer)(nil)
    57  
    58  	originalStderr = os.Stderr
    59  
    60  	errExpectedBlockWithVerifyContext = errors.New("expected block.WithVerifyContext")
    61  )
    62  
    63  // VMServer is a VM that is managed over RPC.
    64  type VMServer struct {
    65  	vmpb.UnsafeVMServer
    66  
    67  	vm block.ChainVM
    68  	// If nil, the underlying VM doesn't implement the interface.
    69  	bVM block.BuildBlockWithContextChainVM
    70  	// If nil, the underlying VM doesn't implement the interface.
    71  	ssVM block.StateSyncableVM
    72  
    73  	allowShutdown *utils.Atomic[bool]
    74  
    75  	metrics prometheus.Gatherer
    76  	db      database.Database
    77  	log     logging.Logger
    78  
    79  	serverCloser grpcutils.ServerCloser
    80  	connCloser   wrappers.Closer
    81  
    82  	ctx    *snow.Context
    83  	closed chan struct{}
    84  }
    85  
    86  // NewServer returns a vm instance connected to a remote vm instance
    87  func NewServer(vm block.ChainVM, allowShutdown *utils.Atomic[bool]) *VMServer {
    88  	bVM, _ := vm.(block.BuildBlockWithContextChainVM)
    89  	ssVM, _ := vm.(block.StateSyncableVM)
    90  	return &VMServer{
    91  		vm:            vm,
    92  		bVM:           bVM,
    93  		ssVM:          ssVM,
    94  		allowShutdown: allowShutdown,
    95  	}
    96  }
    97  
    98  func (vm *VMServer) Initialize(ctx context.Context, req *vmpb.InitializeRequest) (*vmpb.InitializeResponse, error) {
    99  	subnetID, err := ids.ToID(req.SubnetId)
   100  	if err != nil {
   101  		return nil, err
   102  	}
   103  	chainID, err := ids.ToID(req.ChainId)
   104  	if err != nil {
   105  		return nil, err
   106  	}
   107  	nodeID, err := ids.ToNodeID(req.NodeId)
   108  	if err != nil {
   109  		return nil, err
   110  	}
   111  	publicKey, err := bls.PublicKeyFromCompressedBytes(req.PublicKey)
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  	xChainID, err := ids.ToID(req.XChainId)
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  	cChainID, err := ids.ToID(req.CChainId)
   120  	if err != nil {
   121  		return nil, err
   122  	}
   123  	avaxAssetID, err := ids.ToID(req.AvaxAssetId)
   124  	if err != nil {
   125  		return nil, err
   126  	}
   127  
   128  	pluginMetrics := metrics.NewPrefixGatherer()
   129  	vm.metrics = pluginMetrics
   130  
   131  	processMetrics, err := metrics.MakeAndRegister(
   132  		pluginMetrics,
   133  		"process",
   134  	)
   135  	if err != nil {
   136  		return nil, err
   137  	}
   138  
   139  	// Current state of process metrics
   140  	processCollector := collectors.NewProcessCollector(collectors.ProcessCollectorOpts{})
   141  	if err := processMetrics.Register(processCollector); err != nil {
   142  		return nil, err
   143  	}
   144  
   145  	// Go process metrics using debug.GCStats
   146  	goCollector := collectors.NewGoCollector()
   147  	if err := processMetrics.Register(goCollector); err != nil {
   148  		return nil, err
   149  	}
   150  
   151  	grpcMetrics, err := metrics.MakeAndRegister(
   152  		pluginMetrics,
   153  		"grpc",
   154  	)
   155  	if err != nil {
   156  		return nil, err
   157  	}
   158  
   159  	// gRPC client metrics
   160  	grpcClientMetrics := grpc_prometheus.NewClientMetrics()
   161  	if err := grpcMetrics.Register(grpcClientMetrics); err != nil {
   162  		return nil, err
   163  	}
   164  
   165  	vmMetrics := metrics.NewPrefixGatherer()
   166  	if err := pluginMetrics.Register("vm", vmMetrics); err != nil {
   167  		return nil, err
   168  	}
   169  
   170  	// Dial the database
   171  	dbClientConn, err := grpcutils.Dial(
   172  		req.DbServerAddr,
   173  		grpcutils.WithChainUnaryInterceptor(grpcClientMetrics.UnaryClientInterceptor()),
   174  		grpcutils.WithChainStreamInterceptor(grpcClientMetrics.StreamClientInterceptor()),
   175  	)
   176  	if err != nil {
   177  		return nil, err
   178  	}
   179  	vm.connCloser.Add(dbClientConn)
   180  	vm.db = corruptabledb.New(
   181  		rpcdb.NewClient(rpcdbpb.NewDatabaseClient(dbClientConn)),
   182  	)
   183  
   184  	// TODO: Allow the logger to be configured by the client
   185  	vm.log = logging.NewLogger(
   186  		fmt.Sprintf("<%s Chain>", chainID),
   187  		logging.NewWrappedCore(
   188  			logging.Info,
   189  			originalStderr,
   190  			logging.Colors.ConsoleEncoder(),
   191  		),
   192  	)
   193  
   194  	clientConn, err := grpcutils.Dial(
   195  		req.ServerAddr,
   196  		grpcutils.WithChainUnaryInterceptor(grpcClientMetrics.UnaryClientInterceptor()),
   197  		grpcutils.WithChainStreamInterceptor(grpcClientMetrics.StreamClientInterceptor()),
   198  	)
   199  	if err != nil {
   200  		// Ignore closing errors to return the original error
   201  		_ = vm.connCloser.Close()
   202  		return nil, err
   203  	}
   204  
   205  	vm.connCloser.Add(clientConn)
   206  
   207  	msgClient := messenger.NewClient(messengerpb.NewMessengerClient(clientConn))
   208  	keystoreClient := gkeystore.NewClient(keystorepb.NewKeystoreClient(clientConn))
   209  	sharedMemoryClient := gsharedmemory.NewClient(sharedmemorypb.NewSharedMemoryClient(clientConn))
   210  	bcLookupClient := galiasreader.NewClient(aliasreaderpb.NewAliasReaderClient(clientConn))
   211  	appSenderClient := appsender.NewClient(appsenderpb.NewAppSenderClient(clientConn))
   212  	validatorStateClient := gvalidators.NewClient(validatorstatepb.NewValidatorStateClient(clientConn))
   213  	warpSignerClient := gwarp.NewClient(warppb.NewSignerClient(clientConn))
   214  
   215  	toEngine := make(chan common.Message, 1)
   216  	vm.closed = make(chan struct{})
   217  	go func() {
   218  		for {
   219  			select {
   220  			case msg, ok := <-toEngine:
   221  				if !ok {
   222  					return
   223  				}
   224  				// Nothing to do with the error within the goroutine
   225  				_ = msgClient.Notify(msg)
   226  			case <-vm.closed:
   227  				return
   228  			}
   229  		}
   230  	}()
   231  
   232  	vm.ctx = &snow.Context{
   233  		NetworkID: req.NetworkId,
   234  		SubnetID:  subnetID,
   235  		ChainID:   chainID,
   236  		NodeID:    nodeID,
   237  		PublicKey: publicKey,
   238  
   239  		XChainID:    xChainID,
   240  		CChainID:    cChainID,
   241  		AVAXAssetID: avaxAssetID,
   242  
   243  		Log:          vm.log,
   244  		Keystore:     keystoreClient,
   245  		SharedMemory: sharedMemoryClient,
   246  		BCLookup:     bcLookupClient,
   247  		Metrics:      vmMetrics,
   248  
   249  		// Signs warp messages
   250  		WarpSigner: warpSignerClient,
   251  
   252  		ValidatorState: validatorStateClient,
   253  		// TODO: support remaining snowman++ fields
   254  
   255  		ChainDataDir: req.ChainDataDir,
   256  	}
   257  
   258  	if err := vm.vm.Initialize(ctx, vm.ctx, vm.db, req.GenesisBytes, req.UpgradeBytes, req.ConfigBytes, toEngine, nil, appSenderClient); err != nil {
   259  		// Ignore errors closing resources to return the original error
   260  		_ = vm.connCloser.Close()
   261  		close(vm.closed)
   262  		return nil, err
   263  	}
   264  
   265  	lastAccepted, err := vm.vm.LastAccepted(ctx)
   266  	if err != nil {
   267  		// Ignore errors closing resources to return the original error
   268  		_ = vm.vm.Shutdown(ctx)
   269  		_ = vm.connCloser.Close()
   270  		close(vm.closed)
   271  		return nil, err
   272  	}
   273  
   274  	blk, err := vm.vm.GetBlock(ctx, lastAccepted)
   275  	if err != nil {
   276  		// Ignore errors closing resources to return the original error
   277  		_ = vm.vm.Shutdown(ctx)
   278  		_ = vm.connCloser.Close()
   279  		close(vm.closed)
   280  		return nil, err
   281  	}
   282  	parentID := blk.Parent()
   283  	return &vmpb.InitializeResponse{
   284  		LastAcceptedId:       lastAccepted[:],
   285  		LastAcceptedParentId: parentID[:],
   286  		Height:               blk.Height(),
   287  		Bytes:                blk.Bytes(),
   288  		Timestamp:            grpcutils.TimestampFromTime(blk.Timestamp()),
   289  	}, nil
   290  }
   291  
   292  func (vm *VMServer) SetState(ctx context.Context, stateReq *vmpb.SetStateRequest) (*vmpb.SetStateResponse, error) {
   293  	err := vm.vm.SetState(ctx, snow.State(stateReq.State))
   294  	if err != nil {
   295  		return nil, err
   296  	}
   297  
   298  	lastAccepted, err := vm.vm.LastAccepted(ctx)
   299  	if err != nil {
   300  		return nil, err
   301  	}
   302  
   303  	blk, err := vm.vm.GetBlock(ctx, lastAccepted)
   304  	if err != nil {
   305  		return nil, err
   306  	}
   307  
   308  	parentID := blk.Parent()
   309  	return &vmpb.SetStateResponse{
   310  		LastAcceptedId:       lastAccepted[:],
   311  		LastAcceptedParentId: parentID[:],
   312  		Height:               blk.Height(),
   313  		Bytes:                blk.Bytes(),
   314  		Timestamp:            grpcutils.TimestampFromTime(blk.Timestamp()),
   315  	}, nil
   316  }
   317  
   318  func (vm *VMServer) Shutdown(ctx context.Context, _ *emptypb.Empty) (*emptypb.Empty, error) {
   319  	vm.allowShutdown.Set(true)
   320  	if vm.closed == nil {
   321  		return &emptypb.Empty{}, nil
   322  	}
   323  	errs := wrappers.Errs{}
   324  	errs.Add(vm.vm.Shutdown(ctx))
   325  	close(vm.closed)
   326  	vm.serverCloser.Stop()
   327  	errs.Add(vm.connCloser.Close())
   328  	return &emptypb.Empty{}, errs.Err
   329  }
   330  
   331  func (vm *VMServer) CreateHandlers(ctx context.Context, _ *emptypb.Empty) (*vmpb.CreateHandlersResponse, error) {
   332  	handlers, err := vm.vm.CreateHandlers(ctx)
   333  	if err != nil {
   334  		return nil, err
   335  	}
   336  	resp := &vmpb.CreateHandlersResponse{}
   337  	for prefix, handler := range handlers {
   338  		serverListener, err := grpcutils.NewListener()
   339  		if err != nil {
   340  			return nil, err
   341  		}
   342  		server := grpcutils.NewServer()
   343  		vm.serverCloser.Add(server)
   344  		httppb.RegisterHTTPServer(server, ghttp.NewServer(handler))
   345  
   346  		// Start HTTP service
   347  		go grpcutils.Serve(serverListener, server)
   348  
   349  		resp.Handlers = append(resp.Handlers, &vmpb.Handler{
   350  			Prefix:     prefix,
   351  			ServerAddr: serverListener.Addr().String(),
   352  		})
   353  	}
   354  	return resp, nil
   355  }
   356  
   357  func (vm *VMServer) Connected(ctx context.Context, req *vmpb.ConnectedRequest) (*emptypb.Empty, error) {
   358  	nodeID, err := ids.ToNodeID(req.NodeId)
   359  	if err != nil {
   360  		return nil, err
   361  	}
   362  
   363  	peerVersion := &version.Application{
   364  		Name:  req.Name,
   365  		Major: int(req.Major),
   366  		Minor: int(req.Minor),
   367  		Patch: int(req.Patch),
   368  	}
   369  	return &emptypb.Empty{}, vm.vm.Connected(ctx, nodeID, peerVersion)
   370  }
   371  
   372  func (vm *VMServer) Disconnected(ctx context.Context, req *vmpb.DisconnectedRequest) (*emptypb.Empty, error) {
   373  	nodeID, err := ids.ToNodeID(req.NodeId)
   374  	if err != nil {
   375  		return nil, err
   376  	}
   377  	return &emptypb.Empty{}, vm.vm.Disconnected(ctx, nodeID)
   378  }
   379  
   380  // If the underlying VM doesn't actually implement this method, its [BuildBlock]
   381  // method will be called instead.
   382  func (vm *VMServer) BuildBlock(ctx context.Context, req *vmpb.BuildBlockRequest) (*vmpb.BuildBlockResponse, error) {
   383  	var (
   384  		blk snowman.Block
   385  		err error
   386  	)
   387  	if vm.bVM == nil || req.PChainHeight == nil {
   388  		blk, err = vm.vm.BuildBlock(ctx)
   389  	} else {
   390  		blk, err = vm.bVM.BuildBlockWithContext(ctx, &block.Context{
   391  			PChainHeight: *req.PChainHeight,
   392  		})
   393  	}
   394  	if err != nil {
   395  		return nil, err
   396  	}
   397  
   398  	blkWithCtx, verifyWithCtx := blk.(block.WithVerifyContext)
   399  	if verifyWithCtx {
   400  		verifyWithCtx, err = blkWithCtx.ShouldVerifyWithContext(ctx)
   401  		if err != nil {
   402  			return nil, err
   403  		}
   404  	}
   405  
   406  	var (
   407  		blkID    = blk.ID()
   408  		parentID = blk.Parent()
   409  	)
   410  	return &vmpb.BuildBlockResponse{
   411  		Id:                blkID[:],
   412  		ParentId:          parentID[:],
   413  		Bytes:             blk.Bytes(),
   414  		Height:            blk.Height(),
   415  		Timestamp:         grpcutils.TimestampFromTime(blk.Timestamp()),
   416  		VerifyWithContext: verifyWithCtx,
   417  	}, nil
   418  }
   419  
   420  func (vm *VMServer) ParseBlock(ctx context.Context, req *vmpb.ParseBlockRequest) (*vmpb.ParseBlockResponse, error) {
   421  	blk, err := vm.vm.ParseBlock(ctx, req.Bytes)
   422  	if err != nil {
   423  		return nil, err
   424  	}
   425  
   426  	blkWithCtx, verifyWithCtx := blk.(block.WithVerifyContext)
   427  	if verifyWithCtx {
   428  		verifyWithCtx, err = blkWithCtx.ShouldVerifyWithContext(ctx)
   429  		if err != nil {
   430  			return nil, err
   431  		}
   432  	}
   433  
   434  	var (
   435  		blkID    = blk.ID()
   436  		parentID = blk.Parent()
   437  	)
   438  	return &vmpb.ParseBlockResponse{
   439  		Id:                blkID[:],
   440  		ParentId:          parentID[:],
   441  		Status:            vmpb.Status(blk.Status()),
   442  		Height:            blk.Height(),
   443  		Timestamp:         grpcutils.TimestampFromTime(blk.Timestamp()),
   444  		VerifyWithContext: verifyWithCtx,
   445  	}, nil
   446  }
   447  
   448  func (vm *VMServer) GetBlock(ctx context.Context, req *vmpb.GetBlockRequest) (*vmpb.GetBlockResponse, error) {
   449  	id, err := ids.ToID(req.Id)
   450  	if err != nil {
   451  		return nil, err
   452  	}
   453  	blk, err := vm.vm.GetBlock(ctx, id)
   454  	if err != nil {
   455  		return &vmpb.GetBlockResponse{
   456  			Err: errorToErrEnum[err],
   457  		}, errorToRPCError(err)
   458  	}
   459  
   460  	blkWithCtx, verifyWithCtx := blk.(block.WithVerifyContext)
   461  	if verifyWithCtx {
   462  		verifyWithCtx, err = blkWithCtx.ShouldVerifyWithContext(ctx)
   463  		if err != nil {
   464  			return nil, err
   465  		}
   466  	}
   467  
   468  	parentID := blk.Parent()
   469  	return &vmpb.GetBlockResponse{
   470  		ParentId:          parentID[:],
   471  		Bytes:             blk.Bytes(),
   472  		Status:            vmpb.Status(blk.Status()),
   473  		Height:            blk.Height(),
   474  		Timestamp:         grpcutils.TimestampFromTime(blk.Timestamp()),
   475  		VerifyWithContext: verifyWithCtx,
   476  	}, nil
   477  }
   478  
   479  func (vm *VMServer) SetPreference(ctx context.Context, req *vmpb.SetPreferenceRequest) (*emptypb.Empty, error) {
   480  	id, err := ids.ToID(req.Id)
   481  	if err != nil {
   482  		return nil, err
   483  	}
   484  	return &emptypb.Empty{}, vm.vm.SetPreference(ctx, id)
   485  }
   486  
   487  func (vm *VMServer) Health(ctx context.Context, _ *emptypb.Empty) (*vmpb.HealthResponse, error) {
   488  	vmHealth, err := vm.vm.HealthCheck(ctx)
   489  	if err != nil {
   490  		return &vmpb.HealthResponse{}, err
   491  	}
   492  	dbHealth, err := vm.db.HealthCheck(ctx)
   493  	if err != nil {
   494  		return &vmpb.HealthResponse{}, err
   495  	}
   496  	report := map[string]interface{}{
   497  		"database": dbHealth,
   498  		"health":   vmHealth,
   499  	}
   500  
   501  	details, err := json.Marshal(report)
   502  	return &vmpb.HealthResponse{
   503  		Details: details,
   504  	}, err
   505  }
   506  
   507  func (vm *VMServer) Version(ctx context.Context, _ *emptypb.Empty) (*vmpb.VersionResponse, error) {
   508  	version, err := vm.vm.Version(ctx)
   509  	return &vmpb.VersionResponse{
   510  		Version: version,
   511  	}, err
   512  }
   513  
   514  func (vm *VMServer) CrossChainAppRequest(ctx context.Context, msg *vmpb.CrossChainAppRequestMsg) (*emptypb.Empty, error) {
   515  	chainID, err := ids.ToID(msg.ChainId)
   516  	if err != nil {
   517  		return nil, err
   518  	}
   519  	deadline, err := grpcutils.TimestampAsTime(msg.Deadline)
   520  	if err != nil {
   521  		return nil, err
   522  	}
   523  	return &emptypb.Empty{}, vm.vm.CrossChainAppRequest(ctx, chainID, msg.RequestId, deadline, msg.Request)
   524  }
   525  
   526  func (vm *VMServer) CrossChainAppRequestFailed(ctx context.Context, msg *vmpb.CrossChainAppRequestFailedMsg) (*emptypb.Empty, error) {
   527  	chainID, err := ids.ToID(msg.ChainId)
   528  	if err != nil {
   529  		return nil, err
   530  	}
   531  
   532  	appErr := &common.AppError{
   533  		Code:    msg.ErrorCode,
   534  		Message: msg.ErrorMessage,
   535  	}
   536  	return &emptypb.Empty{}, vm.vm.CrossChainAppRequestFailed(ctx, chainID, msg.RequestId, appErr)
   537  }
   538  
   539  func (vm *VMServer) CrossChainAppResponse(ctx context.Context, msg *vmpb.CrossChainAppResponseMsg) (*emptypb.Empty, error) {
   540  	chainID, err := ids.ToID(msg.ChainId)
   541  	if err != nil {
   542  		return nil, err
   543  	}
   544  	return &emptypb.Empty{}, vm.vm.CrossChainAppResponse(ctx, chainID, msg.RequestId, msg.Response)
   545  }
   546  
   547  func (vm *VMServer) AppRequest(ctx context.Context, req *vmpb.AppRequestMsg) (*emptypb.Empty, error) {
   548  	nodeID, err := ids.ToNodeID(req.NodeId)
   549  	if err != nil {
   550  		return nil, err
   551  	}
   552  	deadline, err := grpcutils.TimestampAsTime(req.Deadline)
   553  	if err != nil {
   554  		return nil, err
   555  	}
   556  	return &emptypb.Empty{}, vm.vm.AppRequest(ctx, nodeID, req.RequestId, deadline, req.Request)
   557  }
   558  
   559  func (vm *VMServer) AppRequestFailed(ctx context.Context, req *vmpb.AppRequestFailedMsg) (*emptypb.Empty, error) {
   560  	nodeID, err := ids.ToNodeID(req.NodeId)
   561  	if err != nil {
   562  		return nil, err
   563  	}
   564  
   565  	appErr := &common.AppError{
   566  		Code:    req.ErrorCode,
   567  		Message: req.ErrorMessage,
   568  	}
   569  	return &emptypb.Empty{}, vm.vm.AppRequestFailed(ctx, nodeID, req.RequestId, appErr)
   570  }
   571  
   572  func (vm *VMServer) AppResponse(ctx context.Context, req *vmpb.AppResponseMsg) (*emptypb.Empty, error) {
   573  	nodeID, err := ids.ToNodeID(req.NodeId)
   574  	if err != nil {
   575  		return nil, err
   576  	}
   577  	return &emptypb.Empty{}, vm.vm.AppResponse(ctx, nodeID, req.RequestId, req.Response)
   578  }
   579  
   580  func (vm *VMServer) AppGossip(ctx context.Context, req *vmpb.AppGossipMsg) (*emptypb.Empty, error) {
   581  	nodeID, err := ids.ToNodeID(req.NodeId)
   582  	if err != nil {
   583  		return nil, err
   584  	}
   585  	return &emptypb.Empty{}, vm.vm.AppGossip(ctx, nodeID, req.Msg)
   586  }
   587  
   588  func (vm *VMServer) Gather(context.Context, *emptypb.Empty) (*vmpb.GatherResponse, error) {
   589  	metrics, err := vm.metrics.Gather()
   590  	return &vmpb.GatherResponse{MetricFamilies: metrics}, err
   591  }
   592  
   593  func (vm *VMServer) GetAncestors(ctx context.Context, req *vmpb.GetAncestorsRequest) (*vmpb.GetAncestorsResponse, error) {
   594  	blkID, err := ids.ToID(req.BlkId)
   595  	if err != nil {
   596  		return nil, err
   597  	}
   598  	maxBlksNum := int(req.MaxBlocksNum)
   599  	maxBlksSize := int(req.MaxBlocksSize)
   600  	maxBlocksRetrivalTime := time.Duration(req.MaxBlocksRetrivalTime)
   601  
   602  	blocks, err := block.GetAncestors(
   603  		ctx,
   604  		vm.log,
   605  		vm.vm,
   606  		blkID,
   607  		maxBlksNum,
   608  		maxBlksSize,
   609  		maxBlocksRetrivalTime,
   610  	)
   611  	return &vmpb.GetAncestorsResponse{
   612  		BlksBytes: blocks,
   613  	}, err
   614  }
   615  
   616  func (vm *VMServer) BatchedParseBlock(
   617  	ctx context.Context,
   618  	req *vmpb.BatchedParseBlockRequest,
   619  ) (*vmpb.BatchedParseBlockResponse, error) {
   620  	blocks := make([]*vmpb.ParseBlockResponse, len(req.Request))
   621  	for i, blockBytes := range req.Request {
   622  		block, err := vm.ParseBlock(ctx, &vmpb.ParseBlockRequest{
   623  			Bytes: blockBytes,
   624  		})
   625  		if err != nil {
   626  			return nil, err
   627  		}
   628  		blocks[i] = block
   629  	}
   630  	return &vmpb.BatchedParseBlockResponse{
   631  		Response: blocks,
   632  	}, nil
   633  }
   634  
   635  func (vm *VMServer) GetBlockIDAtHeight(
   636  	ctx context.Context,
   637  	req *vmpb.GetBlockIDAtHeightRequest,
   638  ) (*vmpb.GetBlockIDAtHeightResponse, error) {
   639  	blkID, err := vm.vm.GetBlockIDAtHeight(ctx, req.Height)
   640  	return &vmpb.GetBlockIDAtHeightResponse{
   641  		BlkId: blkID[:],
   642  		Err:   errorToErrEnum[err],
   643  	}, errorToRPCError(err)
   644  }
   645  
   646  func (vm *VMServer) StateSyncEnabled(ctx context.Context, _ *emptypb.Empty) (*vmpb.StateSyncEnabledResponse, error) {
   647  	var (
   648  		enabled bool
   649  		err     error
   650  	)
   651  	if vm.ssVM != nil {
   652  		enabled, err = vm.ssVM.StateSyncEnabled(ctx)
   653  	}
   654  
   655  	return &vmpb.StateSyncEnabledResponse{
   656  		Enabled: enabled,
   657  		Err:     errorToErrEnum[err],
   658  	}, errorToRPCError(err)
   659  }
   660  
   661  func (vm *VMServer) GetOngoingSyncStateSummary(
   662  	ctx context.Context,
   663  	_ *emptypb.Empty,
   664  ) (*vmpb.GetOngoingSyncStateSummaryResponse, error) {
   665  	var (
   666  		summary block.StateSummary
   667  		err     error
   668  	)
   669  	if vm.ssVM != nil {
   670  		summary, err = vm.ssVM.GetOngoingSyncStateSummary(ctx)
   671  	} else {
   672  		err = block.ErrStateSyncableVMNotImplemented
   673  	}
   674  
   675  	if err != nil {
   676  		return &vmpb.GetOngoingSyncStateSummaryResponse{
   677  			Err: errorToErrEnum[err],
   678  		}, errorToRPCError(err)
   679  	}
   680  
   681  	summaryID := summary.ID()
   682  	return &vmpb.GetOngoingSyncStateSummaryResponse{
   683  		Id:     summaryID[:],
   684  		Height: summary.Height(),
   685  		Bytes:  summary.Bytes(),
   686  	}, nil
   687  }
   688  
   689  func (vm *VMServer) GetLastStateSummary(ctx context.Context, _ *emptypb.Empty) (*vmpb.GetLastStateSummaryResponse, error) {
   690  	var (
   691  		summary block.StateSummary
   692  		err     error
   693  	)
   694  	if vm.ssVM != nil {
   695  		summary, err = vm.ssVM.GetLastStateSummary(ctx)
   696  	} else {
   697  		err = block.ErrStateSyncableVMNotImplemented
   698  	}
   699  
   700  	if err != nil {
   701  		return &vmpb.GetLastStateSummaryResponse{
   702  			Err: errorToErrEnum[err],
   703  		}, errorToRPCError(err)
   704  	}
   705  
   706  	summaryID := summary.ID()
   707  	return &vmpb.GetLastStateSummaryResponse{
   708  		Id:     summaryID[:],
   709  		Height: summary.Height(),
   710  		Bytes:  summary.Bytes(),
   711  	}, nil
   712  }
   713  
   714  func (vm *VMServer) ParseStateSummary(
   715  	ctx context.Context,
   716  	req *vmpb.ParseStateSummaryRequest,
   717  ) (*vmpb.ParseStateSummaryResponse, error) {
   718  	var (
   719  		summary block.StateSummary
   720  		err     error
   721  	)
   722  	if vm.ssVM != nil {
   723  		summary, err = vm.ssVM.ParseStateSummary(ctx, req.Bytes)
   724  	} else {
   725  		err = block.ErrStateSyncableVMNotImplemented
   726  	}
   727  
   728  	if err != nil {
   729  		return &vmpb.ParseStateSummaryResponse{
   730  			Err: errorToErrEnum[err],
   731  		}, errorToRPCError(err)
   732  	}
   733  
   734  	summaryID := summary.ID()
   735  	return &vmpb.ParseStateSummaryResponse{
   736  		Id:     summaryID[:],
   737  		Height: summary.Height(),
   738  	}, nil
   739  }
   740  
   741  func (vm *VMServer) GetStateSummary(
   742  	ctx context.Context,
   743  	req *vmpb.GetStateSummaryRequest,
   744  ) (*vmpb.GetStateSummaryResponse, error) {
   745  	var (
   746  		summary block.StateSummary
   747  		err     error
   748  	)
   749  	if vm.ssVM != nil {
   750  		summary, err = vm.ssVM.GetStateSummary(ctx, req.Height)
   751  	} else {
   752  		err = block.ErrStateSyncableVMNotImplemented
   753  	}
   754  
   755  	if err != nil {
   756  		return &vmpb.GetStateSummaryResponse{
   757  			Err: errorToErrEnum[err],
   758  		}, errorToRPCError(err)
   759  	}
   760  
   761  	summaryID := summary.ID()
   762  	return &vmpb.GetStateSummaryResponse{
   763  		Id:    summaryID[:],
   764  		Bytes: summary.Bytes(),
   765  	}, nil
   766  }
   767  
   768  func (vm *VMServer) BlockVerify(ctx context.Context, req *vmpb.BlockVerifyRequest) (*vmpb.BlockVerifyResponse, error) {
   769  	blk, err := vm.vm.ParseBlock(ctx, req.Bytes)
   770  	if err != nil {
   771  		return nil, err
   772  	}
   773  
   774  	if req.PChainHeight == nil {
   775  		err = blk.Verify(ctx)
   776  	} else {
   777  		blkWithCtx, ok := blk.(block.WithVerifyContext)
   778  		if !ok {
   779  			return nil, fmt.Errorf("%w but got %T", errExpectedBlockWithVerifyContext, blk)
   780  		}
   781  		blockCtx := &block.Context{
   782  			PChainHeight: *req.PChainHeight,
   783  		}
   784  		err = blkWithCtx.VerifyWithContext(ctx, blockCtx)
   785  	}
   786  	if err != nil {
   787  		return nil, err
   788  	}
   789  
   790  	return &vmpb.BlockVerifyResponse{
   791  		Timestamp: grpcutils.TimestampFromTime(blk.Timestamp()),
   792  	}, nil
   793  }
   794  
   795  func (vm *VMServer) BlockAccept(ctx context.Context, req *vmpb.BlockAcceptRequest) (*emptypb.Empty, error) {
   796  	id, err := ids.ToID(req.Id)
   797  	if err != nil {
   798  		return nil, err
   799  	}
   800  	blk, err := vm.vm.GetBlock(ctx, id)
   801  	if err != nil {
   802  		return nil, err
   803  	}
   804  	if err := blk.Accept(ctx); err != nil {
   805  		return nil, err
   806  	}
   807  	return &emptypb.Empty{}, nil
   808  }
   809  
   810  func (vm *VMServer) BlockReject(ctx context.Context, req *vmpb.BlockRejectRequest) (*emptypb.Empty, error) {
   811  	id, err := ids.ToID(req.Id)
   812  	if err != nil {
   813  		return nil, err
   814  	}
   815  	blk, err := vm.vm.GetBlock(ctx, id)
   816  	if err != nil {
   817  		return nil, err
   818  	}
   819  	if err := blk.Reject(ctx); err != nil {
   820  		return nil, err
   821  	}
   822  	return &emptypb.Empty{}, nil
   823  }
   824  
   825  func (vm *VMServer) StateSummaryAccept(
   826  	ctx context.Context,
   827  	req *vmpb.StateSummaryAcceptRequest,
   828  ) (*vmpb.StateSummaryAcceptResponse, error) {
   829  	var (
   830  		mode = block.StateSyncSkipped
   831  		err  error
   832  	)
   833  	if vm.ssVM != nil {
   834  		var summary block.StateSummary
   835  		summary, err = vm.ssVM.ParseStateSummary(ctx, req.Bytes)
   836  		if err == nil {
   837  			mode, err = summary.Accept(ctx)
   838  		}
   839  	} else {
   840  		err = block.ErrStateSyncableVMNotImplemented
   841  	}
   842  
   843  	return &vmpb.StateSummaryAcceptResponse{
   844  		Mode: vmpb.StateSummaryAcceptResponse_Mode(mode),
   845  		Err:  errorToErrEnum[err],
   846  	}, errorToRPCError(err)
   847  }